あなたが説明しているのは、まさに検索エンジンがデフォルトでどのように機能するかです。の検索"John Doe"
は、用語"john"
andの検索になり"doe"
ます。用語ごとに、その用語を含むドキュメントを探し、次に_score
基づいて各ドキュメントに を割り当てます。
- その用語がすべてのドキュメントでどの程度一般的か (より一般的 == 関連性が低い)
- ドキュメントの分野内でその用語がどの程度一般的か (より一般的 == 関連性が高い)
- ドキュメントのフィールドの長さ (長い == 関連性が低い)
明確な結果が表示されない理由は、Elasticsearch が分散されており、少量のデータでテストしているためです。デフォルトでは、インデックスには 5 つのプライマリ シャードがあり、ドキュメントはさまざまなシャードでインデックス化されます。各シャードには独自のドキュメント頻度カウントがあるため、スコアが歪んでいます。
実際の量のデータを追加すると、頻度はシャード全体で均等になりますが、少量のデータをテストするには、次の 2 つのいずれかを行う必要があります。
- プライマリ シャードが 1 つだけのインデックスを作成する、または
search_type=dfs_query_then_fetch
グローバル頻度を使用してクエリを実行する前に、各シャードから頻度を最初に取得するものを指定します
実証するには、まずデータにインデックスを付けます。
curl -XPUT 'http://127.0.0.1:9200/test/test/1?pretty=1' -d '
{
"alt" : "John W Doe",
"name" : "John Doe"
}
'
curl -XPUT 'http://127.0.0.1:9200/test/test/2?pretty=1' -d '
{
"alt" : "John A Doe",
"name" : "My friend John Doe"
}
'
curl -XPUT 'http://127.0.0.1:9200/test/test/3?pretty=1' -d '
{
"alt" : "Susy",
"name" : "John"
}
'
curl -XPUT 'http://127.0.0.1:9200/test/test/4?pretty=1' -d '
{
"alt" : "John Doe",
"name" : "Jack"
}
'
"john doe"
ここで、指定することを忘れずに を検索しますdfs_query_then_fetch
。
curl -XGET 'http://127.0.0.1:9200/test/test/_search?pretty=1&search_type=dfs_query_then_fetch' -d '
{
"query" : {
"match" : {
"name" : "john doe"
}
}
}
'
Doc 1 が結果の最初です。
# {
# "hits" : {
# "hits" : [
# {
# "_source" : {
# "alt" : "John W Doe",
# "name" : "John Doe"
# },
# "_score" : 1.0189849,
# "_index" : "test",
# "_id" : "1",
# "_type" : "test"
# },
# {
# "_source" : {
# "alt" : "John A Doe",
# "name" : "My friend John Doe"
# },
# "_score" : 0.81518793,
# "_index" : "test",
# "_id" : "2",
# "_type" : "test"
# },
# {
# "_source" : {
# "alt" : "Susy",
# "name" : "John"
# },
# "_score" : 0.3066778,
# "_index" : "test",
# "_id" : "3",
# "_type" : "test"
# }
# ],
# "max_score" : 1.0189849,
# "total" : 3
# },
# "timed_out" : false,
# "_shards" : {
# "failed" : 0,
# "successful" : 5,
# "total" : 5
# },
# "took" : 8
# }
だけを検索すると"john"
:
curl -XGET 'http://127.0.0.1:9200/test/test/_search?pretty=1&search_type=dfs_query_then_fetch' -d '
{
"query" : {
"match" : {
"name" : "john"
}
}
}
'
Doc 3 が最初に表示されます。
# {
# "hits" : {
# "hits" : [
# {
# "_source" : {
# "alt" : "Susy",
# "name" : "John"
# },
# "_score" : 1,
# "_index" : "test",
# "_id" : "3",
# "_type" : "test"
# },
# {
# "_source" : {
# "alt" : "John W Doe",
# "name" : "John Doe"
# },
# "_score" : 0.625,
# "_index" : "test",
# "_id" : "1",
# "_type" : "test"
# },
# {
# "_source" : {
# "alt" : "John A Doe",
# "name" : "My friend John Doe"
# },
# "_score" : 0.5,
# "_index" : "test",
# "_id" : "2",
# "_type" : "test"
# }
# ],
# "max_score" : 1,
# "total" : 3
# },
# "timed_out" : false,
# "_shards" : {
# "failed" : 0,
# "successful" : 5,
# "total" : 5
# },
# "took" : 5
# }
アクセントを無視する
2 番目の問題は、" のマッチングの問題"John Doé
です。これは分析の問題です。全文をより検索しやすくするために、それを個別の用語またはトークンに分析し、インデックスに格納します。たとえばjohn
、John
およびJOHN
ユーザーが を検索するとjohn
、各用語/トークンが多数のトークン フィルターに渡され、標準形式に変換されます。
全文検索を行う場合、検索用語はこれとまったく同じプロセスを経ます。したがって、 を含むドキュメントがある場合John
、これは として索引付けされjohn
、ユーザーが を検索するとJOHN
、実際には を検索しjohn
ます。
Doé
matchを作成するにdoe
は、アクセントを削除するトークン フィルターが必要であり、それをインデックス化されるテキストと検索用語の両方に適用する必要があります。これを行う最も簡単な方法は、ASCII フォールディング トークン フィルターを使用することです。
インデックスを作成するときにカスタム アナライザーを定義できます。また、特定のフィールドがインデックス時と検索時の両方でそのアナライザーを使用する必要があることをマッピングで指定できます。
まず、古いインデックスを削除します。
curl -XDELETE 'http://127.0.0.1:9200/test/?pretty=1'
次に、カスタム アナライザーとマッピングを指定して、インデックスを作成します。
curl -XPUT 'http://127.0.0.1:9200/test/?pretty=1' -d '
{
"settings" : {
"analysis" : {
"analyzer" : {
"no_accents" : {
"filter" : [
"standard",
"lowercase",
"asciifolding"
],
"type" : "custom",
"tokenizer" : "standard"
}
}
}
},
"mappings" : {
"test" : {
"properties" : {
"name" : {
"type" : "string",
"analyzer" : "no_accents"
}
}
}
}
}
'
データを再インデックス化します。
curl -XPUT 'http://127.0.0.1:9200/test/test/1?pretty=1' -d '
{
"alt" : "John W Doe",
"name" : "John Doe"
}
'
curl -XPUT 'http://127.0.0.1:9200/test/test/2?pretty=1' -d '
{
"alt" : "John A Doe",
"name" : "My friend John Doe"
}
'
curl -XPUT 'http://127.0.0.1:9200/test/test/3?pretty=1' -d '
{
"alt" : "Susy",
"name" : "John"
}
'
curl -XPUT 'http://127.0.0.1:9200/test/test/4?pretty=1' -d '
{
"alt" : "John Doe",
"name" : "Jack"
}
'
次に、検索をテストします。
curl -XGET 'http://127.0.0.1:9200/test/test/_search?pretty=1&search_type=dfs_query_then_fetch' -d '
{
"query" : {
"match" : {
"name" : "john doé"
}
}
}
'
# {
# "hits" : {
# "hits" : [
# {
# "_source" : {
# "alt" : "John W Doe",
# "name" : "John Doe"
# },
# "_score" : 1.0189849,
# "_index" : "test",
# "_id" : "1",
# "_type" : "test"
# },
# {
# "_source" : {
# "alt" : "John A Doe",
# "name" : "My friend John Doe"
# },
# "_score" : 0.81518793,
# "_index" : "test",
# "_id" : "2",
# "_type" : "test"
# },
# {
# "_source" : {
# "alt" : "Susy",
# "name" : "John"
# },
# "_score" : 0.3066778,
# "_index" : "test",
# "_id" : "3",
# "_type" : "test"
# }
# ],
# "max_score" : 1.0189849,
# "total" : 3
# },
# "timed_out" : false,
# "_shards" : {
# "failed" : 0,
# "successful" : 5,
# "total" : 5
# },
# "took" : 6
# }