>我有一个查询来搜索以下格式的记录:TR000002_1_2020
.
用户应该能够通过以下方式搜索结果:
TR000002
或2_1_2020
或TR000002_1_2020
或2020
.我使用的是 Elasticsearch 6.8,所以我无法使用 E7 中引入的内置搜索类型。因此,我认为要么wildcard
搜索,要么ngram
最适合我的需要。以下是我的两种方法以及它们不起作用的原因。
- 通配符
属性映射:
.Text(t => t
.Name(tr => tr.TestRecordId)
)
查询:
m => m.Wildcard(w => w
.Field(tr => tr.TestRecordId)
.Value($"*{form.TestRecordId}*")
),
这有效,但它区分大小写,因此如果用户使用tr000002_1_2020
进行搜索,则不会返回任何结果(因为查询中的t
和r
是小写的)
- ngram(键入等效项时搜索)
创建自定义 ngram 分析器
.Analysis(a => a
.Analyzers(aa => aa
.Custom("autocomplete", ca => ca
.Tokenizer("autocomplete")
.Filters(new string[] {
"lowercase"
})
)
.Custom("autocomplete_search", ca => ca
.Tokenizer("lowercase")
)
)
.Tokenizers(t => t
.NGram("autocomplete", e => e
.MinGram(2)
.MaxGram(16)
.TokenChars(new TokenChar[] {
TokenChar.Letter,
TokenChar.Digit,
TokenChar.Punctuation,
TokenChar.Symbol
})
)
)
)
属性映射
.Text(t => t
.Name(tr => tr.TestRecordId)
.Analyzer("autocomplete")
.SearchAnalyzer("autocomplete_search")
)
查询
m => m.Match(m => m
.Query(form.TestRecordId)
),
如本答案所述,这是行不通的,因为分词器将字符拆分为20
和02
和2020
等元素,因此我的查询返回了索引中包含 2020 年的所有文档,例如TR000002_1_2020
和TR000008_1_2020
和TR000003_6_2020
。
Elasticsearch 的最佳用途是什么,以允许我想要的搜索行为?我也见过query string
使用过。谢谢!
这里有一种简单的方法来满足您的要求(我希望)。
- 我们使用模式替换字符过滤器来删除引用的固定部分(TR000... )
- 我们使用拆分分词器来拆分对"_"字符的引用
- 我们使用 matchPhrase 查询来确保引用的片段按顺序匹配
有了这个分析链作为参考TR000002_1_2020
我们得到了["2", "1", "2020" ]
的代币。所以它会匹配["TR000002_1_2020", "TR000002 1 2020", "2_1_2020", "1_2020"]
查询,但它不会匹配3_1_2020
或2_2_2020
。
下面是映射和分析的示例。它不在Nest中,但我认为您将能够进行翻译。
PUT pattern_split_demo
{
"settings": {
"analysis": {
"char_filter": {
"replace_char_filter": {
"type": "pattern_replace",
"pattern": "^TR0*",
"replacement": ""
}
},
"tokenizer": {
"split_tokenizer": {
"type": "simple_pattern_split",
"pattern": "_"
}
},
"analyzer": {
"split_analyzer": {
"tokenizer": "split_tokenizer",
"filter": [
"lowercase"
],
"char_filter": [
"replace_char_filter"
]
}
}
}
},
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "split_analyzer"
}
}
}
}
POST pattern_split_demo/_analyze
{
"text": "TR000002_1_2020",
"analyzer": "split_analyzer"
} => ["2", "1", "2020"]
POST pattern_split_demo/_doc?refresh=true
{
"content": "TR000002_1_2020"
}
POST pattern_split_demo/_search
{
"query": {
"match_phrase": {
"content": "TR000002_1_2020"
}
}
}