Elasticsearch:使用 distance feature 查询提高分数

Posted Elastic 中国社区官方博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Elasticsearch:使用 distance feature 查询提高分数相关的知识,希望对你有一定的参考价值。

Elasticsearch 有一些专门用于提供专门功能的高级查询。 例如,使用 distance_feature 查询提高在指定位置提供冷饮的咖啡馆的分数 —— 本文的主题。

在搜索经典文学时,我们可能想添加一个子句来查找 1813 年出版的书籍。随着返回所有文学经典书籍,我们可以期望找到傲慢与偏见(简·奥斯汀的经典),但是想法是把傲慢与偏见排在榜首,因为它是 1813 年印刷的。排在榜首无非是提高了基于特定子句的查询结果的相关性得分; 在这种情况下,我们特别希望 1813 年出版的书籍具有更高的重要性。

通过使用 distance_feature 查询,可以在 Elasticsearch 中使用此类功能。 查询获取结果,如果它们更接近起始日期(在本例中为 1813),则用较高的相关性分数标记其中的一些结果。

distance_feature 查询也为位置提供类似的支持。 如果我们愿意,我们可以突出显示靠近特定地址的位置,并将其提升到列表的顶部。 假设我们要查找所有供应炸鱼和薯条的餐厅,但排在首位的餐厅应该位于伦敦桥附近的 Borough Market。 

我们可以对此类用例使用 distance_feature 查询,该查询用于查找更接近原始位置或日期的结果。 日期和位置分别是声明为日期(我们也可以将其声明为 date_nanos)和 geo_point 数据类型的字段。 更接近给定日期或给定位置的结果在相关性得分中被评为更高。 让我们看几个例子来详细理解这个概念。

使用地理位置提高附近大学的分数

在寻找英国的大学时,我们希望优先选择离某个地方较近的大学; 例如,Knightsbridge 10 公里半径范围内的所有大学。 我们需要提高这些匹配的比分。

为了尝试这种情况,让我们为 universities 索引创建一个映射,并将位置声明为 geo_point 字段。 以下列表为四所大学创建映射和索引:两所在伦敦,两所在该国其他地方。

# Create a mapping of universities index with bare minimum fields
PUT universities

  "mappings": 
    "properties": 
      "name":
        "type": "text"
      ,
      "location":
        "type": "geo_point"
      
    
  

我们使用如下的命令来写入一些文档:

POST _bulk
 "index" :  "_index" : "universities", "_id" : "1"  
 "name" : "London School of Economics (LSE)", "location":[0.1165, 51.5144]
 "index" :  "_index" : "universities", "_id" : "2"  
 "name" : "Imperial College London", "location":[0.1749, 51.4988]
 "index" :  "_index" : "universities", "_id" : "3"  
 "name" : "University of Oxford", "location":[1.2544, 51.7548]
 "index" :  "_index" : "universities", "_id" : "4"  
 "name" : "University of Cambridge", "location":[0.1132, 52.2054]

现在已经准备好索引和数据,让我们获取大学,提高相关性分数,使靠近伦敦桥(London Bridge)的大学位于列表的顶部。 请参见如下图中的伦敦地图,其中包含这些大学在上述地点附近的大致距离。 为此,我们使用 distance_feature 查询,它与查询条件匹配,但会根据查询中提供的附加参数提高相关性分数。

我们想搜索位于伦敦大桥位置 [-0.0860, 51.5048]  附近的所有大学。

首先,让我们编写查询,然后深入了解细节。 以下清单在 bool 查询中使用 distance_feature 查询来获取大学。

GET universities/_search?filter_path=**.hits

  "query": 
    "distance_feature": 
      "field": "location",
      "origin": [
        -0.086,
        51.5048
      ],
      "pivot": "10 km"
    
  

上述命令返回结果:


  "hits": 
    "hits": [
      
        "_index": "universities",
        "_id": "1",
        "_score": 0.4157174,
        "_source": 
          "name": "London School of Economics (LSE)",
          "location": [
            0.1165,
            51.5144
          ]
        
      ,
      
        "_index": "universities",
        "_id": "2",
        "_score": 0.3562365,
        "_source": 
          "name": "Imperial College London",
          "location": [
            0.1749,
            51.4988
          ]
        
      ,
      
        "_index": "universities",
        "_id": "4",
        "_score": 0.11223929,
        "_source": 
          "name": "University of Cambridge",
          "location": [
            0.1132,
            52.2054
          ]
        
      ,
      
        "_index": "universities",
        "_id": "3",
        "_score": 0.09380584,
        "_source": 
          "name": "University of Oxford",
          "location": [
            1.2544,
            51.7548
          ]
        
      
    ]
  

查询在执行时搜索所有返回我们四所大学。 此外,如果这些大学中的任何一所大学位于原点周围 10 公里附近(-0.0860,51.5048 代表英国的 London Bridge),它们的得分就会高于其他大学。

