2023-09-12 - 7 搜索排序

news2024/10/7 10:24:38

1 查询时设置权重

用户可以使用布尔查询将多种查询组合在一起。在默认情况下,这些查询的权重都为1,也就是查询之间都是平等的。有时我们希望某些查询的权重高一些,也就是在其他条件相同的情况下,匹配该查询的文档得分更高。此时应该怎么做呢?本节将介绍的boosting查询和boost设置可以满足上述查询需求。

1.1 查询时boost参数的设置

在ES中可以通过查询的boost值对某个查询设定其权重。在默认情况下,所有查询的boost值为1。但是当设置某个查询的boost为2时,不代表匹配该查询的文档评分是原来的2倍,而是代表匹配该查询的文档得分相对于其他文档得分被提升了。例如,可以为查询A设定boost值为3,为查询B设定boost值为6,则在进行相关性计算时,查询B的权重将比查询A相对更高一些。

boost值的设置只限定在term查询和类match查询中,其他类型的查询不能使用boost设置。boost值没有特别约束,因为它代表的是一个相对值。当该值在0~1时表示对权重起负向作用,当该值大于1时表示对权重起正向作用。为方便演示,下面先创建索引:

PUT /hotel 
{ 
  "settings": { 
    "number_of_shards": 1 
  },  
 "mappings": {                           //定义字段 
    "properties": { 
      "title": { 
        "type": "text" 
      }, 
      "price": { 
        "type": "double" 
      }, 
      "full_room": { 
        "type": "boolean" 
      } 
    } 
  } 
} 

在上面的DSL中设定了索引的主分片数为1,这是为了方便计算文本的IDF值,现在向索引中写入数据:

POST /_bulk 
{"index":{"_index":"hotel","_id":"001"}} 
{"title": "文雅酒假日酒店","price": 556.00,"full_room":false} 
{"index":{"_index":"hotel","_id":"002"}} 
{"title": "金都嘉怡假日酒店","price": 337.00,"full_room":true} 
{"index":{"_index":"hotel","_id":"003"}} 
{"title": "金都欣欣酒店","price": 200.00,"full_room":true} 
{"index":{"_index":"hotel","_id":"004"}} 
{"title": "金都家至酒店","price": 500.00,"full_room":false} 
{"index":{"_index":"hotel","_id":"005"}} 
{"title": "文雅精选酒店","price": 800.00,"full_room":true}  

下面对索引进行查询,假设“金都”或者“文雅”是两个酒店的品牌,用户想查询标题中包含“金都”或者“文雅”的酒店文档:

GET /hotel/_search 
{ 
  "query": { 
    "bool": { 
      "should": [ 
        { 
          "match": {                   //查询标题匹配“金都”的文档 
            "title":{ 
              "query": "金都" 
            } 
          } 
        }, 
        { 
          "match": {                  //查询标题匹配“文雅”的文档 
            "title":{ 
              "query": "文雅" 
            } 
          } 
        } 
      ] 
    } 
  } 
} 

在默认情况下,各个子查询的boost值为1,也就是说上述的两个match查询是平等的。文档的分值等于两个match相关性分数之和。执行上述DSL后结果如下:

{"hits" : {"hits" : [                     //匹配的文档列表 
      {"_id" : "005", 
        "_score" : 1.7743526, 
        "_source" : { 
          "title" : "文雅精选酒店",} 
      },
      {"_id" : "001", 
        "_score" : 1.6631467, 
        "_source" : { 
          "title" : "文雅酒假日酒店",} 
      }, 
      {"_id" : "002", 
        "_score" : 1.0924089, 
        "_source" : { 
          "title" : "金都嘉怡酒店",} 
      }, 
      {"_id" : "003", 
        "_score" : 1.0924089, 
        "_source" : { 
          "title" : "金都欣欣酒店",} 
      }, 
      {"_id" : "004", 
        "_score" : 1.0924089, 
        "_source" : { 
          "title" : "金都家至酒店",} 
      } 
    ] 
  } 
}  

通过上述结果可以看到,“金都”品牌的酒店文档的打分相对低一些,如果想对“金都”品牌的酒店进行推广,也就是提升标题中包含“金都”这些文档的排序分值,则可以设定“金都”的match查询的boost值更高一些,例如下面的DSL:

