想要使用完成建议程序来构建电子商务网站的自动完成功能。
这是我的索引:
PUT myIndex
{
"mappings": {
"_doc" : {
"properties" : {
"suggest" : {
"type" : "completion"
},
"title" : {
"type": "keyword"
},
"category" : {
"type": "keyword"
},
"description" : {
"type": "keyword"
}
}
}
}
}
现在,当上传广告时,我希望标题字段用于自动完成,因此这就是我上传文档的方式:
POST dummy/_doc
{
"title": "Blue asics running shoes",
"category": "sports",
"description": "Nice blue running shoes, size 44 eu",
"suggest": {
"input": "Blue Asics running shoes" // <-- use title
}
}
问题是,弹性搜索仅从开始就匹配字符串...即“ Blu”将找到结果,但“ Asic”或“ Run”或“ Sho”将不会返回任何结果...
所以我需要做的是这样标记输入:
POST dummy/_doc
{
"title": "Blue asics running shoes",
"category": "sports",
"description": "Nice blue running shoes, size 44 eu",
"suggest": {
"input": ["Blue", "Asics", "running", "shoes"] // <-- tokenized title
}
}
这会很好...但是我应该如何标记我的字段?我知道我可以在c#中拆分字符串,但是无论如何,我可以在Elasticsearch / Nest中做到这一点吗?
答案 0 :(得分:1)
Completion suggester设计用于使用simple
分析器而不是默认的standard
分析器,根据您的类型快速搜索前缀查询text
数据类型。
如果您需要标题中的 any 标记上的部分前缀匹配,而不仅仅是从标题的开头开始,您可能要考虑采用以下方法之一:
将Analyze API与分析器一起使用,该分析器会将标题标记化为要部分前缀匹配的标记/术语,然后将此集合作为input
索引到{{1 }}字段。标准分析仪可能是一个很好的起点。
请记住,完成建议程序的数据结构在使用中保存在内存中,因此跨文档的长期基数将增加此数据结构的内存需求。还应考虑到匹配项的“计分”很简单,因为它受应用于每个输入的权重的控制。
或
请不要在此处使用“完成建议程序”,而是将completion
字段设置为具有multi-fields的title
数据类型,其中包括text
的不同方式应该进行分析(或不进行分析,例如,使用title
子字段)。
花一些时间使用Analyze API来构建一个分析器,该分析器将允许在标题中任何位置使用部分术语前缀。首先,诸如标准令牌生成器,小写令牌过滤器,Edgengram令牌过滤器以及可能的Stop令牌过滤器之类的工具会让您运行起来。还要注意,您可能希望Search analyzer的功能类似于索引分析器 Edgengram令牌过滤器,因为搜索输入中的令牌不需要进行ngramming。
< / li>答案 1 :(得分:0)
基于上述Russ Cam的答案(选项2),this Elasticsearch guide以及this document,我得出了以下解决方案:
PUT my_index
{
"settings": {
"analysis": {
"filter": {
"edge_ngram_token_filter": {
"type": "edge_ngram",
"min_gram": 2,
"max_gram": 10
},
"additional_stop_words": {
"type": "stop",
"stopwords": ["your"]
},
"english_stemmer": {
"type": "stemmer",
"language": "english"
},
"english_possessive_stemmer": {
"type": "stemmer",
"language": "possessive_english"
}
},
"char_filter": {
"my_char_filter": {
"type": "mapping",
"mappings": [
"C# => csharp",
"c# => csharp"
]
}
},
"analyzer": {
"result_suggester_analyzer": {
"type": "custom",
"tokenizer": "standard",
"char_filter": [ "html_strip", "my_char_filter" ],
"filter": [
"english_possessive_stemmer",
"lowercase",
"asciifolding",
"stop",
"additional_stop_words",
"english_stemmer",
"edge_ngram_token_filter",
"unique"
]
}
}
}
}
}
查询以测试此解决方案:
POST my_index/_analyze
{
"analyzer": "result_suggester_analyzer",
"text": "C# & SQL are great languages. K2 is the mountaineer's mountain. Your house-décor is à la Mode"
}
我会得到这些令牌(NGrams):
cs, csh, csha, cshar, csharp, sq, sql, gr, gre, grea, great, la, lan, lang,
langu, langua, languag, k2, mo, mou, moun, mount, mounta, mountai, mountain,
ho, hou, hous, hous, de, dec, deco, decor, mod, mode
这里要注意的事情:
stop
过滤器,这是默认的英语
过滤并阻止are, is, the
-但没有阻止your
。 additional_stop_words
,它会停止your
english
和possessive_english
词干分析器将标记词干:这就是为什么我们有 languag 标记但没有语言的原因……请注意,我们有山脉,但没有高山运动。mapped_words_char_filter
,它将C#转换为csharp,没有这个c#将不是有效的令牌...(此设置不会标记化F#)html_strip
,char_filter
将&
转换为&,并且由于我们的min_gram = 2 asciifolding
令牌过滤器,这就是为什么décor被标记为 decor 的原因。这是上面的NEST代码:
var createIndexResponse = ElasticClient.CreateIndex(IndexName, c => c
.Settings(st => st
.Analysis(an => an
.Analyzers(anz => anz
.Custom("result_suggester_analyzer", cc => cc
.Tokenizer("standard")
.CharFilters("html_strip", "mapped_words_char_filter")
.Filters(new string[] { "english_possessive_stemmer", "lowercase", "asciifolding", "stop", "english_stemmer", "edge_ngram_token_filter", "unique" })
)
)
.CharFilters(cf => cf
.Mapping("mapped_words_char_filter", md => md
.Mappings(
"C# => csharp",
"c# => csharp"
)
)
)
.TokenFilters(tfd => tfd
.EdgeNGram("edge_ngram_token_filter", engd => engd
.MinGram(2)
.MaxGram(10)
)
.Stop("additional_stop_word", sfd => sfd.StopWords(new string[] { "your" }))
.Stemmer("english_stemmer", esd => esd.Language("english"))
.Stemmer("english_possessive_stemmer", epsd => epsd.Language("possessive_english"))
)
)
)
.Mappings(m => m.Map<AdDocument>(d => d.AutoMap())));