2016-05-05 4 views
0

Zunächst einmal: Entschuldigung für die lange Post, ich versuche, eine schwierige Situation auf einfache Weise zu erklären und gleichzeitig versuche, so viele Informationen wie möglich zu geben.Variety on search results

Ich habe einen Algorithmus, der versucht, Benutzererwartung während einer Suche zu bestimmen. Es gibt ein paar Möglichkeiten, wie ich es benutzen kann und ich habe das gleiche Problem mit beiden, also sagen wir es zur Disambiguierung. Nun, mit einem DB-Struktur wie dieser (oder einer anderen, die die Arbeit erlaubt):

Post

ID | TITLE 
---+---------------------------------------------- 
1 | Orange developed the first 7G phone 
2 | Orange: the fruit of gods 
3 | Theory of Colors: Orange 
4 | How to prepare the perfect orange juice 

Schlüsselwörter

ID | WORD  | ABOUT 
---+----------+--------- 
1 | orange | company 
2 | orange | fruit 
3 | orange | color 

post_keywords

ID | POST | KEYWORD 
---+-------+--------- 
1 | 1 | 1 
2 | 2 | 2 
3 | 3 | 3 
4 | 4 | 2 

.

Wenn in einem Suchfeld ein Benutzer nach dem Wort "Orange" sucht, würde der Algorithmus aussehen, dass orange auf die Firma, die Farbe oder die Frucht beziehen kann und durch Beantworten ein paar Fragen, es versucht zu bestimmen, wonach der Benutzer sucht. Nach allem, was ich ein Array wie diese bekommen:

$e = array(
    'fruit' => 0.153257, 
    'color' => 0.182332, 
    'company' => 0.428191, 
); 

In diesem Punkt weiß ich, der Benutzer wahrscheinlich für Informationen über die Frucht suchen (weil fruit ‚s Wert näher an 0 ist) und wenn ich falsch liege meine zweite Wette geht für die color. Am Ende der Liste steht company.

Also, mit einem Join und ORDER BY FIELD(keywords.id, 2,3,1) kann ich den Ergebnissen die (fast) perfekte Ordnung geben:

- Orange: the fruit of gods 
- How to prepare the perfect orange juice 
- Theory of Colors: Orange 
- Orange developed the first 7G phone 

.

Nun ... wie Sie sich vorstellen können, würde ich nicht um Hilfe kommen, wenn alles so nett ist. Das Problem ist, dass das vorherige Beispiel nur 4 mögliche Ergebnisse hat. Wenn der Benutzer wirklich nach dem company gesucht hat, kann er dieses Ergebnis in der 4. Position finden und alles ist in Ordnung. Aber ... Wenn wir 200 Post über die Frucht und 100 Post über die Farbe haben, kommt der erste Post über das Unternehmen in der Position 301..

Ich bin auf der Suche nach einer Möglichkeit, die Reihenfolge (in einer vorhersehbaren und wiederholbaren Weise) zu wechseln, jetzt, da ich weiß, dass der Benutzer wahrscheinlich nach der fruit, gefolgt von der color und der Firma am Ende suchen. Ich möchte einen Beitrag über die fruit in der ersten Position (und möglicherweise die zweite) zeigen, gefolgt von einem Post über die color, gefolgt von der company und starten Sie diesen Zyklus erneut, bis das Ergebnis endet.

Bearbeiten: Ich werde mit einem MySQL-Trick oder mit einer Idee, den Ansatz zu ändern, aber ich kann keine Lösungen von Drittanbietern akzeptieren.

+0

Ich würde Gruppe nach Kategorie in der Tat und das Rück das beste Ergebnis für jede Kategorie, und ermöglichen es dem Benutzer an dieser Stelle dann die Kategorie klicken, um zu sehen alle anderen Links für diese Kategorie. – Eric

+1

Es sieht so aus, als ob Sie in MySQL einen invertierten Index mit Ihrer Keyword-Tabelle erstellen. Sie haben einige Funktionen zum Verständnis von Abfragen. Haben Sie über die Verwendung von Elasticsearch nachgedacht? dieses Gespräch von mir könnte Ihnen helfen, Ihren Kopf um, wie Sie Elasticsearch https://www.elastic.co/elasticon/conf/2016/sf/opensource-connections-the-ghost-in-the-search verwenden würde -machine –

+0

^ich stimme zu .. ElasticSearch wird hier sehr hilfreich sein .. Auf diese Weise werden Sie in der Lage, Suchergebnisse und viele andere coole Sachen im Zusammenhang mit der Suche ... –

Antwort

2

Sie können Variablen verwenden, um ein benutzerdefiniertes Sortierfeld bereitzustellen.

SELECT 
    p.*, 
    CASE k.about 
    WHEN 'company' THEN @sort_company := @sort_company + 1 
    WHEN 'color' THEN @sort_color := @sort_color + 1 
    WHEN 'fruit' THEN @sort_fruit := @sort_fruit + 1 
    ELSE NULL 
    END AS sort_order, 