GET /hotel/_search 
{ 
  "query": { 
    "bool": { 
      "should": [ 
        { 
          "match": { 
            "title":{ 
              "query": "金都", 
             "boost": 2                  //设置“金都”匹配的权重更高一些 
            } 
          } 
        }, 
        { 
          "match": { 
            "title":{ 
              "query": "文雅" 
            } 
          } 
        } 
      ] 
    } 
  } 
}

执行上述DSL后,ES的返回结果如下:

{"hits" : {"hits" : [                         //匹配的文档列表 
      {"_id" : "002", 
        "_score" : 2.1848178, 
        "_source" : { 
          "title" : "金都嘉怡酒店",} 
      }, 
      {"_id" : "003", 
        "_score" : 2.1848178, 
        "_source" : { 
          "title" : "金都欣欣酒店",} 
      }, 
      { 
        "_index" : "hotel", 
        "_type" : "_doc", 
        "_id" : "004", 
        "_score" : 2.1848178, 
        "_source" : { 
          "title" : "金都家至酒店",} 
      }, 
      {"_id" : "005", 
        "_score" : 1.7743526, 
        "_source" : { 
          "title" : "文雅精选酒店",} 
      }, 
      {"_id" : "001", 
        "_score" : 1.6631467, 
        "_source" : { 
          "title" : "文雅酒假日酒店",} 
      } 
    ] 
  } 
} 

如上所示,设定的boost值提升了标题中包含“金都”的文档的得分。现在我们来思考一下上述match查询的打分细节,在默认情况下,文档的boost为BM25中的k1+1,因为在默认情况下k1=1.2,所以boost=k1+1=1.2+1=2.2。当在match查询中设置boost为2时,匹配该查询文档的最终boost=(k1+1)×2=(1.2+1)×2=4.4。

title字段使用标准分析器,设置“金都”这个match查询的boost值为2后,在查询时“金都”被切分成“金”“都”,这两个切分的字在BM25查询中的最终boost值都为4.4。

因此设置match查询的boost参数可以直接影响BM25的评分机制,从而影响整体结果的相关度。更近一步说,设置boost参数为某个值后并不是将查询命中的文档分数乘以该值,而是将BM25中的boost参数乘以该数值。

在Java客户端中使用boost参数时,只需要在QueryBuilder实例中调用boost()方法即可,以下Java代码和上面的DSL在搜索结果上是等效的:

