MySQL match () gegen () - Reihenfolge nach Relevanz und Spalte?

80

Okay, also versuche ich, eine Volltextsuche in mehreren Spalten durchzuführen, so etwas Einfaches:

SELECT * FROM pages WHERE MATCH(head, body) AGAINST('some words' IN BOOLEAN MODE)

Jetzt möchte ich nach Relevanz ordnen (wie viele der Wörter werden gefunden?), Was ich mit so etwas machen konnte:

SELECT * , MATCH (head, body) AGAINST ('some words' IN BOOLEAN MODE) AS relevance 
FROM pages
WHERE MATCH (head, body) AGAINST ('some words' IN BOOLEAN MODE)
ORDER BY relevance

Jetzt kommt der Teil, in dem ich mich verliere. Ich möchte die Relevanz in der headSpalte priorisieren .

Ich denke, ich könnte zwei Relevanzspalten erstellen , eine für headund eine für body, aber zu diesem Zeitpunkt würde ich dreimal ungefähr die gleiche Suche in der Tabelle durchführen, und für das, was ich für diese Funktion mache, ist die Leistung wichtig, da die Die Abfrage wird zusammengefügt und mit anderen Tabellen abgeglichen.

Meine Hauptfrage lautet also : Gibt es eine schnellere Möglichkeit, nach Relevanz zu suchen und bestimmte Spalten zu priorisieren? (Und als Bonus wird möglicherweise sogar die Relevanz gezählt, wie oft die Wörter in den Spalten vorkommen?)

Anregungen oder Ratschläge wären toll.

Hinweis: Ich werde dies auf einem LAMP-Server ausführen. (WAMP in lokalen Tests)

Kristoffer la Cour
quelle
Müssen Sie MATCH ... GEGEN die SELECT-Klausel und die WHERE-Klausel wirklich einfügen? Können Sie es nicht in der SELECT-Klausel aliasen und auf den Alias ​​in der WHERE-Klausel verweisen? Ich versuche vorbereitete Anweisungen zu verwenden und dies scheint mir überflüssig / seltsam.
S. Imp
2
Nein, wie in der MySQL-Dokumentation seit 5.5 angegeben, wird MATCH ... AGAINST einmal berechnet, wenn sowohl in SELECT als auch in WHERE, also kein zusätzlicher Aufwand.
Bob2u

Antworten:

156

Dies kann die erhöhte Relevanz für das gewünschte Kopfteil erhöhen. Es wird es nicht verdoppeln, aber es könnte möglicherweise gut genug für Sie sein:

SELECT pages.*,
       MATCH (head, body) AGAINST ('some words') AS relevance,
       MATCH (head) AGAINST ('some words') AS title_relevance
FROM pages
WHERE MATCH (head, body) AGAINST ('some words')
ORDER BY title_relevance DESC, relevance DESC

-- alternatively:
ORDER BY title_relevance + relevance DESC

Eine Alternative, die Sie auch untersuchen möchten, wenn Sie die Flexibilität haben, die DB-Engine zu wechseln, ist Postgres . Es ermöglicht, das Gewicht der Operatoren festzulegen und mit dem Ranking herumzuspielen.

Denis de Bernardy
quelle
14
Abgesehen davon unterstützt MySQL 5.6 die Volltextsuche in InnoDB-Tabellen!
Jabari
1
Können Sie hierfür eine SQL-Geige bereitstellen?
Benutzer
Wie stark wirken sich mehrere Suchanfragen aus? Ich würde 4 Übereinstimmungen mit meinem SELECT benötigen, da ich 4 verschiedene Gewichtsfaktoren habe. Würde das die Leistung viel verringern?
ToBe
@ToBe Ich habe bei anderen ähnlichen Fragen gesehen, dass mehr als eine Person sagt, dass die Verwendung mehrerer MATCHAnweisungen aufgrund der internen Funktionsweise von MySQL keinen zusätzlichen Aufwand bedeutet .
BadHorsie
Stellen Sie sicher, dass Sie diese beiden ausführen. ALTER TABLE talk_webpages ADD FULLTEXT(head)undALTER TABLE talk_webpages ADD FULLTEXT(head, body)
Supun Kavinda
15

Nur hinzufügen, wer vielleicht braucht. Vergessen Sie nicht, die Tabelle zu ändern!

ALTER TABLE table_name ADD FULLTEXT(column_name);
Camilla
quelle
3
Wenn Sie den obigen Befehl mehrmals ausführen, werden mehrere Indizes für dieselbe Spalte (n) erstellt. Führen Sie diesen Befehl also nur einmal aus.
Hakiko
Besser noch, verwenden Sie den Indexnamen CREATE FULLTEXT INDEX für den Tabellennamen (Spaltenname (n)). Sie sollten auch wirklich prüfen, ob der Index vorhanden ist, bevor Sie versuchen, ihn zu erstellen. Sie können überprüfen, ob es vorhanden ist, indem Sie: SELECT INDEX_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_CATALOG= 'def' AND TABLE_SCHEMA= DATABASE () AND TABLE_NAME= 'Tabellenname' AND INDEX_NAME= 'Indexname';
Dave Hilditch
9

Ich habe es noch nie getan, aber es scheint so

MATCH (head, head, body) AGAINST ('some words' IN BOOLEAN MODE)

