Boostingを使ってるが片方の結果しか返ってこない


(Tarou Tanaka) #1

boostingを使って2つの単語を検索しているのですが、片方しか結果が表示されません。

背景を説明させて頂きます。
私は今、複数の単語で既存のドキュメントに対して検索し、マッチした物をすべて表示するシステムを作っています。また、検索単語の一部は優先的に表示したいです。
そのためスコアーを上げて優劣をつける方法を考えました。
そこで調べると、boostingを使うと一方のクエリの検索結果に対してスコアーを上げそうでした。
そこで以下のようなクエリを書きました。

{
    "query": {
        "boosting": {
            "positive": {
                "term": {
                    "base_form": "リアル"
                }
            },
            "negative": {
                "term": {
                    "base_form": "了解"
                }
            },
            "negative_boost": 0.5
        }
    }
}

しかしこの検索結果は"リアル"の分しか帰ってきませんでした。また反対にした場合"了解"の方の結果が帰ってくることは確認済です。

私のクエリは何が間違っているでしょうか?また私の目的を実現する方法としてboostingを使うことは間違っていないでしょうか?

----7/30追記----
以下に上記のQueryにexplainを付与し更にsizeを指定したQueryを貼らせて頂きます。

{
    "from": 0,
    "size": 50,
    "explain": true,
    "query": {
        "boosting": {
            "positive": {
                "term": {
                    "base_form": "リアル"
                }
            },
            "negative": {
                "term": {
                    "base_form": "了解"
                }
            },
            "negative_boost": 1
        }
    }
}

以下が結果です。全てを貼るとこのフォーラムの文字数制限に引っ掛かっているようなので、結果は1件分のみに省略しました。また省略した内容にはnegative分に指定した単語の結果は入っていませんでした。
また一部のパラメータは自分の事情でぼかしています。

{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 12,
        "successful": 12,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 18,
        "max_score": 9.85408,
        "hits": [
            {
                "_shard": "[words][0]",
                "_node": "jquFb9RIQpG9sbmLwA_b9A",
                "_index": "words",
                "_type": "word",
                "_id": "15666",
                "_score": 9.85408,
                "_source": {
                    "base_form": "~~"
                },
                "_explanation": {
                    "value": 9.85408,
                    "description": "weight(base_form:リアル in 5665) [PerFieldSimilarity], result of:",
                    "details": [
                        {
                            "value": 9.85408,
                            "description": "score(doc=5665,freq=1.0 = termFreq=1.0 ), product of:",
                            "details": [
                                {
                                    "value": 7.1245217,
                                    "description": "idf, computed as log(1 + (docCount - docFreq + 0.5) / (docFreq + 0.5)) from:",
                                    "details": [
                                        {
                                            "value": 18,
                                            "description": "docFreq",
                                            "details": []
                                        },
                                        {
                                            "value": 22977,
                                            "description": "docCount",
                                            "details": []
                                        }
                                    ]
                                },
                                {
                                    "value": 1.3831216,
                                    "description": "tfNorm, computed as (freq * (k1 + 1)) / (freq + k1 * (1 - b + b * fieldLength / avgFieldLength)) from:",
                                    "details": [
                                        {
                                            "value": 1,
                                            "description": "termFreq=1.0",
                                            "details": []
                                        },
                                        {
                                            "value": 1.2,
                                            "description": "parameter k1",
                                            "details": []
                                        },
                                        {
                                            "value": 0.75,
                                            "description": "parameter b",
                                            "details": []
                                        },
                                        {
                                            "value": 6.1939764,
                                            "description": "avgFieldLength",
                                            "details": []
                                        },
                                        {
                                            "value": 2,
                                            "description": "fieldLength",
                                            "details": []
                                        }
                                    ]
                                }
                            ]
                        }
                     ....
                    ]
                }
            }
        ]
    }
}

(Makoto Nozawa) #2

boosting queryで検索単語ごとの重み付けをするのは間違ってないように思います。

検索にsizeは指定しているでしょうか。デフォルトは上位10ドキュメントしか取得されません。

あとは

反対にした場合"了解"の方の結果が帰ってくる

ということであれば、反対にした場合に帰って来たドキュメントのスコアを見ながら(反対にしない場合の)negative_boostの値を1に近づけてみてどこかで"了解"を含む結果が返るようになるかを確認するのはどうでしょう。


(Sunggyu Kei Rhie) #3

explainの結果など一緒にあげていただけるとなにかわかるかもしれません!


(Tarou Tanaka) #4

@r4-keisuke様、 ご返信有難うございます。質問文にexplainしたQueryとその結果を追記させていただきました。ご確認ください。


(Tarou Tanaka) #5

@mnozawa様、御返信有難うございます。質問文にSizeを十分に指定したQueryとその結果を追記させて抱きました。
また negative_boostの値を色々と変更して最終的に1まで持って行ったのですが、negativeに指定した単語は含まれていませんでした。


(Sunggyu Kei Rhie) #6

ここが気になりますね。
Boostingするには何かしらの形でNegativeになったワードでのスコアが存在しないといけないはずで、
そもそもexplainの中に該当ワード自体存在しないのは検索対象になってないって意味なんじゃないかと。


(Sunggyu Kei Rhie) #7

というかよく見たらこのBoostingは

positiveとnegativeが別のクエリで評価するわけではなく、
positiveで抽出したドキュメントに対して、negativeでスコアを落とすような処理をやるんですね。

手元で確かめた結果、
positiveのtermの条件にヒットしたドキュメントのみに対して、
negativeのtermの条件にもヒットしたものが

{
       "value": 0.2,
       "description": "boost",
       "details": []
}

以上のようにboostingされてました。
つまりpositiveの結果に対してnegativeでboostingを行う感じですね。

ご参考に。


(Tarou Tanaka) #8

@r4-keisuke様
ご返信ありがとうございます。

positiveで抽出したドキュメントに対して、negativeでスコアを落とすような処理をやるんですね。

そうだったのですね、勘違いしておりました。
その前提で、動作が問題なく動くことをこちらでも確認できました。
ご回答ありがとうございました。


(Makoto Nozawa) #9

なるほど、boosting queryを完全に勘違いしていました。
混乱を招いて申し訳ないです。

positiveにも"了解"を含めた上で改めてnegative boostを行えば期待した動作になりそうですね。


(Jun Ohtani) #10

@mnozawa
多分、ドキュメントがわかりにくいんですよね。
古い資料になりますが、Definitive Guideにある記述がわかりやすいです。

It accepts a positive query and a negative query. 
Only documents that match the positive query will be included in the results list, 
but documents that also match the negative query will be downgraded 
by multiplying the original _score of the document with the negative_boost.

@Tarou_Tanaka
これもわかりにくいのですが、QueryごとにBoostを追加することが可能です。
https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-boost.html
QueryではなくMappingのページに記載があるので探しにくいですね。。。

ですので、bool queryのshouldなどで単語ごとに条件を指定しつつ、 上位に出したい単語の条件のboostの値を大きくするなどといった方法で対応ができるのではないでしょうか?


(Tarou Tanaka) #11

御返信有難うございます。

bool queryのshouldなどで単語ごとに条件を指定しつつ、 上位に出したい単語の条件のboostの値を大きくする

確かにこちらの方が、Boostingを使うよりもわかりやすく書けそうですね。ですのでこちらの方法で実装しようと思います。
有難うございました。


(system) closed #12

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