30.Elasticsearch|match_phrase/スコアリング

match_phraseで検索をかけた時、何を基準としてスコアリングされるのか、仕事で問われる機会があったので学習。

  • analyzerの基本

blog.chocolapod.net

www.elastic.co

medium.com

  • _analyze
GET Index名/_analyze
{
  "field": "~Field名~",
  "text": "~Value~"
}

下記が返ってくる

token: tokenの内容
start_offset: 入力値の先頭から数えたtokenの始まる位置
end_offset: 入力値の先頭から数えたtokenの終わる位置
type: tokenのタイプ
position: token列内でのtokenの位置
  • 下記で、対象Indexのマッピング(どのDocumentをどう設定しているか)を確認できる
GET Index名/_mappings
  • Standard tokenizer

www.elastic.co

lucene.apache.org

The Standard Tokenizer supports Unicode standard annex UAX#29 word boundaries with the following token types: , , <SOUTHEAST_ASIAN>, , and .

Standard Tokenizer は、(Unicode Standard Annex#29で指定されているように、Unicode Text Segmentationアルゴリズムに基づく)文法ベースのトークン化を提供し、ほとんどの言語でうまく機能します。

  • 参考
GET    /_cat/count/{index}      # インデックスのドキュメント数取得

medium.com

match_all ... 全てのドキュメントを返す
match ... キーワード検索
match_phrase ... 語順も考慮される
query_string ... Lucene形式での検索式
term ... 完全一致検索
terms ... 複数のtermを指定できる
range ... 数値は日付などの範囲検索
bool,must,should,must_not ... andやorなどの検索
filter ... スコアを返さない

Elasticsearchでは、全文検索を行うために文章を単語の単位に分割する処理機能を、Analyzerと呼びます。 ちなみにElasticsearch標準のAnalyzerでは日本語の形態素解析が行えないため、kuromojiプラグインをインストールする方法が書籍では紹介されています。

Analyzerは

Char filter ... 入力されたテキストを前処理するためのフィルタ
Tokeneizer ... テキストの分割処理
Token filter ... 分割されたテキスト(トークン)に対する処理を行うフィルタ
phrase match
フレーズ検索

fooとbaaの間に未知の単語をslop個許容したフレーズを検索
{
  "query" : {
    "match_phrase" : {
      "title" : {
        "query" : "foo baa",
        "slop" : 1
      }
    }
  }
}

qiita.com

  • Elasticsearchのスコアリングは、下記によって計算されるようだ。
以下の項目でスコアリングされます。

TF
IDF
fieldの長さ
つまり、
一つのDocumentに対して
一つの検索語を構成している単語が
どれだけ含有されているか
その単語はどれだけそのdocumentに対して特徴的なのか
を計算され、
検索対象のfieldの文字列の長さが短いのをもっと高く
評価する仕組みです。

思想的には
一つの文書の中で該当検索語がよくマッチしていて、しかもそれは他の文書ではあんまり見られない該当文書のユニークな検索語で、しかもそれが短い文書であれば、マッチ度は高いということになります。

qiita.com

  • TF(Term Frequency):
    一つのDocumentの中で、該当単語の出現頻度を表わす。

  • IDF(Inverse Document Frequency):
    文書頻度の逆数/ある単語が出現する文書数であるDFの逆数。対数を取ることで、重み付けに利用されることが多い。
    噛み砕いて言うと、レアなら特徴的なので高い値となる。

www.cse.kyoto-su.ac.jp

※分かりやすい  ↓ dev.classmethod.jp

  • tf/計算例
1.4142135 = tf(freq=2.0), with freq of:

DocumentのTermの個数から求められる関数で、2つ以上のDocumentがヒットした時に、Termがより多く含まれた方が上にくる。
ここでは、「java」というTermが2回(freq=2.0)登場している。

  • idf/計算例
1.2231436 = idf(docFreq=3, maxDocs=5)

Index内のDocumentの数と、指定したTermを含むDocumentの数から求められる関数。
指定したTermを含むDocumentが少ないほど、大きな数字となる。
ここでは、全Document(maxDocs=5)中、3回登場している(docFreq+3)。

kazuhira-r.hatenablog.com

sitest.jp

  • これは結構わかりやすいかも。
GET scoring/_search
{
  "query" : {
    "match" : {
      "name" : "one two"
    }
  }
}

{
  "_index": "scoring",
  "_type": "doc",
  "_id": "1",
  "_score": 0.79143506,
  "_source": {
    "name": "one two"
  }
}
{
  "_index": "scoring",
  "_type": "doc",
  "_id": "3",
  "_score": 0.6331481,
  "_source": {
    "name": "one two three"
  }
}
{
  "_index": "scoring",
  "_type": "doc",
  "_id": "4",
  "_score": 0.6331481,
  "_source": {
    "name": "one two three four"
  }
}
{
  "_index": "scoring",
  "_type": "doc",
  "_id": "2",
  "_score": 0.14893481,
  "_source": {
    "name": "one three"
  }
}
  • フィールド内のターム数が少ない方がスコアが高くなる。

notta55.hatenablog.com

検索語の出現数が多いと高評価。
ここで、レアな検索語であれば、出現数評価の重みをさらにUPする。
ここで、検索語の出現割合が高い文書であれば、さらに出現数評価の重みをUPする。

itdepends.hateblo.jp

  • explain(検索結果の_explanationを参照)
GET ~Index名~/_search
{
    "query": {
        "bool": {
                {
                    "match_phrase": {
                        "content": "~検索文字列~"
                    }
                }
        }
    },
    "size": 10,
    "from": 0,
    "explain": true
}
  • 参照図
その名も「TF-IDF」である。

Elasticsearchでの検索では、

より短い文章の中に*2より多くの検索語が出現するほど良い。検索語がレアなワードであればそれを多く含む文章が際立つ、結果として

評価が高くなるということだと理解した。

itdepends.hateblo.jp

  • Similarity

PerFieldSimilarity…? Similarity?

www.elastic.co

  • Similarity Module

FullTextSearchにおけるクエリとドキュメントの適合度を求めるモジュール

www.elastic.co