public void getBoostSearch() { 
    //创建搜索请求 
    SearchRequest searchRequest = new SearchRequest("hotel"); 
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(
    //构建“金都”的match查询 
    MatchQueryBuilder matchQueryBuilder1 = QueryBuilders.matchQuery 
("title", "金都"); 
    //设置boost值为2 
    matchQueryBuilder1.boost(2); 
    //构建“文雅”的match查询,boost使用默认值 
    MatchQueryBuilder matchQueryBuilder2 = QueryBuilders.matchQuery 
("title", "文雅"); 
    BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery(); 
    //将“金都”的match查询添加到布尔查询中 
    boolQueryBuilder.should(matchQueryBuilder1); 
    //将“文雅”的match查询添加到布尔查询中 
    boolQueryBuilder.should(matchQueryBuilder2); 
    searchSourceBuilder.query(boolQueryBuilder); //设置查询为布尔查询 
    searchRequest.source(searchSourceBuilder);   //设置查询请求 
   printResult(searchRequest);                   //打印搜索结果 
} 

1.2 boosting查询

虽然使用boost值可以对查询的权重进行调整,但是仅限于term查询和类match查询。有时需要调整更多类型的查询,如搜索酒店时,需要将房价低于200的酒店权重降低,此时可能需要用到range查询,但是range查询不能使用boost参数,这时可以使用ES的boosting查询进行封装

ES的boosting查询分为两部分,一部分是positive查询,代表正向查询,另一部分是negative查询,代表负向查询。可以通过negative_boost参数设置负向查询的权重系数,该值的范围为0~1。最终的文档得分为:正向匹配值+负向匹配值×negative_boost。先来看看使用原始查询时的搜索排序状态,以下DSL为搜索“金都”查询:

GET /hotel/_search 
{ 
 "query": {                //普通的match搜索 
    "match": { 
      "title": "金都" 
    } 
  } 
}  

搜索结果如下:

{"hits" : {"max_score" : 1.0924089, 
   "hits" : [               //匹配的文档列表  
      {"_id" : "002", 
        "_score" : 1.0924089, 
        "_source" : { 
          "title" : "金都嘉怡酒店", 
          "price" : 337.0, 
          "full_room" : true 
        } 
      }, 
      {"_id" : "003", 
        "_score" : 1.0924089, 
        "_source" : { 
          "title" : "金都欣欣酒店", 
          "price" : 200.0, 
          "full_room" : true 
        } 
      }, 
      {"_id" : "004", 
        "_score" : 1.0924089, 
        "_source" : { 
          "title" : "金都家至酒店", 
          "price" : 500.0, 
          "full_room" : false 
        } 
      } 
    ] 
  } 
} 

可以看到,上面的搜索结果只是按照标题相关度进行了打分,其中,标价为200元的“金都欣欣酒店”排在第二位,如果希望它排在最后该怎么做呢?下面的DSL将对房价低于200元的酒店进行降权处理:

GET /hotel/_search 
{ 
  "query": { 
    "boosting": { 
      "positive": { 
        "match": { 
          "title": { 
            "query": "金都" 
          } 
        } 
      }, 
      "negative": {            //设置负面查询 
        "range": { 
          "price": { 
            "lte": 200 
          } 
        } 
      }, 
      "negative_boost": 0.2   //设置降低的权重值 
    } 
  } 
}   

执行上述DSL后,ES搜索结果如下:

{"hits" : { 
    "total" : { 
      "value" : 3, 
      "relation" : "eq" 
    }, 
    "max_score" : 1.0924089, 
   "hits" : [                  //匹配的文档列表 
      {"_id" : "002", 
        "_score" : 1.0924089, 
        "_source" : { 
          "title" : "金都嘉怡酒店", 
          "price" : 337.0, 
          "full_room" : true 
        } 
      }, 
      {"_id" : "004", 
        "_score" : 1.0924089, 
        "_source" : { 
          "title" : "金都家至酒店", 
          "price" : 500.0, 
          "full_room" : false 
        } 
      }, 
      {"_id" : "003", 
        "_score" : 0.21848178, 
        "_source" : { 
          "title" : "金都欣欣酒店", 
          "price" : 200.0, 
          "full_room" : true 
        } 
      } 
    ] 
  } 
} 

通过上面的结果可知,对房价低于200元的酒店进行降权处理后,目标酒店已经排在了最后面。

如果在以上结果基础上要求降低满房酒店的权重该怎么做呢?我们可以将在negative中的查询进行扩展:

GET /hotel/_search 
{ 
  "query": { 
    "boosting": { 
      "positive": { 
        "match": { 
          "title": { 
            "query": "金都" 
          } 
        } 
      }, 
      "negative": {               //扩展negative查询,增加更多条件 
        "bool": { 
          "should": [ 
            { 
              "range": { 
                "price": { 
                  "lte": 200 
                } 
              } 
            }, 
            { 
              "term": { 
                "": { 
                  "value": "true" 
                } 
              } 
            } 
          ] 
        } 
      }, 
      "negative_boost": 0.2 
    } 
  } 
}  

在以上查询中,使用布尔查询将“房价低于200元”和“满房状态”的酒店封装到了一个布尔查询中然后放入negative查询中,执行上述DSL后,搜索结果如下:

{"hits" : {"hits" : [                     //匹配的文档列表 
 
 
      {"_id" : "004", 
        "_score" : 1.0924089, 
        "_source" : { 
          "title" : "金都家至酒店", 
          "price" : 500.0, 
          "full_room" : false 
        } 
      }, 
      {"_id" : "002", 
        "_score" : 0.21848178, 
        "_source" : { 
          "title" : "金都嘉怡酒店", 
          "price" : 337.0, 
          "full_room" : true 
        } 
      }, 
      {"_id" : "003", 
        "_score" : 0.21848178, 
        "_source" : { 
          "title" : "金都欣欣酒店", 
          "price" : 200.0, 
          "full_room" : true 
        } 
      } 
    ] 
  } 
}

如上所示,通过使用negative进行调权,“房价低于200元”和“满房状态”的酒店都排在了后面。

在Java客户端中使用boosting查询:

public void getBoostingSearch() { 
    //创建搜索请求 
    SearchRequest searchRequest = new SearchRequest("hotel"); 
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
    //构建“金都”的match查询 
    MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery 
("title", "金都"); 
    //构建价格的range查询 
    QueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price"). 
lte("200"); 
    //构建满房的term查询 
    QueryBuilder termQueryBuilder = QueryBuilders.termQuery("full_room", 
true); 
    BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery(); 
    //将价格的range查询添加到布尔查询中 
    boolQueryBuilder.should(rangeQueryBuilder); 
    //将满房的term查询添加到布尔查询中 
    boolQueryBuilder.should(termQueryBuilder); 
    //构建boosting查询,将match查询作为正向查询,布尔查询作为负向查询 
    BoostingQueryBuilder boosting=QueryBuilders.boostingQuery(matchQuery 
Builder,boolQueryBuilder); 
    boosting.negativeBoost(0.2f);              //设置负向查询的权重系数 
    searchSourceBuilder.query(boosting);       //设置查询为boosting查询 
    searchRequest.source(searchSourceBuilder); //设置查询请求 
   printResult(searchRequest);                 //打印搜索结果 
} 

2 Function Score查询简介

例如,一个酒店搜索引擎,不仅需要考虑查询词和酒店名称的匹配程度,而且还需要评估酒店的好评率、地理位置和设施服务等诸多因素。ES提供了Function Score查询模式,用户可以借助该查询模式使用多种因素来影响打分逻辑。

2.1 简单函数

我们在第4章中简要介绍了在Function Score查询中可以使用random_score随机函数对文档进行打分,在Function Score查询中还提供了其他打分函数,如表6.1所示。
在这里插入图片描述
在这些函数中,比较灵活的是script_score函数,它支持用户使用脚本自定义评分函数。在函数体中,既可以使用原有的score值进行计算,也可以使用文档的某个字段值的一些运算结果来影响评分的值。下面使用script_score函数将原有评分和好评数相乘的结果作为最后的评分,示例如下:

GET /hotel/_search 
{ 
  "query": { 
    "function_score": {  
      "query": {               //定义查询条件 
        "match_all": {}        //匹配所有文档 
      }, 
      "functions": [           //可以定义多个打分函数 
        {  
          "script_score": {    //使用脚本打分 
            "script": "_score * doc[' favourable_comment'].value" 
          } 
        } 
      ] 
    } 
  } 
} 

需要注意的是,script_score子句中的结果必须大于或者等于0,不能为负数,否则,ES将会报错。以下是script_score取值为原有评分和差评数的乘积再乘以-1的查询示例:

GET /hotel/_search 
{ 
  "query": { 
    "function_score": { 
      "query": { 
        "match_all": {}     //匹配所有文档 
      }, 
      "functions": [ 
        { 
          "script_score": { 
            //乘以-1使得分为负数 
            "script": "_score * -1*doc['negative_comment'].value" 
          } 
        } 
      ] 
    } 
  } 
} 

系统报错信息如下:

{ 
  "error" : { 
    "root_cause" : [ 
     {                        //打分函数返回负数时ES报错 
        "type" : "illegal_argument_exception", 
        "reason" : "script score function must not produce negative scores,
but got: [-10.0]" 
      } 
    ], 
    "type" : "search_phase_execution_exception",}, 
 "status" : 400               //返回的状态码 
} 

另外,还可以使用params为script_score传递参数。在下面的示例中,将原有评分和评论进行相乘,然后乘以p,并将得到的结果作为最后的评分。其中,p的值是通过params中的传递参数得到的。

GET /hotel/_search 
{ 
  "query": { 
    "function_score": { 
      "query": { 
        "match_all": {}           //匹配所有文档 
      }, 
      "functions": [ 
        { 
          "script_score": { 
            "script": { 
              "params": {        //传递p参数的值为0.5 
                "p": 0.5 
              }, 
               //在打分函数的计算中使用p参数 
              "source": "_score*doc['favourable_comment'].value*params.p" 
            } 
          } 
        } 
      ] 
    } 
  } 
} 

weight函数提供的是一个系数,最终的得分等于对原有评分乘以这个系数。例如,对命中的文档原有评分乘以10:

GET /hotel/_search 
{ 
  "query": { 
    "function_score": { 
      "query": { 
        "match_all": {}            //匹配所有文档 
      }, 
      "functions": [ 
        {                          //定义weight函数 
          "weight": 10             //定义weight函数中的权重值 
        } 
      ] 
    } 
 } 
} 

random_score产生0~1的随机小数,但是不包括1。在默认情况下,该随机函数使用的随机种子为文档_id,可以通过seed参数指定随机数种子。例如,使用随机函数的简单形式对文档打分:

GET /hotel/_search 
{ 
  "query": { 
    "function_score": { 
      "query": { 
        "match_all": {}         //匹配所有文档 
      }, 
      "functions": [ 
        { 
          "random_score": {}    //使用随机函数打分 
        } 
      ] 
    } 
  } 
}

如果希望文档中的某些字段对排序产生影响,除了使用script_score函数以外,也可以使用字段值因子函数field_value_factor,该函数可以省去编写脚本代码的麻烦。在下面的例子中以原有评分和好评数相乘的结果作为最后的评分:

GET /hotel/_search 
{ 
  "query": { 
    "function_score": { 
      "query": { 
        "match_all": {}                //匹配所有文档 
      }, 
      "functions": [ 
        { 
          "field_value_factor": { 
            //定义field_value_factor中的field参数为字段favourable_comment, 则ES将原有分数乘以字段favourable_comment的值作为文档最终得分 
            "field": "favourable_comment" 
          } 
        } 
      ] 
    } 
  } 
}

在field_value_factor中还可以使用函数进一步对字段的因子进行处理。例如使用原有评分和好评数的平方根进行相乘的结果作为最后的评分:

GET /hotel/_search 
{ 
  "query": { 
    "function_score": { 
      "query": { 
        "match_all": {} 
      }, 
      "functions": [ 
        { 
          "field_value_factor": { 
            "field": "favourable_comment", 
            //使用原有评分和好评数的平方根进行相乘的结果作为最后的评分 
            "modifier": "sqrt" 
          } 
        } 
      ] 
    } 
  } 
}

2.2 函数计算关系

如果在Function Score的functions子句中有多个函数,则可以使用score_mode参数定义各个函数值之间的计算关系,当前支持的计算关系如表6.2所示。
在这里插入图片描述
score_mode的默认值为multiply,即最终的分数默认取各个函数的值相乘的结果。在下面的示例中score_mode取各个值的加和值:

GET /hotel/_search 
{ 
  "query": { 
    "function_score": { 
      "query": { 
        "match_all": {} 
      }, 
      "score_mode": "sum",   //设置score_mode为sum,则最终得分取各个值的加和值 
      "functions": [ 
        { 
          "field_value_factor": { 
            "field": "favourable_comment", 
            "modifier": "sqrt" 
          }, 
          "random_score": {} 
        } 
      ] 
    } 
  } 
}

2.3 衰减函数

在对文档进行打分时,希望在某个值域附近进行衰减打分。例如当搜索酒店时,酒店距离当前位置越近越好。假定距离当前位置1km范围内的酒店都可以接受,如果使用过滤器将超过1km的酒店排除掉,这种做法未免有些“生硬”。假设一个酒店距离当前位置刚好是1.1km,其好评度也不错,那么是可以考虑一下该酒店的。所以我们希望酒店最好距离当前位置在1km范围内,如果超过1km,酒店的评分应该随着距离的增大有一个明显的下降趋势。

为了解决这类问题,可以在Function Score查询中使用衰减函数。ES提供了3个衰减函数,分别为gauss、linear和exp,这3个函数的区别主要是衰减曲线形状不同,但是它们的用法和参数设置都是一样的。如图6.4所示为以年龄字段为例展示的这3个函数的衰减曲线图像。
在这里插入图片描述
衰减函数可以用于数值型、日期型和地理位置型数据,需要用户设置一个中心值,如果实际值偏离中心值,无论大于中心值还是小于中心值,文档的分数都将降低。

由图6.4可知,gauss图像有点类似于钟摆,起初,其衰减值随着年龄的增大缓慢增大,然后到达某个区域后急速增大,直到到达某个阈值后又急速减小,最后又缓慢减小;linear的函数曲线是一条直线,其衰减值随着年龄的增大而线性增大,直到到达某个阈值后随着年龄的增大而线性减小;exp是一种指数衰减,它的衰减速率比gauss要激烈一些。

使用衰减函数时,可以设定如下参数:
·origin:用于设定计算距离的原点,该参数的值必须和字段类型相对应。
·offset:用于设定距离原点多远范围内的数据将享有和原点一样的衰减值,其默认值为0。
·scale:衰减曲线的一个锚点,即定义到该点的值,其衰减的值为某个值(即为decay的值)。这个锚点横坐标值的定义为原点+offset+scale,纵坐标为decay参数的值。
·decay:和scale配套使用,用于设定锚点的纵坐标,即衰减值,其默认值为0.5。

下面用一个酒店搜索的实例来介绍衰减函数的使用,先来建立酒店索引:

PUT /hotel 
{ 
  "mappings": { 
    "properties": { 
      "title": {              //定义title字段和类型 
        "type": "text" 
      }, 
      "location": {           //定义location字段和类型 
        "type": "geo_point" 
      } 
    } 
  } 
}

为方便介绍,在索引中写入一些酒店数据,这些酒店都是北京天安门附近的酒店:

POST /_bulk 
{"index":{"_index":"hotel","_id":"001"}} 
{"title": "大前门瀚海酒店","location": {"lat": 39.905194, "lon": 116.400029}} 
{"index":{"_index":"hotel","_id":"002"}} 
{"title": "磁器口美乐酒店","location": {"lat": 39.895314, "lon": 116.426241}} 
{"index":{"_index":"hotel","_id":"003"}} 
{"title": "天坛望都酒店","location": {"lat": 39.88892, "lon": 116.428415}} 
{"index":{"_index":"hotel","_id":"004"}} 
{"title": "南海公园酒店","location": {"lat": 39.918034, "lon": 116.395932}} 
{"index":{"_index":"hotel","_id":"005"}} 
{"title": "国贸天地酒店","location": {"lat": 39.914423, "lon": 116.462227}}

假设当前位置是天安门,经纬度坐标为[116.4039,39.915143],需求为搜索附近5km内的酒店,其中最佳距离是1km,超过1km的酒店打分需要按照距离进行衰减,其中3km的时候酒店衰减得分为0.4,则搜索的DSL如下:

GET /hotel/_search 
{ 
  "query": { 
    "function_score": { 
      "query": {                     //设置搜索范围为距离中心点5km 
        "geo_distance":{ 
          "distance":"5km", 
          "location":{ "lat": 39.915143, "lon": 116.4039 } 
        } 
      },  
      "functions": [ 
        { 
          "gauss": {                //设置衰减函数为gauss 
            "location": {  
              "origin": { "lat": 39.915143, "lon": 116.4039 }, 
              //最佳距离为1km,在1km范围内的所有酒店得分均相同 
              "offset": "1km", 
              "scale":  "2km",      //设定固定的衰减距离 
              "decay": 0.4          //设置距离中心点3km时的衰减得分为0.4 
            }        
          } 
        } 
      ] 
    } 
  } 
}

执行上述DSL,搜索结果如下:

{"hits" : {"hits" : [                          //返回的文档列表 
      {"_id" : "004", 
        "_score" : 1.0, 
        "_source" : {"title" : "南海公园酒店","location" : {}} 
      }, 
      {"_id" : "001", 
        "_score" : 0.99454683, 
        "_source" : {"title" : "大前门瀚海酒店","location" : {}} 
      }, 
      {"_id" : "002", 
        "_score" : 0.43195635, 
        "_source" : {"title" : "磁器口美乐酒店","location" : {}} 
      }, 
      {"_id" : "003", 
        "_score" : 0.21555501, 
        "_source" : {"title" : "天坛望都酒店","location" : {}}}, 
      {"_id" : "005", 
        "_score" : 0.026788887, 
        "_source" : {"title" : "国贸天地酒店","location" : {}} 
      } 
    ] 
  } 
}

通过以上结果大体上可以看出一些规律:距离天安门越近的酒店得分越高,反之则得分越低。为了能直观地看到更细粒度的结果,需要给出实际距离,因此我们使用普通的距离查询,并且将查询结果直接按照距离降序排列:

GET /hotel/_search 
{ 
  "query": { 
   "geo_distance": {                       //在距离中心点5km范围内搜索酒店 
      "distance": "5km", 
      "location": { 
        "lat": 39.915143, 
        "lon": 116.4039 
      } 
    } 
  }, 
  "sort": [ 
    { 
      "_geo_distance": {                  //按照与中心点的距离进行排序 
        "location": { 
          "lat": 39.915143, 
          "lon": 116.4039 
        }, 
        "unit": "km",                    //排序使用的距离计量单位 
        "order": "asc"                   //升序排列 
      } 
    } 
  ] 
}

执行上述DSL,ES的返回结果如下:

{"hits":{"hits":[                            //返回的文档列表 
            {"_id":"004", 
                "_score":null, 
                "_source":{"title":"南海公园酒店","location":{}}, 
                "sort":[0.7517456062542669] //文档的排序值:酒店与中心点的距离 
            }, 
            {"_id":"001", 
                "_score":null, 
                "_source":{ "title":"大前门瀚海酒店","location":{}}, 
                "sort":[1.154501237598761]   //文档的排序值:酒店与中心点的距离 
            }, 
            { 
                "_index":"hotel", 
                "_type":"_doc", 
                "_id":"002", 
                "_score":null, 
                "_source":{"title":"磁器口美乐酒店","location":{}}, 
                "sort":[2.91428143818939]  //文档的排序值:酒店与中心点的距离 
            }, 
            {"_id":"003", 
                "_score":null, 
                "_source":{"title":"天坛望都酒店","location":{}}, 
                "sort":[3.5882267893003497]   //文档的排序值:酒店与中心点的距离 
            }, 
            {"_id":"005", 
                "_score":null, 
                "_source":{"title":"国贸天地酒店","location":{}}, 
                "sort":[4.975151875412991]   //文档的排序值:酒店与中心点的距离 
            } 
        ] 
    } 
}

将上面的两个结果结合起来看,南海公园酒店距离天安门小于1km范围内,符合offset值的设定,因此其得分为1;大前门瀚海酒店距离天安门在1km和2km之间,并且非常接近1km,因此其得分虽然得到衰减,但只是轻微衰减到0.99左右;磁器口美乐酒店距离天安门2.91km,该值已经非常接近锚点值,因此其得分为0.43左右,更加接近decay的值(其值为0.4);天坛望都酒店和天安门的距离为3.5km,已经超过3km,因此其得分迅速衰减到0.22左右;最后的国贸天地酒店,它和天安门的距离已经接近5km,因此其得分急速衰减到0.03左右。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1003124.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高忆管理:震仓什么意思?

震仓是股市、期货商场和商业运营中常见的一个概念。它的本意是指在生意中许多生意同一种证券或产品,然后引起商场的震荡。在详细的情境中,震仓有许多不同的意义。本文将从股市、期货商场和商业运营三个角度解析震仓的意义和效果。 一、股市中的震仓 在股…

RK3568开发笔记(八):开发板烧写buildroot固件(支持hdmi屏),搭建Qt交叉编译开发环境,编译一个Demo,目标板运行Demo测试

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/132826197 红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

Map和Set及其实现类详解

目录 一, 搜索 1,传统搜索 2,Map和Set模型 二, Map的使用 1,Map接口的继承及实现图 2,Map接口的使用 3,TreeMap和HashMap的使用和对比 1,TreeMap 代码示例 map中插入的数据按照key进行排序 map中插入的数据必须具有可比较性(或者实现了比较器相关接口) ​map中插入…

鸿蒙应用开发(基础篇)之列表组件

一、简介 在我们常用的手机应用中,经常会见到一些数据列表,如设置页面、通讯录、商品列表等。下图中两个页面都包含列表,“首页”页面中包含两个网格布局,“商城”页面中包含一个商品列表。 上图中的列表中都包含一系列相同宽度的…

XShell7 + Xftp7 + IDEA 打包MapReduce程序到集群运行

参考博客 【MapReduce打包成jar上传到集群运行】http://t.csdn.cn/2gK1d 【Xshell7/Xftp7 解决强制更新问题】http://t.csdn.cn/rxiBG IDEA打包MapReduce程序 这里的打包是打包整个项目,后期等学会怎么打包单个指定的mapreduce程序再来更新博客。 1、编译打包 …

MATLAB入门-程序控制结构

MATLAB入门-程序控制结构 注:本篇文章为课程学习笔记,课程链接为:头歌 if、elseif、else 相比于C语言,这里多了一个end switch、case、otherwise 相比于C语言,这里也多了一个end,默认字符也不一样。 …

智慧公厕建设,要以技术为支撑、体验为目的、业务为驱动

#智慧公厕[话题]# #智慧公厕系统[话题]# #智慧公厕厂家[话题]# #智慧公厕驿站[话题]# 在数字化城市与智慧城市的大力推进下,作为社会重要的生活设施,智慧化的公共厕所的建设变得越来越重要。作为城市的基础部件之一,公厕的智慧化建设需要进行…

实例 | Python 实现 RSA 加解密

大家好,欢迎来到编程教室 ! 前阵子看到一篇英文文章[1],展示了如何用 Python 来实现 RSA 算法。不太熟悉 RSA 的朋友可以看一下一文搞懂 RSA 算法,里面对什么是 RSA,RSA 的数学原理进行了说明,并举了一个简…

平板用的触控笔什么牌子好?开学便宜电容笔推荐

在新学期即将来临之际,你觉得什么样的电容笔才是最好的选择呢?我是一个数码爱好者,有几年以上的使用经验,也知道一些关于电容笔的事情。我觉得,这款苹果原装的电容笔,与普通的电容笔最大的不同之处&#xf…

手把手教你,如何先梳理业务逻辑再写代码

1.业务逻辑与代码 代码是需求逻辑的一种展现形式 需求文档是业务逻辑的一种展现形式,而代码不过是业务逻辑的另一种表现形式;如果逻辑本身有问题,那么它的各种展示形式自然也是错的,所以写代码前应该先思考清楚业务逻辑。 Revi…

【校招VIP】专业课考点之网络存储

考点介绍: cookie、session和localstorage 是目前常用的存储机制,不管是大厂还是中小公司,都会对这个问题有比较高的考察频度,而且有一定的深度和对比分析 专业课考点之网络存储-相关题目及解析内容可点击文章末尾链接查看&#…

为什么C ++在嵌入式系统设计中是C的可行替代品

你是一名。你知道C是适合该工作的语言,尽管有时维护周期可以重复很长时间。有时你会感到that琐,就像在编码自动机一样,反复在结构上创建基本迭代,这些结构与上周或上个月的结构非常相似。 你已经听说过C 作为一种功能强大的语言的…

【AI绘画接口】Midjourney是什么?Midjourney有官方接口吗?

什么是 Midjourney? 随着AI技术的发展,AI聊天、AI绘画都从小众尝鲜逐渐应用到了生产当中。现在市面上的绘画AI并不少,而 Midjourney 是其中最好用的之一。我们只需要输入一些提示词,Midjourney 就能根据输入的提示词自动生成符合…

怎么找回回收站删除的文件?轻松恢复数据,就看这3个方法!

“求助求助!回收站删除的文件还有找回来的机会吗?一不小心就把回收站中的文件删除了,现在不知道该如何是好了,希望热心的网友们可以帮帮我!” 大家都知道,电脑有一个功能叫回收站,系统会将我们删…

代码随想录 -- day49 -- 121. 买卖股票的最佳时机 、122.买卖股票的最佳时机II

121. 买卖股票的最佳时机 动态规划: dp[i][0] 表示第i天持有股票所得最多现金,dp[i][0] 表示第i天持有股票所得最多现金。 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0]第…

