我正在寻找一个映射/分析器设置Elasticsearch 7与英国邮政编码。我们不需要任何模糊算子,但应该能够处理大写字母和间距的变化。
下面是一些例子:
查询字符串: "SN13 9ED“应返回:
但不应返回:
关键字分析器在默认情况下使用,这似乎是敏感的间隔问题,但不是大写字母。它还将返回SN13 1EP的匹配,除非我们将查询指定为SN13 AND 9ED,这是我们不想要的。
此外,使用关键字分析器,SN13 9ED查询返回SN13 1EP的结果,其相关性高于SN13 9ED,尽管这应该是完全匹配的。为什么在同一个字符串中的两个匹配比一个匹配更低的相关性?
邮政编码映射
"post_code": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},查询
"query" => array:1 [▼
"query_string" => array:1 [▼
"query" => "KT2 7AJ"
]
]发布于 2020-03-22 00:37:31
我相信根据我的评论,当搜索字符串为SN13 1EP时,您可能已经能够过滤掉SN13 9ED。
希望您了解Analysis是什么,Analyzers如何在text字段上工作,以及在令牌最终存储在倒排索引之前如何在令牌上应用Standard Analyzer。请注意,这仅适用于text字段。
查看您的映射,如果您使用的是在post_code上搜索而不是使用post_code.keyword,我相信大写化会得到解决,因为text字段的ES默认使用Standard Analyzer,这意味着您的令牌最终将被保存为小写格式的索引,即使在查询期间,也会在查询期间在搜索倒排索引之前应用分析器。
请注意,默认情况下,映射中配置的同一个分析器在索引时间和该字段的搜索时间内应用。
对于有sn131ep的场景,我所做的是使用模式捕获令牌过滤器,其中我指定了一个正则表达式,它将令牌分成长度分别为4和3的两个,从而将它们保存在倒排索引中,在本例中是sn13和1ep。在将它们存储在倒排索引中之前,我还降低了它们的限制。
注意,我为您的邮政编码添加的场景是,它的大小是固定的,即有7个字符。如果不是这样的话,可以添加更多的模式,
详情请参阅下文:
制图:
PUT my_postcode_index
{
"settings" : {
"analysis" : {
"filter" : {
"mypattern" : {
"type" : "pattern_capture",
"preserve_original" : true,
"patterns" : [
"(\\w{4}+)|(\\w{3}+)", <--- Note this and feel free to add more patterns
"\\s" <--- Filter based on whitespace
]
}
},
"analyzer" : {
"my_analyzer" : {
"tokenizer" : "pattern",
"filter" : [ "mypattern", "lowercase" ] <--- Note the lowercase here
}
}
}
},
"mappings": {
"properties": {
"postcode":{
"type": "text",
"analyzer": "my_analyzer", <--- Note this
"fields":{
"keyword":{
"type": "keyword"
}
}
}
}
}
}样本文件:
POST my_postcode_index/_doc/1
{
"postcode": "SN131EP"
}
POST my_postcode_index/_doc/2
{
"postcode": "sn13 1EP"
}
POST my_postcode_index/_doc/3
{
"postcode": "sn131ep"
}注意,这些文档在语义上是相同的。
请求查询:
POST my_postcode_index/_search
{
"query": {
"query_string": {
"default_field": "postcode",
"query": "SN13 1EP",
"default_operator": "AND"
}
}
}响应:
{
"took" : 24,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 0.6246513,
"hits" : [
{
"_index" : "my_postcode_index",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.6246513,
"_source" : {
"postcode" : "SN131EP"
}
},
{
"_index" : "my_postcode_index",
"_type" : "_doc",
"_id" : "3",
"_score" : 0.6246513,
"_source" : {
"postcode" : "sn131ep"
}
},
{
"_index" : "my_postcode_index",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.5200585,
"_source" : {
"postcode" : "sn13 1EP"
}
}
]
}
}请注意,即使使用查询snp131p和snp13 1ep,也会返回所有三个文档。
补充说明:
可以使用分析API来确定为特定文本创建了哪些标记。
POST my_postcode_index/_analyze
{
"analyzer": "my_analyzer",
"text": "sn139ed"
}下面可以看到倒排索引中存储的标记。
{
"tokens" : [
{
"token" : "sn139ed",
"start_offset" : 0,
"end_offset" : 7,
"type" : "word",
"position" : 0
},
{
"token" : "sn13",
"start_offset" : 0,
"end_offset" : 7,
"type" : "word",
"position" : 0
},
{
"token" : "9ed",
"start_offset" : 0,
"end_offset" : 7,
"type" : "word",
"position" : 0
}
]
}另外:
您可能还想阅读有关Ngram托卡器的内容。我建议你考虑一下这两种解决方案,看看什么最适合你的输入。
如果您有任何疑问,请进行测试,并通知我。
发布于 2020-03-22 12:56:59
除了Opster的回答之外,下面的内容也可以用来从相反的角度来解决这个问题。对于Opster的回答,他们建议用一个已知的邮政编码模式来分割值,这是很棒的。
如果我们不知道这种模式,可以使用以下方法:
{
"analysis": {
"filter": {
"whitespace_remove": {
"pattern": " ",
"type": "pattern_replace",
"replacement": ""
}
},
"analyzer": {
"no_space_analyzer": {
"filter": [
"lowercase",
"whitespace_remove"
],
"tokenizer": "keyword"
}
}
}
}{
"post_code": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
},
"analyzer": "no_space_analyzer"
}
}这允许我们搜索任何类型的间隔,和任何情况下由于小写过滤器。
sn13 1ep,s n 1 3 1 e p,sn131ep都会和SN13 1EP比赛
但是,我认为这个选项的主要缺点是我们将不再为sn13获得任何结果,因为我们不会在令牌上生成任何结果。然而,sn13*会给我们带来结果。
是否有可能将这两种方法混合在一起,这样我们就可以同时拥有这两个世界的优点了吗?
https://stackoverflow.com/questions/60793330
复制相似问题