88400


### 実現したいこと

titleフィールドに「消費税」という単語が含まれていれば、5ポイント、  
questionフィールドに「消費税」という単語が含まれていれば、4ポイント、  
answerフィールドに「消費税」という単語が含まれていれば、3ポイントを付与し、  
その合計をスコアリングの値とし("score_mode": "sum")、スコアの降順で表示したいです。  
※Elasticsearchのデフォルトのスコアリングは無視する設定にしています("boost_mode": "replace")。

[function_score_queryの公式ドキュメント](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-
dsl-function-score-query.html)

### 問題を発見した経緯

titleとquestionに「消費税」という単語が含まれている場合、  
スコアは9.0になるはず(titleに含まれている：5ポイント＋questionに含まれている：4ポイント＝9ポイント)ですが、実行結果は12.0になっています。  
explainAPIでデバッグをしてみたところ、どうやら「消費税」を「消」「費」「税」と分割していることがわかりました。  
("description" : "match filter: title:消 title:費 title:税")

※title、question、answerフィールドは全てtext型で、kuromojiプラグインによる形態素解析をしています。これが原因のような気もするのですが...

・mapping定義

[code]

    "title" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
    
[/code]

### 解決したいこと

上記事象、スコアリング時に言葉が分割される問題を解決したいです。

以下、実行クエリです。  
※すべてkibanaコンソール上で実行

・multi_matchでの検索とfunction_score_queryを同時に実行するクエリ

[code]

    GET /sample_table/_search?pretty=true
    {
      "query": {
        "function_score": {
          "query": {"multi_match": {
          "fields": ["title","question","answer"],
          "query": "消費税"
        }},
          "functions": [
            {
              "filter": { "match": { "title": "消費税" } },
              "weight": 5
            },
            {
              "filter": { "match": { "question": "消費税" } },
              "weight": 4
            },
            {
              "filter": { "match": { "answer": "消費税" } },
              "weight": 3
            }
          ],
          "max_boost": 100,
          "score_mode": "sum",
          "boost_mode": "replace",
          "min_score": 0
        }
      }
      ,"size": 1500
      ,"_source": ["title","question","answer"]
    }
    
[/code]

・explainAPIの実行クエリ

[code]

    GET /sample_table/_explain/QCu5jH8BunS87XDCQfYF
    {
      "query": {
        "function_score": {
          "query": {"multi_match": {
          "fields": ["title","question","answer"],
          "query": "消費税"
        }},
          "functions": [
            {
              "filter": { "match": { "title": "消費税" } },
              "weight": 5
            },
            {
              "filter": { "match": { "question": "消費税" } },
              "weight": 4
            },
            {
              "filter": { "match": { "answer": "消費税" } },
              "weight": 3
            }
          ],
          "score_mode": "sum",
          "boost_mode": "replace"
        }
      }
    }
    
[/code]

・explainAPIの実行結果

[code]

    {
      "_index" : "sample_table",
      "_type" : "_doc",
      "_id" : "QCu5jH8BunS87XDCQfYF",
      "matched" : true,
      "explanation" : {
        "value" : 12.0,
        "description" : "min of:",
        "details" : [
          {
            "value" : 12.0,
            "description" : "function score, score mode [sum]",
            "details" : [
              {
                "value" : 5.0,
                "description" : "function score, product of:",
                "details" : [
                  {
                    "value" : 1.0,
                    "description" : "match filter: title:消 title:費 title:税",
                    "details" : [ ]
                  },
                  {
                    "value" : 5.0,
                    "description" : "product of:",
                    "details" : [
                      {
                        "value" : 1.0,
                        "description" : "constant score 1.0 - no function provided",
                        "details" : [ ]
                      },
                      {
                        "value" : 5.0,
                        "description" : "weight",
                        "details" : [ ]
                      }
                    ]
                  }
                ]
              },
              {
                "value" : 4.0,
                "description" : "function score, product of:",
                "details" : [
                  {
                    "value" : 1.0,
                    "description" : "match filter: question:消 question:費 question:税",
                    "details" : [ ]
                  },
                  {
                    "value" : 4.0,
                    "description" : "product of:",
                    "details" : [
                      {
                        "value" : 1.0,
                        "description" : "constant score 1.0 - no function provided",
                        "details" : [ ]
                      },
                      {
                        "value" : 4.0,
                        "description" : "weight",
                        "details" : [ ]
                      }
                    ]
                  }
                ]
              },
              {
                "value" : 3.0,
                "description" : "function score, product of:",
                "details" : [
                  {
                    "value" : 1.0,
                    "description" : "match filter: answer:消 answer:費 answer:税",
                    "details" : [ ]
                  },
                  {
                    "value" : 3.0,
                    "description" : "product of:",
                    "details" : [
                      {
                        "value" : 1.0,
                        "description" : "constant score 1.0 - no function provided",
                        "details" : [ ]
                      },
                      {
                        "value" : 3.0,
                        "description" : "weight",
                        "details" : [ ]
                      }
                    ]
                  }
                ]
              }
            ]
          },
          {
            "value" : 3.4028235E38,
            "description" : "maxBoost",
            "details" : [ ]
          }
        ]
      }
    }
    
[/code]

どなたか原因及び対処法をご教示頂けますと幸いです。よろしくお願いいたします。


CC BY-SA 4.0
2022-04-19T05:40:29.337
88396
2022-04-19T12:19:06.853
2022-04-19T12:19:06.853
3060
52279
question
elasticsearch
Function_score queryでのスコアリング時に単語が分割されてしまう


まず、 multifield は、元になったフィールドと同じ内容が、 `${元のフィールド名}.${マルチフィールドの名前}`
というフィールドに投入されたような効果を実現してくれる機能です。現在の共有されたクエリでは、マルチフィールドを利用している部分はないので、その設定は効果をなしていない状態です。

次に、elasticsearch
の検索をチューニングしたい場合、全文検索としてどのような挙動を行わせたいか、を意識する必要があります。おそらくですが、今回やりたいことは、

  1. `title`, `question`, `answer` の analyze 結果には 「消費税」というトークンが含まれるようにする
  2. クエリするトークンは「消費税」そのもの

なんじゃないか、と思います。1 については、 analyzer の設定をチューニングすることだけが、その実現方法です。 2 についても、 index の
analyzer 設定そのものをチューニングして実現可能ではありますが、その他にも、与えられた文字を analyze せずにインデックスに問い合わせる
`term` クエリを用いる、という方法があるかな、という感じです。「消費税」がすでにトークンとして `title`, `question`,
`answer` フィールドに含まれている場合、

[code]

    GET /sample_table/_explain/QCu5jH8BunS87XDCQfYF
    {
      "query": {
        "function_score": {
          "query": {"multi_match": {
          "fields": ["title","question","answer"],
          "query": "消費税"
        }},
          "functions": [
            {
              "filter": { "term": { "title": "消費税" } },
              "weight": 5
            },
            {
              "filter": { "term": { "question": "消費税" } },
              "weight": 4
            },
            {
              "filter": { "term": { "answer": "消費税" } },
              "weight": 3
            }
          ],
          "score_mode": "sum",
          "boost_mode": "replace"
        }
      }
    }
    
[/code]

でいける気がします。


CC BY-SA 4.0
2022-04-19T07:43:17.777
88400
2022-04-19T07:43:17.777
754
88396
answer