A curious thing can happen when you try to use phrase matching on multivalue
fields. (((“proximity matching”, “on multivalue fields”)))(((“match_phrase query”, “on multivalue fields”))) Imagine that you index this document:
PUT /my_index/groups/1
{
“names”: [ “John Abraham”, “Lincoln Smith”]
}
// SENSE: 120_Proximity_Matching/15_Multi_value_fields.json
Then run a phrase query for :
GET /my_index/groups/_search
{
“query”: {
“match_phrase”: {
“names”: “Abraham Lincoln”
}
}
}
Surprisingly, our document matches, even though Abraham
and Lincoln
belong to two different people in the names
array. The reason for this comes
down to the way arrays are indexed in Elasticsearch.
When John Abraham
is analyzed, it produces this:
- Position 1:
john
- Position 2:
abraham
Then when Lincoln Smith
is analyzed, it produces this:
- Position 4:
smith
In other words, Elasticsearch produces exactly the same list of tokens as it would have
for the single string John Abraham Lincoln Smith
. Our example query
looks for abraham
directly followed by lincoln
, and these two terms do
indeed exist, and they are right next to each other, so the query matches.
Fortunately, there is a simple workaround for cases like these, called theposition_offset_gap
, which(((“mapping (types)”, “position_offset_gap”)))(((“position_offset_gap”))) we need to configure in the field mapping:
PUT /my_index/_mapping/groups <2>
{
“properties”: {
“names”: {
“type”: “string”,
“position_offset_gap”: 100
}
}
}
// SENSE: 120_Proximity_Matching/15_Multi_value_fields.json
<1> First delete the groups
mapping and all documents of that type.
<2> Then create a new groups
mapping with the correct values.
The setting tells Elasticsearch that it should increase
the current term position
by the specified value for every new array
element. So now, when we index the array of names, the terms are emitted with
the following positions:
- Position 1:
john
- Position 2:
abraham
- Position 104:
smith