2

「短いドキュメント」のセットに対して正確にクエリを実行する必要があります。例:

ドキュメント:

  1. {"name": "John Doe", "alt": "John W Doe"}
  2. {"name": "私の友人 John Doe", "alt": "John A Doe"}
  3. {"name": "John", "alt": "Susy"}
  4. {"name": "Jack", "alt": "John Doe"}

予想された結果:

  1. 「John Doe」を検索する場合、1 のスコアが 2 と 4 のスコアよりもはるかに大きくなるようにします
  2. 「John Doé」で検索すると、上記と同じ
  3. 「John」を検索すると、3 を取得したい (名前と alt の繰り返しよりも完全一致の方が良い)

ESで可能ですか?どうすればこれを達成できますか? 「名前」をブーストしようとしましたが、ドキュメント フィールド内を検索する代わりに、ドキュメント フィールドと完全に一致させる方法が見つかりません。

4

2 に答える 2

5

あなたが説明しているのは、まさに検索エンジンがデフォルトでどのように機能するかです。の検索"John Doe"は、用語"john"andの検索になり"doe"ます。用語ごとに、その用語を含むドキュメントを探し、次に_score基づいて各ドキュメントに を割り当てます。

  • その用語がすべてのドキュメントでどの程度一般的か (より一般的 == 関連性が低い)
  • ドキュメントの分野内でその用語がどの程度一般的か (より一般的 == 関連性が高い)
  • ドキュメントのフィールドの長さ (長い == 関連性が低い)

明確な結果が表示されない理由は、Elasticsearch が分散されており、少量のデータでテストしているためです。デフォルトでは、インデックスには 5 つのプライマリ シャードがあり、ドキュメントはさまざまなシャードでインデックス化されます。各シャードには独自のドキュメント頻度カウントがあるため、スコアが歪んでいます。

実際の量のデータを追加すると、頻度はシャード全体で均等になりますが、少量のデータをテストするには、次の 2 つのいずれかを行う必要があります。

  1. プライマリ シャードが 1 つだけのインデックスを作成する、または
  2. 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éです。これは分析の問題です。全文をより検索しやすくするために、それを個別の用語またはトークンに分析し、インデックスに格納します。たとえばjohnJohnおよび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
# }
于 2013-03-22T11:13:30.347 に答える
2

複数のフィールドとしてマッピングし、分析されていないフィールドをブーストすると、必要なものが達成されると思います。

 "name": {
            "type": "multi_field",
            "fields": {
                "untouched": {
                    "type": "string",
                    "index": "not_analyzed",
                    "boost": "1.1"
                },
                "name": {
                    "include_in_all": true,
                    "type": "string",
                    "index": "analyzed",
                    "search_analyzer": "someanalyzer",
                    "index_analyzer": "someanalyzer"
                }
            }
        }

柔軟性が必要な場合は、query_string で '^' 表記を使用して、インデックス時間の代わりにクエリ時間を増やすこともできます。

{
    "query_string" : {
        "fields" : ["name, name.untouched^5"],
        "query" : "this AND that OR thus",
    }
}
于 2013-03-21T13:54:27.833 に答える