it-swarm.com.de

Wie kann ich die Relevanz der MySQL-Volltextsuche ändern, um ein Feld "wertvoller" als ein anderes zu machen?

Angenommen, ich habe zwei Spalten, Schlüsselwörter und Inhalt. Ich habe einen Volltextindex über beide. Ich möchte, dass eine Zeile mit "foo" in den Keywords relevanter ist als eine Zeile mit "foo" im Inhalt. Was muss ich tun, damit MySQL die Übereinstimmungen in Keywords höher gewichtet als in Inhalten?

Ich verwende die Syntax "Übereinstimmung mit".

LÖSUNG:

Konnte diese Arbeit auf folgende Weise machen:

SELECT *, 
CASE when Keywords like '%watermelon%' then 1 else 0 END as keywordmatch, 
CASE when Content like '%watermelon%' then 1 else 0 END as contentmatch,
MATCH (Title, Keywords, Content) AGAINST ('watermelon') AS relevance 
FROM about_data  
WHERE MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE) 
HAVING relevance > 0  
ORDER by keywordmatch desc, contentmatch desc, relevance desc 
36
Buzz

Tatsächlich könnte die Verwendung einer case-Anweisung zum Erstellen eines Paares von Flags eine bessere Lösung sein:

select 
...
, case when keyword like '%' + @input + '%' then 1 else 0 end as keywordmatch
, case when content like '%' + @input + '%' then 1 else 0 end as contentmatch
-- or whatever check you use for the matching
from 
   ... 
   and here the rest of your usual matching query
   ... 
order by keywordmatch desc, contentmatch desc

Dies ist wiederum nur der Fall, wenn alle Keyword-Übereinstimmungen einen höheren Rang haben als alle Nur-Inhalt-Übereinstimmungen. Ich bin auch davon ausgegangen, dass eine Übereinstimmung in Keyword und Inhalt den höchsten Rang hat.

20
notnot

Erstellen Sie drei Volltextindizes

  • a) eins in der Schlüsselwortspalte
  • b) eine in der Inhaltsspalte
  • c) eine in Schlüsselwort- und Inhaltsspalte

Dann Ihre Anfrage:

SELECT id, keyword, content,
  MATCH (keyword) AGAINST ('watermelon') AS rel1,
  MATCH (content) AGAINST ('watermelon') AS rel2
FROM table
WHERE MATCH (keyword,content) AGAINST ('watermelon')
ORDER BY (rel1*1.5)+(rel2) DESC

Der Punkt ist, dass rel1 die Relevanz Ihrer Abfrage nur in der Spalte keyword angibt (weil Sie den Index nur für diese Spalte erstellt haben). rel2 macht dasselbe, nur für die Spalte content. Sie können nun diese beiden Relevanzwerte addieren, indem Sie eine beliebige Gewichtung anwenden.

Sie verwenden jedoch keinen dieser beiden Indizes für die eigentliche Suche. Dafür verwenden Sie Ihren dritten Index, der sich in beiden Spalten befindet.

Der Index für (Schlüsselwort, Inhalt) steuert Ihren Rückruf. Aka, was wird zurückgegeben.

Die zwei separaten Indizes (einer nur für Schlüsselwörter, einer nur für Inhalte) steuern Ihre Relevanz. Und Sie können hier Ihre eigenen Gewichtungskriterien anwenden.

Beachten Sie, dass Sie eine beliebige Anzahl verschiedener Indizes verwenden können (oder die Indizes und Gewichtungen, die Sie zum Zeitpunkt der Abfrage verwenden, auf der Grundlage anderer Faktoren variieren können). Suchen Sie nur nach Schlüsselwörtern, wenn die Abfrage ein Stoppwort enthält. Verringern Sie die Gewichtung von Schlüsselwörter, wenn die Abfrage mehr als 3 Wörter enthält ... etc).

Jeder Index belegt Speicherplatz, sodass mehr Indizes und mehr Speicherplatz zur Verfügung stehen. Und im Gegenzug höherer Speicherbedarf für MySQL. Außerdem dauern Einfügungen länger, da Sie mehr Indizes aktualisieren müssen.

Sie sollten die Leistung auf Ihre Situation abstimmen (indem Sie den mysql-Abfrage-Cache für das Benchmarking ausschalten, da sonst die Ergebnisse verzerrt werden). Dies ist nicht Google-effizient, aber es ist ziemlich einfach und "out of the box" und es ist mit ziemlicher Sicherheit viel besser als die Verwendung von "like" in den Abfragen.

Ich finde es funktioniert wirklich gut.

75
mintywalker

Einfachere Version mit nur 2 Volltextindizes (Credits von @mintywalker):

SELECT id, 
   MATCH (`content_ft`) AGAINST ('keyword*' IN BOOLEAN MODE) AS relevance1,  
   MATCH (`title_ft`) AGAINST ('keyword*' IN BOOLEAN MODE) AS relevance2
FROM search_table
HAVING (relevance1 + relevance2) > 0
ORDER BY (relevance1 * 1.5) + (relevance2) DESC
LIMIT 0, 1000;

Dadurch werden beide vollständig indizierten Spalten nach der keyword durchsucht und die übereinstimmende Relevanz in zwei separaten Spalten ausgewählt. Wir schließen Elemente ohne Übereinstimmung aus (relevance1 und relevance2 sind beide Null) und ordnen die Ergebnisse durch eine höhere Gewichtung der Spalte content_ft neu an. Wir brauchen keinen zusammengesetzten Volltextindex.

4
lubosdz

Ich habe das vor ein paar Jahren gemacht, aber ohne den Volltextindex. Ich habe den Code nicht zur Hand (ehemaliger Arbeitgeber), aber ich erinnere mich gut an die Technik.

Kurz gesagt, ich habe aus jeder Spalte ein "Gewicht" ausgewählt. Zum Beispiel:

select table.id, keyword_relevance + content_relevance as relevance from table
   left join
      (select id, 1 as keyword_relevance from table_name where keyword match) a
   on table.id = a.id
   left join
      (select id, 0.75 as content_relevance from table_name where content match) b
   on table.id = b.id

Bitte verzeihen Sie hier schlechtes SQL. Es ist ein paar Jahre her, seit ich etwas schreiben musste, und ich mache das aus dem Häuschen ...

Hoffe das hilft!

J.Js

0
Justin James

Im Booleschen Modus unterstützt MySQL die Operatoren ">" und "<", um den Beitrag eines Words in den einer Zeile zugewiesenen Relevanzwert zu ändern.

Ich frage mich, ob so etwas funktionieren würde?

SELECT *, 
MATCH (Keywords) AGAINST ('>watermelon' IN BOOLEAN MODE) AS relStrong, 
MATCH (Title,Keywords,Content) AGAINST ('<watermelon' IN BOOLEAN MODE) AS relWeak 
FROM about_data  
WHERE MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE) 
ORDER by (relStrong+relWeak) desc
0
Tom

Soweit ich weiß, wird dies bei der MySQL-Volltextsuche nicht unterstützt, aber Sie können den Effekt erzielen, indem Sie das Wort im Keyword-Feld mehrmals wiederholen. Anstatt die Schlüsselwörter "foo bar" zu haben, müssen Sie "foo bar foo bar foo bar" verwenden. Auf diese Weise sind sowohl foo als auch bar in der Schlüsselwortspalte gleich wichtig und werden für mysql relevanter, da sie mehrmals auftreten.

Wir verwenden dies auf unserer Website und es funktioniert.

0
adamJLev