45

キーワードとコンテンツの2つの列があるとします。両方にフルテキストインデックスがあります。キーワードにfooが含まれる行は、コンテンツにfooが含まれる行よりも関連性が高くなります。MySQLがコンテンツの一致よりもキーワードの一致に重みを付けるには、何をする必要がありますか?

「一致」構文を使用しています。

解決:

この作業を次の方法で行うことができました。

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 
4

9 に答える 9

96

3 つの全文索引を作成する

  • a) キーワード列に 1 つ
  • b) コンテンツ欄に 1 つ
  • c) キーワードとコンテンツ列の両方に 1 つ

次に、クエリ:

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

ポイントは、rel1その列だけでクエリの関連性を示すkeywordことです (その列でのみインデックスを作成したため)。 rel2同じことを行いますが、content列に対してです。これら 2 つの関連性スコアを合計して、任意の重み付けを適用できます。

ただし、実際の検索にはこれら 2 つのインデックスのいずれも使用していません。そのために、両方の列にある 3 番目のインデックスを使用します。

(keyword,content) のインデックスは、リコールを制御します。別名、返されるもの。

2 つの個別のインデックス (1 つはキーワードのみ、もう 1 つはコンテンツのみ) が関連性を制御します。また、ここで独自の加重基準を適用できます。

任意の数の異なるインデックスを使用できることに注意してください (または、おそらく他の要因に基づいて、クエリ時に使用するインデックスと重み付けを変更します...クエリにストップワードが含まれている場合にのみキーワードで検索します...重み付けバイアスを減らしますクエリに 3 つ以上の単語が含まれる場合のキーワード ... など)。

各インデックスはディスク領域を使用するため、インデックスが増えるとディスクが増えます。その結果、mysql のメモリ フットプリントが高くなります。また、更新するインデックスが増えるため、挿入に時間がかかります。

状況に応じてパフォーマンスをベンチマークする必要があります (ベンチマークのために mysql クエリ キャッシュをオフにするように注意してください。そうしないと、結果が歪んでしまいます)。これは Google ほど効率的ではありませんが、非常に簡単で「すぐに使える」ものであり、クエリで「いいね」を使用するよりもはるかに優れていることはほぼ間違いありません。

私はそれが本当にうまくいくと思います。

于 2009-03-02T00:34:45.507 に答える
19

実際には、case ステートメントを使用してフラグのペアを作成する方が良い解決策になる場合があります。

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

繰り返しますが、これはすべてのキーワード一致がすべてのコンテンツのみの一致よりも上位にランク付けされている場合のみです。また、キーワードとコンテンツの両方が一致した場合が最高ランクであると仮定しました。

于 2009-02-13T21:51:51.687 に答える
7

2 つのフルテキスト インデックスのみを使用した単純なバージョン (クレジットは @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;

これにより、完全なインデックス付き列が に対して検索され、keyword一致した関連性が 2 つの別々の列に選択されます。一致しないアイテム (relevance1 と relevance2 が両方ともゼロ) を除外し、content_ft列の重みを増やして結果を並べ替えます。複合フルテキスト インデックスは必要ありません。

于 2017-07-08T12:02:12.033 に答える
0

ブールモードでは、MySQLは「>」および「<」演算子をサポートして、行に割り当てられた関連性の値に対する単語の寄与を変更します。

このようなものがうまくいくのだろうか?

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
于 2009-08-10T09:13:36.273 に答える
0

私は数年前にこれを行いましたが、全文索引はありませんでした。私はコードを手元に持っていませんが(元雇用主)、テクニックをよく覚えています。

一言で言えば、私は各列から「重み」を選択しました。例えば:

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

ここで見苦しいSQLを許してください、私が何かを書く必要があったので数年が経ちました、そして私は頭のてっぺんからこれをやっています...

お役に立てれば!

J.Js

于 2009-02-17T15:28:16.637 に答える
-1

私の知る限り、これはMySQL全文検索ではサポートされていませんが、キーワードフィールドでその単語を数回繰り返すことで効果を得ることができます。キーワード「foobar」の代わりに「foobarfoobar foo bar」を使用すると、キーワード列内でfooとbarの両方が等しく重要になり、何度か表示されるため、mysqlとの関連性が高くなります。

私たちはこれを私たちのサイトで使用し、それは機能します。

于 2009-02-13T20:34:21.857 に答える
-1

同様のものが必要で、OPのソリューションを使用しましたが、フルテキストが部分的な単語と一致しないことに気付きました。そのため、'watermelon' が単語の一部として Keywords または Content に含まれている場合 (watermelonsalesmanager など)、WHERE MATCH により一致せず、結果に含まれません。だから私は少しだまされて、OPのクエリをこれに微調整しました:

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 (Keywords LIKE '%watermelon%' OR 
  Title LIKE '%watermelon%' OR 
  MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE)) 
HAVING (keywordmatch > 0 OR contentmatch > 0 OR relevance > 0)  
ORDER BY keywordmatch DESC, contentmatch DESC, relevance DESC

お役に立てれば。

于 2011-02-01T12:06:03.117 に答える
-1

まあ、それはあなたが正確に何を意味するかによって異なります:

コンテンツに foo を含む行よりも、キーワードに foo を含む行の関連性を高めたいと考えています。

キーワードに foo を含む行がコンテンツに foo を含む行よりも前に 来るようにする場合は、2 つの個別のクエリを実行します。コンテンツ。

于 2009-02-16T03:26:42.917 に答える
-4

メトリックが、すべてのキーワードの一致がすべてのコンテンツの一致よりも「価値がある」ということだけである場合は、行数のある和集合を使用できます。これらの線に沿った何か。

select *
from (
   select row_number() over(order by blahblah) as row, t.*
   from thetable t
   where keyword match

   union

   select row_number() over(order by blahblah) + @@rowcount + 1 as row, t.*
   from thetable t
   where content match
)
order by row

それよりも複雑で、すべての行に実際の重みを適用したい場合は、どのように支援すればよいかわかりません。

于 2009-02-13T20:46:01.847 に答える