日本語全文検索について


(tanimoto) #1

elasticseachのプラグインkuromojiを使用して、日本語をバラバラに分割し、検索を行っているのですが、
精度がそれほど良くありません。

例 :

一眼 → 一 と 眼 にわかれる
*kuromojiの検索モードを変えても同じ結果です

ユーザー辞書の使用も考えたのですが、対象となるキーワードが無限にあるため、あまり現実的ではないと考えています。

ならば、elasticsearchのクエリでキーワード検索する際に、検索キーワードも同様にanalyzerにかけてしまえば良いのではと考えたのですが、やり方がわかりません。(というかできるのか?)
参考になるサイトや、方法、または他の良い実現方法をご存知の方がいましたら、ご教授お願いします。


(Shota Ito) #2

見当違いの事を言っていたらすいません。
どういうインターフェースで検索されるのかよくわかっていないのですが、
例えばKibanaのDiscover画面のテキストボックスであればダブルクォーテーションで単語を括ってあげるとそれっぽく検索ができているように思います。


(tanimoto) #3

ご意見ありがとうございます。

現在、elasticsearchを自身の扱っているwebサイトの検索機能として導入しようと考えています。

なので、検索キーワードはwebからの入力値となります。

入力された値を処理でelasticsearchに投げて、elasticsearchのクエリを生成し、該当データを検索しようと考えています。

elasticsearchは、analyzerを設定するとindex時にすでに文字列を単語区切りに分割するようです。

検索時は分割された文字列の中から該当のキーワードを探しているようなのですが、上記のように「一眼」を「一」と「眼」に分割しているように、一部の文字列がうまくヒットしません。

index時にうまくできないのであれば、同じ方法でキーワードも分割してしまえばヒットするかと考えたのですが。。。

やはりユーザー辞書を使用するほかないのでしょうか・・・


(tsgkdt) #4

お使いになられているelasticsearchのバージョンはどれでしょう?

こちらで試した限りですと、5.1.1でkuromojiを設定したフィールドに"私は一眼レフカメラが欲しい"という語を入れて見たところ、
「一眼」が「一」と「眼」に分かれないのです。

mappingの設定や、どのようなクエリをelasticsearchに発行したのかがわかると良いのですが・・・。
なお、検索の精度を上げるアプローチの仕方が参考になるかもしれません。

以下、長くなりますがこちらで確認した内容です。

  1. 事前準備

indexの作成。 kuromoji_tokenizerのmodeごとの差異があるかどうかを確認するため、3つAnalyzerを作りました。

  • ja-normal-analyzer
  • ja-search-analyzer
  • ja-extended-analyzer
PUT kuromoji-test
{
  "template": "kuromoji-test",
  "settings": {
    "analysis": {
      "analyzer": {
        "ja-normal-analyzer": {
          "type": "custom",
          "tokenizer": "ja-normal-tokenizer"
        },
        "ja-search-analyzer": {
          "type": "custom",
          "tokenizer": "ja-search-tokenizer"
        },
        "ja-extended-analyzer": {
          "type": "custom",
          "tokenizer": "ja-extended-tokenizer"
        }
      },
      "tokenizer": {
        "ja-normal-tokenizer": {
          "type": "kuromoji_tokenizer",
          "mode": "normal"
        },
        "ja-search-tokenizer": {
          "type": "kuromoji_tokenizer",
          "mode": "search"
        },
        "ja-extended-tokenizer": {
          "type": "kuromoji_tokenizer",
          "mode": "extended"
        }
      }
    }
  },
  "mappings": {
    "_default_": {
      "dynamic_templates": [
        {
          "test": {
            "match": "message",
            "mapping": {
              "type": "text",
              "fields": {
                "normal": {
                  "type": "text",
                  "analyzer": "ja-normal-analyzer",
                  "term_vector": "with_positions_offsets",
                  "store": true
                },
                "search": {
                  "type": "text",
                  "analyzer": "ja-search-analyzer",
                  "term_vector": "with_positions_offsets",
                  "store": true
                },
                "extended": {
                  "type": "text",
                  "analyzer": "ja-extended-analyzer",
                  "term_vector": "with_positions_offsets",
                  "store": true
                }
              }
            }
          }
        }
      ]
    }
  }
}

2.Analyze APIによる分割の確認

POST kuromoji-test/_analyze
{
  "analyzer": "ja-normal-analyzer",
  "text" : "私は一眼レフカメラが欲しい"
}

normal, search, extendedのいずれで行っても 一眼は1つのトークンになりました。
これはnormalの結果です。

{
  "tokens": [
    {
      "token": "一眼",
      "start_offset": 0,
      "end_offset": 2,
      "type": "word",
      "position": 0
    },
    {
      "token": "レフ",
      "start_offset": 2,
      "end_offset": 4,
      "type": "word",
      "position": 1
    },
    {
      "token": "カメラ",
      "start_offset": 4,
      "end_offset": 7,
      "type": "word",
      "position": 2
    },
    {
      "token": "が",
      "start_offset": 7,
      "end_offset": 8,
      "type": "word",
      "position": 3
    },
    {
      "token": "欲しい",
      "start_offset": 8,
      "end_offset": 11,
      "type": "word",
      "position": 4
    }
  ]
}

3.検索実行による確認

結果が取得できて、またハイライトも行われることを確認しました。(ちゃんと タグの中に一眼が入っている)

PUT kuromoji-test/test/1
{
  "message" : "私は一眼レフカメラが欲しい"
}
GET kuromoji-test/_search
{
  "query": {
    "match_phrase": {
      "message.normal": "一眼"
    }
    
  },
  "highlight": {
    "require_field_match": false,
    "fields": {
      "message.normal" : {},
      "message.search" : {},
      "message.extended" : {}
    }
  }
}
{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.28582606,
    "hits": [
      {
        "_index": "kuromoji-test",
        "_type": "test",
        "_id": "1",
        "_score": 0.28582606,
        "_source": {
          "message": "私は一眼レフカメラが欲しい"
        },
        "highlight": {
          "message.search": [
            "私は<em>一眼</em>レフカメラが欲しい"
          ],
          "message.extended": [
            "私は<em>一眼</em>レフカメラが欲しい"
          ],
          "message.normal": [
            "私は<em>一眼</em>レフカメラが欲しい"
          ]
        }
      }
    ]
  }
}

(tanimoto) #5

バージョンを5.1.1に変更したところ解決しました。


(system) #6

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