DSL查询文档

利用RestClient往ES中导入了很多数据,数据的存储不是目的,最终是从海量的数据中,检索出你所需要的哪些,这就用到了ES的搜索功能了

一、DSL查询分类

1.1.常见的查询类型

Elasticsearch提供了基于JSON的DSL(Domain Specific Language)来定义查询。常见的查询类型包括:

1).查询所有:查询出所有数据,一般测试用。例如:match_all

2).全文检索(full text)查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:

  • match_query
  • multi_match_query

3).精确查询:根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段。例如:

  • ids
  • range
  • term

4).地理(geo)查询:根据经纬度查询。例如:

  • geo_distance
  • geo_bounding_box

5).复合(compound)查询:复合查询可以将上述各种查询条件组合起来,合并查询条件。例如:

  • bool
  • function_score

1.2.DSL Query基本语法

语法如下:

GET /indexName/_search
{
  "query": {
    "查询类型": {
      "查询条件": "条件值"
    }
  }
}

 查询所有

# 查询所有
GET /indexname/_search
{
  "query": {
    "match_all": {}
  }
}

查询所有是不需要查询条件的,以查询文档库hotel为例如下:

# 查询hotel文档库中所有内容
GET /hotel/_search
{
  "query": {
    "match_all": {}
  }
}

执行后结果如下:

二、全文检索查询

全文检索查询,会对用户输入内容分词,常用于搜索框搜索,例如京东搜索功能

2.1.全文检索查询:match

2.1.1.语法说明

match查询:全文检索查询的一种,会对用户输入内容分词,然后去倒排索引库检索,语法:

GET /indexName/_search
{
  "query": {
    "match": {
      "FIELD": "TEXT"
    }
  }
}

注意:

  match:代表有条件,field:字段根据那个字段查询  text:要搜索的内容

2.1.2.案例

查询条件:全文检索字段all ,含有外滩,all是前面学习表映射时的多个字段的结合字段 

# match查询
GET /hotel/_search
{
  "query": {
    "match": {
      "all": "外滩"
    }
  }
}

执行后结果如下:

全文检索all字段:外滩如家,会对外滩如家进行分词,然后倒排索引,

# match查询
GET /hotel/_search
{
  "query": {
    "match": {
      "all": "外滩如家"
    }
  }
}

执行后结果如下:

2.2.全文检索查询:multi_match

2.2.1.语法如下:

multi_match:与match查询类似,只不过允许同时查询多个字段,语法:

GET /indexName/_search
{
  "query": {
    "multi_match": {
      "query": "TEXT",
      "fields": ["FIELD1","FIELD2"]
    }
  }
}

2.2.2.案例演示

multi_match 多个点字段搜索:在多个字段中查询 含有外滩如家的

# 根据"name", "brand", "business"字段全文检索外滩如家
GET /hotel/_search
{
  "query": {
    "multi_match": {
      "query": "外滩如家",
      "fields": ["name", "brand", "business"]
    }
  }
}

执行后结果如下:

2.3.通过使用all和多个字段搜索是一样的,那么使用那个呢?

参与搜索的字段越多查询效率越低推荐使用all的方法,不要查询整个字段,而是把字段copy到一个字段中去查,这样效率更高

三、精准查询

3.1.精准查询说明

精确查询一般是查找keyword、数值、日期、boolean等类型字段。所以不会对搜索条件分词。常见的有:

  • term:根据词条精确值查询
  • range:根据值的范围查询

例如:京东中对于CPU型号、机身内存都属于精准查询,

而这几个字段brand(品牌)、city(城市)、price(价格)、score(评分):都是keyword 或数值类型,在查询的时候不能进行分词

3.2.语法

精确查询常见的有term查询和range查询。

  • term查询:根据词条精确匹配,一般搜索keyword类型、数值类型、布尔类型、日期类型字段
  • range查询:根据数值范围查询,可以是数值、日期的范围

3.2.1.term查询:

语法如下:term是精确匹配的,不会进行分词了

# term查询
GET /indexName/_search
{
  "query": {
    "term": {
      "FIELD": {
        "value": "VALUE"
      }
    }
  }
}

案例说明:term根据词条精确查询:查询city为上海的,如下:

# term查询
GET /hotel/_search
{
  "query": {
    "term": {
      "city": {
        "value": "上海"
      }
    }
  }
}

执行后结果如下:

3.2.2.range查询:

range:根据条件范围查询,语法如下:

# range查询
GET /indeXname/_search
{
  "query": {
    "range": {
      "FIELD": {
        "gte": 10,
        "lte": 20
      }
    }
  }
}

案例说明:搜索price大于等于100,小于等于300的酒店信息,如下:

# range查询
GET /hotel/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 100,
        "lte": 300
      }
    }
  }
}

执行后结果如下:

四、地理坐标查询

4.1.地理坐标查询说明

根据经纬度查询。常见的使用场景包括:

  • 携程:搜索当前位置附近的酒店
  • 滴滴:搜索我附近的出租车
  • 微信:搜索我附近的人

如下:

 

4.2.地理查询

根据经纬度查询有两种方式。分别为:geo_bounding_box和geo_distance

4.2.1.地理查询:geo_bounding_box

geo_bounding_box:查询geo_point值落在某个矩形范围的所有文档

语法如下:

# geo_bounding_box查询
GET /indexname/_search
{
  "query": {
    "geo_bounding_box":{
      "FIELD":{
        "top_left":{
          "lat":31.1,
          "lon":121.5
        },
        "bottom_right":{
          "lat":30.9,
          "lon":121.7
        }
      }
    }
  }
}