echarts折线图每段显示不同的颜色

效果图 配置项: zqChartFour: {title: {text: "一天用电量分布",subtext: "纯属虚构",},tooltip: {trigger: "axis",axisPointer: {type: "cross",},},toolbox: {show: true,feature: {saveAsImage: {},},},xAxis: {type:…

Linux 中nc指令的使用总结

nc指令概述用法一:端口扫描用法二:命令行中发送和接收数据用法三:建立双方通信 nc指令概述 nc 是 Linux 系统中的 netcat 命令之简称,它是一个强大的网络工具,可以用于创建 TCP/UDP 套接字连接。常见的其用法模板可定…

目标检测中生成锚框函数详解

将设一张图片,宽和高为2,2 X torch.rand(size(1,3,2,2)) Y generate_anchors(X,sizes[0.75,0.5,0.25],ratios[1,2,0.5])锚框中心点的设置 # 为每个像素可以生成 nm-1个锚框,整个图像生成 wh(nm-1) def generate_anchors(data,sizes,ratios): # 书上的…

重磅预告 |第十二届中国智能产业高峰论坛9月16日在昌开幕,集团董事长李火亮任专题联席主席,出席本次活动

在这个数字化、智能化社会经济高速迭代的时代,每一次技术的进步都预示着一个全新的未来。在此背景下第十二届中国智能产业高峰论坛即将拉开帷幕。9月16日-9月18日高峰论坛在中国南昌举行,拓世科技集团董事长李火亮将亲身出席本次活动,与众多领…

解决:AD装配输出拾放文件出现闪退问题

PCB在装配输出过程中,需要导出拾放文件,但是今天每次执行这个过程,AD软件就会直接闪退。 重启AD把项目管理器中没有关掉的一系列乱七八糟文件手动关闭关闭AD软件再次重启AD,打开项目重新导出。