首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >英国邮政编码的Elasticsearch映射,能够处理间距和上限

英国邮政编码的Elasticsearch映射,能够处理间距和上限
EN

Stack Overflow用户
提问于 2020-03-21 21:13:10
回答 2查看 531关注 0票数 1

我正在寻找一个映射/分析器设置Elasticsearch 7与英国邮政编码。我们不需要任何模糊算子,但应该能够处理大写字母和间距的变化。

下面是一些例子:

查询字符串: "SN13 9ED“应返回:

  • sn139ed
  • SN13 9ED
  • Sn13 9ed

但不应返回:

  • SN13 1EP
  • SN131EP

关键字分析器在默认情况下使用,这似乎是敏感的间隔问题,但不是大写字母。它还将返回SN13 1EP的匹配,除非我们将查询指定为SN13 AND 9ED,这是我们不想要的。

此外,使用关键字分析器,SN13 9ED查询返回SN13 1EP的结果,其相关性高于SN13 9ED,尽管这应该是完全匹配的。为什么在同一个字符串中的两个匹配比一个匹配更低的相关性?

邮政编码映射

代码语言:javascript
复制
"post_code": {
    "type": "text",
    "fields": {
        "keyword": {
            "type": "keyword",
            "ignore_above": 256
        }
    }
},

查询

代码语言:javascript
复制
  "query" => array:1 [▼
    "query_string" => array:1 [▼
      "query" => "KT2 7AJ"
    ]
  ]
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 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的两个,从而将它们保存在倒排索引中,在本例中是sn131ep。在将它们存储在倒排索引中之前,我还降低了它们的限制。

注意,我为您的邮政编码添加的场景是,它的大小是固定的,即有7个字符。如果不是这样的话,可以添加更多的模式,

详情请参阅下文:

制图:

代码语言:javascript
复制
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"
          }
        }
      }
    }
  }
}

样本文件:

代码语言:javascript
复制
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"
}

注意,这些文档在语义上是相同的。

请求查询:

代码语言:javascript
复制
POST my_postcode_index/_search
{
  "query": {
    "query_string": {
      "default_field": "postcode",
      "query": "SN13 1EP",
      "default_operator": "AND"
    }
  }
}

响应:

代码语言:javascript
复制
{
  "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"
        }
      }
    ]
  }
}

请注意,即使使用查询snp131psnp13 1ep,也会返回所有三个文档。

补充说明:

可以使用分析API来确定为特定文本创建了哪些标记。

代码语言:javascript
复制
POST my_postcode_index/_analyze
{
  "analyzer": "my_analyzer",
  "text": "sn139ed"
}

下面可以看到倒排索引中存储的标记。

代码语言:javascript
复制
{
  "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托卡器的内容。我建议你考虑一下这两种解决方案,看看什么最适合你的输入。

如果您有任何疑问,请进行测试,并通知我。

票数 1
EN

Stack Overflow用户

发布于 2020-03-22 12:56:59

除了Opster的回答之外,下面的内容也可以用来从相反的角度来解决这个问题。对于Opster的回答,他们建议用一个已知的邮政编码模式来分割值,这是很棒的。

如果我们不知道这种模式,可以使用以下方法:

代码语言:javascript
复制
{
  "analysis": {
    "filter": {
      "whitespace_remove": {
        "pattern": " ",
        "type": "pattern_replace",
        "replacement": ""
      }
    },
    "analyzer": {
      "no_space_analyzer": {
        "filter": [
          "lowercase",
          "whitespace_remove"
        ],
        "tokenizer": "keyword"
      }
    }
  }
}
代码语言:javascript
复制
{
  "post_code": {
    "type": "text",
    "fields": {
      "keyword": {
        "type": "keyword"
      }
    },
    "analyzer": "no_space_analyzer"
  }
}

这允许我们搜索任何类型的间隔,和任何情况下由于小写过滤器。

sn13 1eps n 1 3 1 e psn131ep都会和SN13 1EP比赛

但是,我认为这个选项的主要缺点是我们将不再为sn13获得任何结果,因为我们不会在令牌上生成任何结果。然而,sn13*会给我们带来结果。

是否有可能将这两种方法混合在一起,这样我们就可以同时拥有这两个世界的优点了吗?

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60793330

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档