【问题标题】:ElasticSearch get best non-exact matchElasticSearch 获得最佳非精确匹配
【发布时间】:2020-07-01 16:53:19
【问题描述】:

使用 elasticsearch-dsl,我正在尝试搜索与公司名称最接近的匹配项,但排除完全匹配项。

例如,我想搜索类似于“大伦敦当局 (GLA)”的名称,但我希望过滤掉所有完全匹配的名称或在分数中给予显着降级。

澄清一下,在我的索引中,我知道字符串“大伦敦当局”存在,并且希望返回的结果比原始字符串更好(也在索引中)

目前我有:

mn =  Q({
    "bool": {
      "must_not": [
        {
          "match": {
            "buyer": entity_name
          }
        }
      ]
    }
  }
)

s = Search(using=es, index="ccs_notices9") \
          .query("match", buyer=entity_name)\
          .query(mn)
         
results = s.execute(s)
results.to_dict()

但我没有得到任何结果,这是有道理的,因为我基本上是在颠倒这两个查询。我尝试在mn 查询中使用“term”代替“match”,但这是不允许的。我也尝试过更简单的:

s = Search(using=es, index="ccs_notices9") \
          .query("match", buyer=entity_name)\
          .exclude("term", buyer=entity_name)

这确实给了我结果,但仍然包含上面的字符串。

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    您必须使用两个不同的字段才能实现您的目标。简而言之,将multi-fields 用于buyer,就像我在下面的用例中所做的那样。

    映射:

    PUT my_exact_match_exclude
    {
      "settings": {
        "analysis": {
          "normalizer": {
            "my_normalizer": {
              "type": "custom",
              "char_filter": [],
              "filter": ["lowercase"]
            }
          }
        }
      }, 
      "mappings": {
        "properties": {
          "buyer": {
            "type": "text",
            "fields": {
              "keyword": {                         <---- Note this
                "type": "keyword", 
                "normalizer": "my_normalizer"      <---- Note this. To take care of case sensitivity    
              }
            }
          }
        }
      }
    }
    

    请注意,城市的映射具有使用 multi-fields 的 keyword 数据类型的兄弟字段。

    还阅读了normalizer 以及为什么我将其应用于keyword 只是为了确保在进行完全匹配时考虑到不区分大小写。

    示例文档:

    POST my_exact_match_exclude/_doc/1
    {
      "buyer": "Greater London Authority (GLA)"
    }
    
    POST my_exact_match_exclude/_doc/2
    {
      "buyer": "Greater London Authority"
    }
    
    POST my_exact_match_exclude/_doc/3
    {
      "buyer": "Greater London"
    }
    
    POST my_exact_match_exclude/_doc/4
    {
      "buyer": "London Authority"
    }
    
    POST my_exact_match_exclude/_doc/5
    {
      "buyer": "greater london authority (GLA)"
    }
    

    请注意,如果考虑不区分大小写,第一个文档和最后一个文档完全相同。

    示例查询:

    POST my_exact_match_exclude/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "buyer": "Greater London Authority (GLA)"
              }
            }
          ],
          "must_not": [
            {
              "term": {
                "buyer.keyword": "Greater London Authority (GLA)".         
              }
            }
          ]
        }
      }
    }
    

    请注意,我在 buyer.keyword 字段上应用 must_not 以避免所有完全匹配的术语。

    示例响应:

    {
      "took" : 0,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 3,
          "relation" : "eq"
        },
        "max_score" : 0.66237557,
        "hits" : [
          {
            "_index" : "my_exact_match_exclude",
            "_type" : "_doc",
            "_id" : "2",
            "_score" : 0.66237557,
            "_source" : {
              "buyer" : "Greater London Authority"
            }
          },
          {
            "_index" : "my_exact_match_exclude",
            "_type" : "_doc",
            "_id" : "3",
            "_score" : 0.4338556,
            "_source" : {
              "buyer" : "Greater London"
            }
          },
          {
            "_index" : "my_exact_match_exclude",
            "_type" : "_doc",
            "_id" : "4",
            "_score" : 0.4338556,
            "_source" : {
              "buyer" : "London Authority"
            }
          }
        ]
      }
    }
    

    正如预期的那样,文档 1 和 5 不会返回,因为它们是完全匹配的。

    您可以继续在您的代码中以类似的方式使用上述查询。

    希望这会有所帮助!

    【讨论】:

    • 以上有帮助吗?我想没有其他直接的方法。另一种替代方法是在服务层中获取结果并相应地过滤这些文档,然后再将其进一步发送到任何服务/UI 层/数据管道。
    猜你喜欢
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-10
    • 2021-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多