MySQL match()against()-関連性と列による順序?


80

さて、私は複数の列で全文検索をしようとしています。これは次のような単純なものです。

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

今、私は関連性によって注文したいと思います(単語がいくつ見つかりましたか?)これは私がこのようなことで行うことができました:

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

迷子になった部分が来ましたhead。コラムの関連性を優先したいと思います。

1つはfor head、もう1つはforの2つの関連性列を作成できると思いますbodyが、その時点で、テーブルで同じ検索を3回実行します。この関数を作成するためには、パフォーマンスが重要です。クエリは結合され、他のテーブルと照合されます。

だから、私の主な質問は、関連性を検索し、特定の列に優先順位を付けるためのより速い方法はありますか?(そしてボーナスとして、おそらく関連性を列に単語が出現する回数を数えることさえできますか?)

どんな提案やアドバイスも素晴らしいでしょう。

注:これはLAMPサーバーで実行します。(ローカルテストでのWAMP)


本当にMATCH ... AGAINSTをSELECT句WHERE句の両方に配置する必要がありますか?SELECT句でエイリアスを作成し、WHERE句でエイリアスを参照することはできませんか?プリペアドステートメントを使用しようとしていますが、これは冗長/奇妙に思えます。
S. Imp 2018

2
いいえ、5.5以降のMySQLドキュメントに記載されているように、MATCH ... AGAINSTはSELECTとWHEREの両方で一度計算されるため、余分なオーバーヘッドはありません。
Bob2u

回答:


156

これにより、必要なヘッド部分との関連性が高まる可能性があります。それは2倍にはなりませんが、おそらくあなたのために十分かもしれません:

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

DBエンジンを柔軟に切り替えることができる場合は、Postgresも調査する必要があります。演算子の重みを設定し、ランキングをいじることができます。


14
余談ですが、MySQL 5.6はInnoDBテーブルでの全文検索をサポートしています!
ジャバリ2013

1
このためのSQLフィドルを提供できますか?
ユーザー

複数の検索はどの程度の悪影響を及ぼしますか?私は4つの異なる重み係数を持っているので、SELECTに4つの一致が必要になります。それはパフォーマンスをはるかに低下させるでしょうか?
ToBe 2015年

@ToBe他の同様の質問でMATCH、MySQLが内部で機能する方法のために、複数のステートメントを使用しても余分なオーバーヘッドはないと言う人が複数います。
BadHorsie 2016年

これら2つを実行するようにしてください。ALTER TABLE talk_webpages ADD FULLTEXT(head)およびALTER TABLE talk_webpages ADD FULLTEXT(head, body)
SupunKavinda19年

15

必要な人のために追加するだけです。テーブルを変更することを忘れないでください!

ALTER TABLE table_name ADD FULLTEXT(column_name);

3
上記のコマンドを複数回実行すると、同じ列に複数のインデックスが作成されます。したがって、このコマンドは1回だけ実行してください。
hakiko 2018

さらに良いことに、tablename(column_name(s))でCREATE FULLTEXTINDEXインデックス名を使用します。また、インデックスを作成する前に、インデックスが存在するかどうかを実際に確認する必要があります。次を使用して、存在するかどうかを確認できます。SELECTINDEX_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_CATALOG= 'def' AND TABLE_SCHEMA= DATABASE()AND TABLE_NAME= 'tablename' AND INDEX_NAME= 'indexname';
DaveHilditch20年

9

私はそうしたことがありませんが、

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

頭の中で見つかった一致に2倍の重みを与える必要があります。


ドキュメントページでこのコメントを読んでください、それはあなたにとって価値があるかもしれないと思いました:

PatrickO'Loneによって2002年12月9日6:51 amに投稿

ドキュメントでは、IN BOOLEANMODEはほとんどの場合1.0の関連性を返すことに注意してください。意味のある関連性を得るには、次のことを行う必要があります。

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 

BOOLEAN MODEを使用するWHERE句と組み合わせて関連性係数を取得するために、通常の関連性クエリを実行していることに注意してください。BOOLEAN MODEは、BOOLEAN検索の要件を満たすサブセットを提供し、関連性クエリは関連性係数を満たし、HAVING句(この場合)は、ドキュメントが検索に関連していることを保証します(つまり、スコアが0.2未満のドキュメント)。無関係と見なされます)。これにより、関連性で注文することもできます。

これは、IN BOOLEAN MODEの動作方法のバグである場合とそうでない場合がありますが、メーリングリストで読んだコメントによると、IN BOOLEAN MODEの関連性ランキングはそれほど複雑ではないため、実際に関連ドキュメントを提供するには不十分です。ところで、2つのMATCH句が異なっていても、MySQLはFULLTEXT検索を1回しか実行しないように見えるため、これを実行してもパフォーマンスが低下することに気づきませんでした。EXPLAINを使用してこれを証明します。

したがって、「これを証明するためにEXPLAINを使用する」必要がありますが、全文検索を2回呼び出すことを心配する必要はないように思われます。


1
残念ながら、match()関数にheadを2回追加しても機能しません。クエリが単語の出現回数をカウントしないためでしょうか?また、あなたが参照しているそのページも使用していますが、何らかの理由で機能しない可能性があります...まだ列にインデックスを付けていないため、「INBOOLEANMODE」タグがないと検索できません。 。
クリストファーラクール

非ブール検索では発生数が返されると思いますが、ブールでは返されませんか?
jisaacstone 2011年

明日はもっと調べてみますが、とりあえず持ちます。答えてくれてありがとう、これを手に入れたら助けになるかどうか見ていきます。
Kristoffer la Cour 2011年

IN BOOLEAN MODEを使用してから関連性で並べ替えるときに問題が発生しました。これにより、関連性が常に1として返されるという問題が解決しました。ありがとうございます。
Jazzy 2012年

スコアフィールドを生成することで私の問題は解決しました。結果は得られていましたが、多くは完全なノイズでした。ありがとう、+ 1
クリスベイカー

4

私もこれで遊んでいました。重みを追加する1つの方法は、コードのORDERBY領域にあります。

たとえば、3つの異なる列を照合していて、特定の列にさらに重みを付けたい場合は、次のようにします。

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;

これは本当に重いクエリではありませんか?
Beanow 2013年

5
数学をselectステートメントに移動すると、負荷が大幅に軽減されます。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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.