k.about 
FROM post p 
    JOIN post_keywords pk ON (p.id = pk.post) 
    JOIN keywords k ON (pk.keyword = k.id) 
    JOIN (SELECT @sort_fruit := 0, @sort_color := 0, @sort_company := 0) AS vars 
ORDER BY sort_order, FIELD(k.id, 2, 3, 1) 

Ergebnis sieht wie folgt aus:

| id | title         | sort_order | about | 
|---:|:----------------------------------------|-----------:|:--------| 
| 2 | Orange: the fruit of gods    |   1 | fruit | 
| 3 | Theory of Colors: Orange    |   1 | color | 
| 1 | Orange developed the first 7G phone  |   1 | company | 
| 4 | How to prepare the perfect orange juice |   2 | fruit | 
+0

Das sieht aus wie es funktioniert. Ich kann es jetzt nicht ausprobieren, aber ich werde es in ein paar Stunden versuchen. = D –

+0

Ich möchte nur sagen: Es hat funktioniert. Und ich schätze die Einfachheit dieser Lösung. Du bist einfach ein Genie. –

+0

Danke :-) Schön zu hören, dass es dir hilft. – Andrew

0

Ich denke, dass Sie eine Art der Kategorisierung benötigen, oder, würde ich es vorziehen zu sagen, Clustering der Antworten. Wenn Sie dies tun können, können Sie den Benutzern zunächst die Antworten mit der höchsten Punktzahl von jedem Cluster zeigen. Hey, manchmal ist die Maximierung der Vielfalt wirklich nur um ihrer selbst willen wert!

Ich denke, Sie sollten in der Lage sein, Antworten zu bündeln. Sie haben eine Art von Bewertungsformel, die Ihnen sagt, wie gut eine Antwort auf ein Dokument für eine Benutzeranfrage ist, vielleicht basierend auf einem "Beutel mit Wörtern" -Modell. Ich schlage vor, dass Sie damit angeben, wie nahe ein Dokument an einem anderen Dokument ist, indem Sie das andere Dokument als Abfrage behandeln. Wenn Sie genau dies tun, möchten Sie vielleicht jedes Dokument als eine Abfrage mit dem anderen als Antwort behandeln und die zwei Bewertungen mitteln, so dass die Punktzahl d (a, b) die Eigenschaft hat, dass d (a, b) = d (b, a).

Jetzt haben Sie eine Punktzahl (leider wahrscheinlich keine Entfernung: das heißt, mit einer Punktzahl, hohe Werte bedeuten nahe beieinander) und Sie brauchen einen Clustering-Algorithmus. Idealerweise möchten Sie einen schnellen, aber vielleicht muss er auch schnell genug sein, um schneller zu sein als ein Mensch, der die Antworten liest.

Ein schneller Cluster-Algorithmus soll N (für einige Parameter N) Cluster-Zentren verfolgen. Initialisieren Sie diese auf die ersten N Dokumente, die abgerufen werden, und betrachten Sie dann jedes andere Dokument einzeln. In jeder Phase versuchen Sie, die maximale Punktzahl zu reduzieren, die zwischen zwei beliebigen Dokumenten im Clustercenter gefunden wird (was dazu führt, dass die Dokumente so weit wie möglich voneinander entfernt sind). Wenn Sie ein neues Dokument in Betracht ziehen, berechnen Sie die Punktzahl zwischen diesem Dokument und jedem der N aktuellen Cluster-Zentren. Wenn das Maximum dieser Werte kleiner ist als die aktuelle maximale Punktzahl zwischen den N aktuellen Cluster-Zentren, dann ist dieses Dokument weiter von den Cluster-Zentren entfernt als sie voneinander sind, so dass Sie es wollen. Tauschen Sie sie gegen eines der N Cluster-Zentren aus - je nachdem, welche maximale Punktzahl zwischen den neuen N Cluster-Zentren am wenigsten erreicht wird.

Dies ist kein perfekter Clustering-Algorithmus - zum einen hängt das Ergebnis von der Reihenfolge ab, in der Dokumente präsentiert werden, was ein schlechtes Zeichen ist. Es ist jedoch ziemlich schnell für kleine N, und es hat eine nette Eigenschaft: Wenn Sie k < = N-Cluster haben und (von Scores zu Distanzen wechseln) ist jede Entfernung innerhalb eines Clusters kleiner als jeder Abstand zwischen zwei Punkten von verschiedene Cluster, dann enthalten die N Cluster-Zentren am Ende mindestens einen Punkt von jedem der k Cluster. Wenn Sie zum ersten Mal ein Mitglied eines Clusters sehen, das Sie noch nicht gesehen haben, wird es zu einem Cluster-Zentrum, und Sie werden niemals die Anzahl der Cluster-Zentren reduzieren, da Sie einen Punkt in einem anderen Cluster auswerfen würden andere Zentren, die den Mindestabstand zwischen zwei als Clusterzentren gehaltenen Punkten nicht erhöhen (die maximale Punktzahl zwischen zwei solchen Punkten verringern).