我想在elasticsearch上执行精确匹配,但精确匹配应该在文档上而不是在搜索字符串上。例如:
我创建了这个索引:
PUT /indexName
{
"mappings": {
"properties": {
"name": {
"type": "text"
}
}
}
}
POST /indexName/_doc
{
"name": "City"
}
POST /indexName/_doc
{
"name": "City Lab"
}
现在我想执行这样的搜索:
-如果我搜索(“城市”),我只想获取第一个文档,第二个文档不应该匹配,因为(“城市”)没有计算整个(“城市实验室”)。
-如果我搜索(“城市实验室”),我想获得第二个文档和第一个文档网,因为它与它们完全匹配。
-如果我搜索(“Citly Lab 在哪里”),我们有(“City”)并且我们有(“City Lab”),所以我也想同时获得它们。
-如果我搜索(“lab”),我将得到 0 个命中,因为 lab 不匹配任何内容。
-如果我搜索(“我在城市里面,然后我会去实验室”),我应该只得到第一个文档,(“城市”)是完全匹配的,但是(“我在里面” city,那么我会去lab”)(“city ... lab”),(“Lab”)不是直接在(“City”)之后,所以它不匹配。
如何在elasticsearch中做到这一点?
这需要特定的方法。我们需要使用不同的分析器来搜索和索引该字段。索引分析器将删除多余的空格和标点符号,将文本转换为小写,并将其索引为单个术语。同时,搜索分析器还将处理空格和标点符号处理,但它还会为每个单词、单词对、单词三元组等生成搜索词。
因此,在索引过程中,“City Lab”将成为单个标记
city lab
,而“City”将成为 city
。同时搜索“City Lab”时会变成查询:
city
或 lab
或 city lab
这样它将匹配索引标记
city lab
和 city
。同时,仅搜索“lab”将生成一个与任何内容都不匹配的标记 lab
。这是一个完整的例子:
DELETE test
PUT test
{
"settings": {
"max_shingle_diff": 4,
"analysis": {
"char_filter": {
"whitespace_and_punct_to_single_space": {
"type": "pattern_replace",
"pattern": "[\\p{Punct}\\s]+",
"replacement": " "
}
},
"filter": {
"name_shingles": {
"type": "shingle",
"min_shingle_size": 2,
"max_shingle_size": 5,
"output_unigrams": true
}
},
"analyzer": {
"name_index_analyzer": {
"type": "custom",
"char_filter": [
"whitespace_and_punct_to_single_space"
],
"tokenizer": "keyword",
"filter": [
"lowercase"
]
},
"name_search_analyzer": {
"type": "custom",
"char_filter": [
"whitespace_and_punct_to_single_space"
],
"tokenizer": "whitespace",
"filter": [
"lowercase",
"name_shingles"
]
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "name_index_analyzer",
"search_analyzer": "name_search_analyzer"
}
}
}
}
POST test/_bulk?refresh
{"index": {"_id": 1}}
{"name": "City"}
{"index": {"_id": 2}}
{"name": "City Lab"}
GET test/_search
{
"query": {
"match": {
"name": "City"
}
}
}
GET test/_search
{
"query": {
"match": {
"name": "City Lab"
}
}
}
GET test/_search
{
"query": {
"match": {
"name": "Where is the City Lab?"
}
}
}
GET test/_search
{
"query": {
"match": {
"name": "lab"
}
}
}
GET test/_search
{
"query": {
"match": {
"name": "I am inside the city, then I will go to the lab"
}
}
}