案例根据location字段查询,查询左上点位置(121.5,31.1)、和右下点(121.7,30.9)形成的矩形区域内的所有文档,如下:

# geo_bounding_box查询
GET /hotel/_search
{
  "query": {
    "geo_bounding_box":{
      "location":{
        "top_left":{
          "lat":31.1,
          "lon":121.5
        },
        "bottom_right":{
          "lat":30.9,
          "lon":121.7
        }
      }
    }
  }
}

执行后结果如下:

4.2.2.地理查询:geo_distance

geo_distance:查询到指定中心点小于某个距离值的所有文档

语法如下:

# geo_distance查询
GET /indexname/_search
{
  "query": {
    "geo_distance":{
      "distance": "20km",
      "FIELD": "31.21,121.5"
    }
  }
}

案例如下:查询以经纬度(121.5,32.21)为原点,半径20km范围内的酒店信息,如下:

# geo_distance查询
GET /hotel/_search
{
  "query": {
    "geo_distance":{
      "distance": "20km",
      "location": "31.21,121.5"
    }
  }
}

执行后结果如下:

五、复合查询

5.1.复合查询

复合(compound)查询:复合查询可以将其它简单查询组合起来,实现更复杂的搜索逻辑,

例如:fuction score:算分函数查询,可以控制文档相关性算分,控制文档排名。如百度竞价排名:

5.2.相关性算分

当我们利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时按照分值降序排,例如,我们搜索“虹桥如家”,结果如下:

[
  {
    "_score":17.850193,
    "_source":{
    "name""虹桥如家酒店真不错",} 
  },
  {
    "_score":12.259849,
    "_source":{
    "name""外滩如家酒店真不错",} 
  },
  {
    "_score":12.259849,
    "_source":{
    "name""迪士尼如家酒店真不错",} 
  },
]

elasticsearch中的相关性打分算法是什么?

  • TF-IDF:在elasticsearch5.0之前,会随着词频增加而越来越大
  • BM25:在elasticsearch5.0之后,会随着词频增加而增大,但增长曲线会趋于水平

IDF:上面的操作如家在三个文档中都出现了,权重为0 虹桥只有第一条出现了这条文档的权重较大 

BM25:算法的影响不会受词频的影响 

算法说明:

 曲线图如下:

5.3.DSL查询语法-Function Score Query

使用function score query,可以修改文档的相关性算分(query score),根据新得到的算分排序。

上面执行后结果如下:

案例:给如家 品牌的酒店排名靠前一些,想完成设置如家品牌的排名靠前,function score设置需要注意:

1.哪些文档需要算分加权?
品牌为如家的酒店
2.算分函数是什么?
weight就可以
3.加权模式是什么?
求和

DSL语法如下:

GET /hotel/_search
{
  "query": {
    "function_score": {
      "query": {"match": {"all": "外滩"}},
      "functions": [ //算分函数
        {
          "filter": {"term": { "brand": "如家"}}, //满足的条件,品牌必须是如家
          "weight": 10 //算分权重为2
        }
      ],
      "boost_mode": "sum" // 更改加权模式:sum
    }
  }
}

 加权后如家酒店跑到第一名了,如下:

5.4.DSL查询语法-BooleanQuery

Function Score Query和BooleanQuery的区别:

  • Function Score Query:计算相关性算分
  • Boolean Query:不是计算相关性算分,而是把多个查询语句组合在一起,形成新的查询,被组合的查询称为子查询

复合查询Boolean Query是一个或多个查询子句的组合。子查询的组合方:

  • must:必须匹配每个子查询,类似“与”
  • should:选择性匹配子查询,类似“或”
  • must_not:必须不匹配,不参与算分,类似“非”
  • filter:必须匹配,不参与算分

语法如下:

GET /hotel/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {"city": "上海"}}
      ],
      "should": [
        {"term": {"brand": "皇冠假日"}
        {"term": {"brand": "华美达"}}
      ],
      "must_not":[
        {"range": {"price": {"lte":500}}}
      ],
      "filter":[
        {"range": {"score": {"gte":45}}}
      ],
    }
  }
}

注意:

  • must_not和filter 不参与算分 ,它的返回结果是或否 true和false,如果子查询较多,都参与算分,会非常影响性能
  • ES会把filer的查询,放到缓存里面,将来在查询的时候,会近一步提高性能
  • 有以上四种组合关系,除了跟算分相关的,一般是关键字,放到must和should里面
  • 其他的都应该放到must_not和filter里面,尽可能的减少算分提高查询的效率

下面图片的查询,搜索框的内容关键字的搜索可以放到must里,因为它参与算分,过滤条件:类型也好容量也好,放到must_not或者filter里面,放到这里面不参与算分

 

案例说明:

利用bool查询实现功能,需求:搜索名字包含"如家”,价格不高于400,在坐标31.21,121.5周围10km范围内的酒店。如下:

GET /hotel/_search
{
  "query": {
    "bool": {
      "must": [
        {"match": {"name": "如家"}}
      ],
      "must_not": [
        {"range": {"price": {"gt": 400}}
        }
      ],
      "filter": [
        {"geo_distance": {
          "distance": "10km",
          "location": {"lat": 31.21,"lon": 121.5}
        }}
      ]
    }
  }
}

注意:上面的must_not是取反的,gt值为400表示,价格大于400,取反则是价格小于400。

执行后结果如下:

posted @ 2023-11-08 18:39  酒剑仙*  阅读(174)  评论(0)    收藏  举报