让我们暂停一下,看看 distance_feature 查询是由什么组成的。 distance_feature 查询需要这些属性:

  • field - 文档中的 geo_point 字段
  • origin — 测量距离的焦点(经度和纬度)
  • pivot - 距焦点的距离

在上面的查询中,伦敦经济学院(LSE)大学比帝国理工学院更接近伦敦桥; 因此,LSE 以更高的分数返回顶部。

我们也可以使用带有日期的 distance_feature 查询,下一节的主题。

使用日期提高分数

在上一节中,distance_feature 查询帮助我们搜索大学,提高了离特定地理位置较近的大学的分数。 distance_feature 查询也可以满足类似的要求:如果结果围绕日期旋转,则提高结果的分数。

假设我们要搜索所有 iPhone 的发布日期,将 2020 年 12 月 1 日前后 30 天内发布的 iPhone 列在列表的首位(没有特别的原因,除了尝试这个概念)。 我们可以编写与上一节中类似的查询,但字段属性将基于日期。 让我们首先创建一个 iphones 映射并将一些 iPhone 索引到我们的索引中。 下面清单中的查询就是这样做的。

PUT iphones

  "mappings": 
    "properties": 
      "name":
        "type": "text"
      ,
      "release_date":
        "type": "date",
        "format": "dd-MM-yyyy"
      
    
  

我们使用如下的 bulk 命令一次写入四个文档:

POST _bulk
 "index" :  "_index" : "iphones", "_id" : "1"  
 "name" : "iPhone", "release_date":"29-06-2007"
 "index" :  "_index" : "iphones", "_id" : "2"  
 "name" : "iPhone 12", "release_date":"23-10-2020"
 "index" :  "_index" : "iphones", "_id" : "3"  
 "name" : "iPhone 13", "release_date":"24-09-2021"
 "index" :  "_index" : "iphones", "_id" : "4"  
 "name" : "iPhone 12 Mini", "release_date":"13-11-2020"

我们可以在 Kibana 中进行时域展示:

现在我们有了一个包含一堆 iphones 的索引,让我们开发一个查询来满足我们的要求:我们将获取所有 iPhone,但优先考虑在 2020 年 12 月 1 日前后 30 天发布的 iPhone。下一个清单中的查询做这个。

GET iphones/_search?filter_path=**.hits

  "query": 
    "bool": 
      "must": [
        
          "match": 
            "name": "12"
          
        
      ],
      "should": [
        
          "distance_feature": 
            "field": "release_date", 
            "origin": "01-12-2020", 
            "pivot": "30 d" 
          
        
      ]
    
  

上述搜索的结果为:


  "hits": 
    "hits": [
      
        "_index": "iphones",
        "_id": "4",
        "_score": 1.1876879,
        "_source": 
          "name": "iPhone 12 Mini",
          "release_date": "13-11-2020"
        
      ,
      
        "_index": "iphones",
        "_id": "2",
        "_score": 1.1217185,
        "_source": 
          "name": "iPhone 12",
          "release_date": "23-10-2020"
        
      
    ]
  

 

在上面的查询中,我们将 distance_feature 包装在一个带有 must 和 should 子句的 bool 查询中(我们在之前的文章中了解了 bool 查询)。 must 子句搜索名称字段中包含 12 的所有文档,并从我们的索引中返回 iPhone 12 和 iPhone 12 mini 文档。 我们的要求是优先考虑 12 月 1 日前后 30 天发布的手机(因此,可能是 2020 年 11 月至 12 月之间发布的所有手机)。

为了满足这个要求,should 子句使用 distance_feature 查询来提高最接近所提到的旋转日期的匹配文档的分数。 该查询从 iphones 索引中获取所有文档。 在 2020 年 12 月 1 日(原点)之前或之后 30 天发布的任何 iPhone 都会返回具有更高相关性分数的产品。

请记住,should 子句返回的所有匹配项都将添加到总分中。 因此,你应该会看到 iPhone 12 Mini 位居榜首,因为这款 iPhone 的发布日期(“release_date”:“13–11–2020”)更接近 pivot 日期(“origin”:“01–12–2020”) 30天)。

如你所见,iPhone 12 Mini 的得分高于 iPhone 12,因为它仅在我们的基准日期前 17 天发布,而 iPhone 12 的发布时间稍早于此(将近 5 周前)。

以上是关于Elasticsearch:使用 distance feature 查询提高分数的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch:使用 distance feature 查询提高分数

elasticsearch Geo Distance Query

Elasticsearch:Rank feature query

如何使用 Oracle 的 sdo_distance

MySQL 函数 ST_Distance_Sphere 没有使用 Haversine 公式?

PostGIS ST_Distance_Spheroid 或 Haversine