Sollte Streichhölzern im Kopf ein doppeltes Gewicht geben.


Lesen Sie einfach diesen Kommentar auf der Dokumentenseite. Ich dachte, er könnte für Sie von Wert sein:

Gepostet von Patrick O'Lone am 9. Dezember 2002, 06:51 Uhr

In der Dokumentation ist zu beachten, dass IN BOOLEAN MODE fast immer eine Relevanz von 1,0 zurückgibt. Um eine aussagekräftige Relevanz zu erhalten, müssen Sie:

SELECT MATCH('Content') AGAINST ('keyword1 keyword2') as Relevance 
FROM table 
WHERE MATCH ('Content') AGAINST('+keyword1+keyword2' IN BOOLEAN MODE) 
HAVING Relevance > 0.2 
ORDER BY Relevance DESC 

Beachten Sie, dass Sie eine regelmäßige Relevanzabfrage durchführen, um Relevanzfaktoren in Kombination mit einer WHERE-Klausel zu erhalten, die den BOOLEAN-MODUS verwendet. Der BOOLEAN-MODUS gibt Ihnen die Teilmenge, die die Anforderungen der BOOLEAN-Suche erfüllt, die Relevanzabfrage erfüllt den Relevanzfaktor, und die HAVING-Klausel (in diesem Fall) stellt sicher, dass das Dokument für die Suche relevant ist (dh Dokumente, die weniger als 0,2 Punkte erzielen gelten als irrelevant). Auf diese Weise können Sie auch nach Relevanz bestellen.

Dies kann ein Fehler in der Funktionsweise von IN BOOLEAN MODE sein oder auch nicht, obwohl die Kommentare, die ich auf der Mailingliste gelesen habe, darauf hindeuten, dass das Relevanzranking von IN BOOLEAN MODE nicht sehr kompliziert ist und sich daher schlecht für die tatsächliche Bereitstellung relevanter Dokumente eignet. Übrigens: Ich habe keinen Leistungsverlust festgestellt, da MySQL die FULLTEXT-Suche anscheinend nur einmal durchführt, obwohl die beiden MATCH-Klauseln unterschiedlich sind. Verwenden Sie EXPLAIN, um dies zu beweisen.

Es scheint also, dass Sie sich keine Sorgen machen müssen, die Volltextsuche zweimal aufzurufen, obwohl Sie dennoch "EXPLAIN verwenden sollten, um dies zu beweisen".

Jisaacstone
quelle
1
Das zweimalige Hinzufügen von head zur match () -Funktion funktioniert leider nicht. Vielleicht, weil die Abfrage nicht zählt, wie oft die Wörter vorkommen? Und ich habe diese Seite verwendet, auf die Sie auch verweisen, aber ich kann sie aus irgendeinem Grund nicht zum Laufen bringen ... Ich habe meine Spalten noch nicht indiziert und kann daher nicht ohne das Tag "IN BOOLEAN MODE" suchen. .
Kristoffer la Cour
Ich denke, eine Nicht-Booleen-Suche würde die Anzahl der Vorkommen zurückgeben, Booleen jedoch nicht?
Jisaacstone
Ich werde morgen mehr darüber nachdenken, aber ich werde es vorerst festhalten. Vielen Dank für die Antwort, wir werden sehen, ob es mir hilft, wenn ich das in den Griff bekomme.
Kristoffer la Cour
Ich hatte ein Problem mit der Verwendung des IN BOOLEAN-MODUS und der anschließenden Bestellung nach Relevanz. Dies löste mein Problem, da die Relevanz immer als 1 zurückgegeben wurde. Danke.
Jazzy
Das Generieren eines Bewertungsfeldes löste mein Problem: Ich erhielt Ergebnisse, aber viele davon waren völliges Rauschen. Vielen Dank, +1
Chris Baker
4

Ich habe auch nur damit rumgespielt. Eine Möglichkeit, zusätzliches Gewicht hinzuzufügen, ist der Bereich ORDER BY des Codes.

Wenn Sie beispielsweise 3 verschiedene Spalten abgeglichen haben und bestimmte Spalten stärker gewichten möchten:

SELECT search.*,
MATCH (name) AGAINST ('black' IN BOOLEAN MODE) AS name_match,
MATCH (keywords) AGAINST ('black' IN BOOLEAN MODE) AS keyword_match,
MATCH (description) AGAINST ('black' IN BOOLEAN MODE) AS description_match
FROM search
WHERE MATCH (name, keywords, description) AGAINST ('black' IN BOOLEAN MODE)
ORDER BY (name_match * 3  + keyword_match * 2  + description_match) DESC LIMIT 0,100;
Noah King
quelle
Ist das nicht eine wirklich schwere Frage?
Beanow
5
Bewegen Sie die Mathematik in die select-Anweisung und sie erleichtert die Belastung erheblich. SELECT search.*, (MATCH (name) AGAINST ('black' IN BOOLEAN MODE) * 3) + (MATCH (keywords) AGAINST ('black' IN BOOLEAN MODE)*2 + MATCH (description) AGAINST ('black' IN BOOLEAN MODE)) AS totalScore , FROM search WHERE MATCH (name, keywords, description) AGAINST ('black' IN BOOLEAN MODE) ORDER BY totalScore DESC LIMIT 0,100;
invertedSpear