フレーズ検索時のNGram TokenizerとNGram Token Filterの違いについて


#1

お世話になっております。

フレーズ検索をした際、アナライザーにNGram Tokenizerをセットした場合と、NGram Token Filterをセットした場合で検索結果が異なりました。
NGram Token Filterをセットした場合でも、NGram Tokenizerをセットした場合と同じ検索結果にしたいのですが、どなたか解決策をご存じでしょうか。よろしくお願いいたします。

1.アナライザー設定

{
  "analysis": {
    "filter": {
      "ngram_filter": {
        "type": "ngram",
        "min_gram": "1",
        "max_gram": "2"
      },
      "normalize": {
        "name": "nfkc",
        "type": "icu_normalizer"
      }
    },
    "char_filter": {
      "whitespace_remove": {
        "pattern": "\\s{1,}",
        "type": "pattern_replace",
        "replacement": ""
      }
    },
    "analyzer": {
      "jp_ngram_tokenizer": {
        "filter": [ "normalize" ],
        "char_filter": [ "whitespace_remove" ],
        "type": "custom",
        "tokenizer": "ngram_tokenizer"
      },
      "jp_ngram_filter": {
        "filter": [ "normalize", "ngram_filter" ],
        "char_filter": [ "whitespace_remove" ],
        "type": "custom",
        "tokenizer": "whitespace_tokenizer"
      }
    },
    "tokenizer": {
      "ngram_tokenizer": {
        "type": "ngram",
        "min_gram": "1",
        "max_gram": "2"
      },
      "whitespace_tokenizer": { "type": "whitespace" }
    }
  }

2.登録データ

value
日本
本日
日の丸弁当
日本国憲法

3.検索クエリ

(1) NGram Tokenizerの場合

GET index1/_search
{
  "from": 0,
  "size": 4,
  "query": {
    "match_phrase": {
      "value": {
        "query": "日本",
        "analyzer": "jp_ngram_tokenizer"
      }
    }
  }
}

(2) NGram Token Filterの場合

GET index1/_search
{
  "from": 0,
  "size": 4,
  "query": {
    "match_phrase": {
      "value": {
        "query": "日本",
        "analyzer": "jp_ngram_filter"
      }
    }
  }
}

4.結果

(1) NGram Tokenizerの場合

"hits": {
    "total": 2,
    "max_score": 0.8027456,
    "hits": [
      {
        "_index": "index1",        
        "_id": "1",
        "_score": 0.8027456,
        "_source": {
          "value": "日本"
        }
      },
      {
        "_index": "index1",        
        "_id": "4",
        "_score": 0.5158902,
        "_source": {
          "value": "日本国憲法"
        }
      }
    ]
  }

(2) NGram Token Filterの場合

"hits": {
    "total": 4,
    "max_score": 0.27233246,
    "hits": [
      {
        "_index": "index1",        
        "_id": "3",
        "_score": 0.27233246,
        "_source": {
          "value": "日の丸弁当"
        }
      },
      {
        "_index": "index1",        
        "_id": "1",
        "_score": 0.21923064,
        "_source": {
          "value": "日本"
        }
      },
      {
        "_index": "index1",        
        "_id": "2",
        "_score": 0.19454905,
        "_source": {
          "value": "本日"
        }
      },
      {
        "_index": "index1",        
        "_id": "4",
        "_score": 0.17135386,
        "_source": {
          "value": "日本国憲法"
        }
      }
    ]
  }

(Jun Ohtani) #2

根本的な質問として同様にしたい理由というのはどういったものでしょうか?

問題点としては、NGram Token Filterがpositionを書き換えているのが問題になります。。。


#3

返信が遅くなってしまい申し訳ございません。
後出しになってしまいますが、やりたいことは、同義語展開した語でPhrase Matchingをさせるというものです。
同義語展開がトークンフィルターで行われるため、同じくトークンフィルターでNgramにトークンを分解し、Termの出現位置や順序を保持した状態で検索する必要があると思い、質問させていただきました。
現状、search_analyzerクエリを使って検索キーワードの同義語を取得した後に、match_phraseクエリを組み立てているのですが、よりよい方法はないのでしょうか。


(Jun Ohtani) #4

Synonymでという話なら、Synonymの設定にTokenizerを指定することができますが、それはダメなのでしょうか?
https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-synonym-tokenfilter.html


#5

ご回答ありがとうございます。
Synonymの設定のTokenizerですが、Ngramの場合ですと同義語展開できない場合があるため使っていませんでした。

例えば同義語辞書に次の語を登録し、

にほん => にほん,にっぽん,日本
日本 => 日本,にほん,にっぽん,
日 => 日,日本,にほん,にっぽん

Synonymの設定のTokenizerに上記の「ngram_tokenizer」を設定した場合、
「にほん」及び「日本」で検索をかけると同義語展開されません。

形態素解析であればSynonymの設定のTokenizerを使うことができると思いますが、Ngramで検索をしたいため困っております。


(Jun Ohtani) #6

具体的にどのようにやった場合にうまくいかなかったでしょうか?
実際のサンプルを提示していただけますでしょうか?類義語とNGramの部分だけでもいいので。


(system) #7

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