# Function\_score queryでのスコアリング時に単語が分割されてしまう事象について

**URL:** <https://discuss.elastic.co/t/function-score-query/302662>\
**Category:** 日本語による質問・議論はこちら\
**Created:** [April 19, 2022, 4:05am UTC](https://discuss.elastic.co/t/function-score-query/302662 "2022-04-19T04:05:02Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Totsuka](https://avatars.discourse-cdn.com/v4/letter/t/b4bc9f/32.png) [@Totsuka](https://discuss.elastic.co/u/Totsuka)\
**Post date:** [April 19, 2022, 4:05am UTC](https://discuss.elastic.co/t/function-score-query/302662/1 "2022-04-19T04:05:02Z")

</div>

＜実現したいこと＞  
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定義

```auto
"title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }

```

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

* * *

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

・multi\_matchでの検索とfunction\_score\_queryを同時に実行するクエリ

```auto
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"]
}

```

・explainAPIの実行クエリ

```auto
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"
    }
  }
}

```

・explainAPIの実行結果

```auto
{
  "_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" : []
      }
    ]
  }
}

```

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

---

<div class="post-metadata">

**Author:** ![Tomo\_M](https://avatars.discourse-cdn.com/v4/letter/t/848f3c/32.png) [@Tomo\_M](https://discuss.elastic.co/u/Tomo_M)\
**Post date:** [April 22, 2022, 4:05pm UTC](https://discuss.elastic.co/t/function-score-query/302662/2 "2022-04-22T16:05:51Z")

</div>

ご指摘の通りtokenizerによる挙動と思われます。multi-matchクエリでどうなのか確証がないのですが、[matchクエリにおいてデフォルトはOR検索](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html#query-dsl-match-query-boolean)です。したがって、「消 OR 費 OR 税」となっていることが考えられます。  
ただANDにすると離れて出現している場合もヒットしてしまいますので、これも完璧ではないですが、N-gram tokenizerを用いた上で、"operator": ANDにしてみてはどうでしょうか。厳密な部分一致が必要であれば、wildcard typeとregex queryを用いる方法もあるかもしれません。

---

<div class="post-metadata">

**Author:** ![Koji\_Kawamura](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/koji_kawamura/32/93938_2.png) [@Koji\_Kawamura](https://discuss.elastic.co/u/Koji_Kawamura)\
**Post date:** [May 2, 2022, 5:19am UTC](https://discuss.elastic.co/t/function-score-query/302662/3 "2022-05-02T05:19:50Z")

</div>

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

ご質問に記載のマッピング定義だと、 kuromoji の analyzer 指定がないのでデフォルトの standard analyzer が動いているのではないでしょうか。こちらで kuromoji を使ってテストしたところ、 title と question に消費税が入ったドキュメントのスコアは期待通り 9.0 となりました。

なお、 kuromoji で分割されたトークンは '消費' と '税' でした。このため、 '税' の一文字が入っていれば match だとスコアが加算されてしまいます。 match\_phrase クエリに変更すれば消費税のみを対象とできます。  
テストデータの二件目は answer に '税' が含まれるため match クエリだとスコアが 12.0 になります。match\_phrase だと 9.0 になります。

テストに利用したのは以下です:

```auto
PUT discuss-302662
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "kuromoji"
      },
      "question": {
        "type": "text",
        "analyzer": "kuromoji"
      },
      "answer": {
        "type": "text",
        "analyzer": "kuromoji"
      }
    }
  }
}

POST discuss-302662/_bulk
{"index": {}}
{"title": "消費税、また増税の可能性", "question": "消費税がまた上がるのですか？", "answer": "なんとも言えません"}
{"index": {}}
{"title": "消費税、また増税の可能性", "question": "消費税がまた上がるのですか？", "answer": "なんとも言えません税"}

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

```

---

<div class="post-metadata">

**Author:** ![Totsuka](https://avatars.discourse-cdn.com/v4/letter/t/b4bc9f/32.png) [@Totsuka](https://discuss.elastic.co/u/Totsuka)\
**Post date:** [May 2, 2022, 8:52am UTC](https://discuss.elastic.co/t/function-score-query/302662/4 "2022-05-02T08:52:10Z")

</div>

Tomo\_M さま

回答を下さったにも関わらず、ご返信が遅くなり申し訳ございません。

1. tokenizerにより検索キーワードが "消 費 税"と分割される
2. 分割したキーワードを使用して、"消 OR 費 OR 税" とOR検索をしているということですね。

ご意見を頂戴し、大変助かりました。ありがとうございました。

---

<div class="post-metadata">

**Author:** ![Totsuka](https://avatars.discourse-cdn.com/v4/letter/t/b4bc9f/32.png) [@Totsuka](https://discuss.elastic.co/u/Totsuka)\
**Post date:** [May 2, 2022, 9:02am UTC](https://discuss.elastic.co/t/function-score-query/302662/5 "2022-05-02T09:02:57Z")

</div>

Koji\_Kawamura さま

kuromojiのAnalyzer指定の記載が漏れていました。  
マッピング定義は全てのフィールドで、Standard analyzerを使用しております。

match\_phraseクエリを使用し、語順通りに検索する ≒ 検索キーワードが分割されずにスコアリングされるということですね。

match\_phraseクエリを使用して実行したところ、期待通りの結果が得られました。

ご教示頂き、誠にありがとうございました。

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [May 30, 2022, 9:03am UTC](https://discuss.elastic.co/t/function-score-query/302662/6 "2022-05-30T09:03:37Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
