ES-DSL查询

2022-05-05 17:00:45 浏览数 (1)

DSL查询

DSL查询分类

查询所有:查询出所有数据(match_all)

全文检索:利用分词器对用户输入内容分词,然后去倒排索引库中匹配

  • match_query
  • multi_match_query

精确查询:根据精确词条值查找数据,一般是查找keyword,数值,boolean等字段

  • ids
  • range
  • Term

地理查询:根据经纬度查询

  • Geo_distance
  • Get_bounding_box

复合查询:复合查询可以将上述各种查询条件组合起来,合并查询条件

  • boool
  • function_score

DSL Query基本语法

代码语言:javascript复制
GET /indexName/_search
{
  "query": {
    "查询类型": {
      "查询条件": "条件值"
    }
  }
}

全文检索查询

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

代码语言:javascript复制
GET /indexName/_search
{
  "query": {
    "match": {
      "FIELD": "TEXT"
    }
  }
}

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

代码语言:javascript复制
GET /indexName/_search
{
  "query": {
    "multi_match": {
      "query": "TEXT",
      "fields": ["FIELD1", " FIELD12"]
    }
  }
}

match与multi_match的区别

  • match根据一个条件查询
  • Multi_match根据多个字段查询,参与查询字段越多,查询性能越差,多字段建议使用all的方式

精确查询

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

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

trem查询语法:

代码语言:javascript复制
// term查询
GET /indexName/_search
{
  "query": {
    "term": {
      "FIELD": {
        "value": "VALUE"
      }
    }
  }
}

range查询语法:

代码语言:javascript复制
// range查询
GET /indexName/_search
{
  "query": {
    "range": {
      "FIELD": {
        "gte": 10,
        "lte": 20
      }
    }
  }
}

地理查询

根据经纬度查询

  • geo_bounding_box:查询geo_point值落在某个矩形范围的所有数据

语法:

代码语言:javascript复制
// 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
        }
      }
    }
  }
}
  • geo_distance:查询到指定中心点小于某个距离值的所有文档

语法:

代码语言:javascript复制
// geo_distance 查询
GET /indexName/_search
{
  "query": {
    "geo_distance": {
      "distance": "距离",
      "FIELD": "经纬度坐标"
    }
  }
}

复合查询

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

相关性算分

当我们利用match查询文档时文档结果会根据于搜索词条的关联度打分,返回结果时按照分值进行排列

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

语法:

代码语言:javascript复制
#相关性算分
GET /hotel/_search
{
  "query": {
    "function_score": {
      //原始查询条件
      "query": {
        "match": {
          "name": "外滩"
        }
      },
      "functions": [
        {
          //过滤条件
          "filter": {
            "term": {
              "city": "如家"
            }
          },
          //算分函数
          "weight": 10
        }
      ],
      //加权模式
      "boost_mode": "multiply"
    }
  }
}

语法解释:

  • query:原始查询条件,搜索文档并根据相关性打分 functions:
    • ​ filter:过滤条件,复合条件的文档才会被重新算分
    • ​ 算分函数:将来会与query score运算,符合条件的文档才会被重新算分
      • ​ weight:给一个常量值,作为函数结果
      • ​ field_value_factor:用文档中的某个字段值作为函数结果
      • ​ random_scope:随机生成一个值,作为函数结果
      • ​ script_scope:自定义计算公式,公式结果作为函数结果
    • ​ 加权模式:
      • ​ multiply:两者相乘(默认)
      • ​ replace:用function score替换query score
      • ​ 其他:sum、avg、max、min

布尔查询

布尔查询是一个或者多个查询子句的组合

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

需求:搜索名字包含如家,价格不高于400在坐标31.21,121.5周围10km范围的酒店文档

语法:

代码语言:javascript复制
#布尔查询
GET /hotel/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "如家"
          }
        }
      ],
      "must_not": [
        {
          "range": {
            "price": {
              "gt": 400
            }
          }
        }
      ],
      "filter": [
        {
          "geo_distance": {
            "distance": "10km",
            "location": "31.21,121.51"
          }
        }
      ]
    }
  }
}

搜索结果处理

排序

es支持对搜索结果排序,默认是根据相关度算分来排序,可以排序的字段有:keyword类型、数值类型、地理坐标、日期类型等

通过评分和价格排序:

代码语言:javascript复制
#通过评分和价格排序
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "score": {
        "order": "desc"
      },
      "price": {
        "order": "asc"
      }
    }
  ]
}

当有多个排序条件时会优先执行前面的条件

通过距离排序

代码语言:javascript复制
#通过距离排序
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_geo_distance": {
        "location": "31.226215,121.495706",
        "order": "asc",
        "unit": "km"
      }
    }
  ]
}

注意这里的经纬度是纬度在前

分页

es中默认只返回top10的数据,而如果要查询更多数据就需要修改分页参数了

es中通过修改from、size参数来控制返回的分页结果

代码语言:javascript复制
#分页
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  //起始记录数
  "from": 0,
  //获取文档总数
  "size": 20
}

语法解释:

from:获取文档的起始位置默认是0(from = size*(page-1))

size:一次获取的文档总数

注意:es能获取到的最大数据为10000

深度分页问题

es的分页原理是先查询出分页所需的所有文档(例如from=100,size=10,就会查询出110条数据再返回101-110的数据)当然这在单机状态是没有问题的,在分布式系统中就会出现问题

集群es中的数据是分片存储在不同的es机器上的,假如集群中有100台机器查询数据为from=990,size=10,es就会从不同的es机器上分别查找1000条数据,然后聚合重排序后返回991-1000的数据,这次查询就会查询出100*(990 10)=100000,这10万条数据放进内存重排序时非常消耗cpu和内存甚至造成服务器宕机,所以在业务中应尽量避免使用深度分页(es设定结果集的上限为10000)

深度分页问题解决方案

针对深度分页,es提供了两种解决方案

search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据(官方推荐方式)

scroll:原理将排序数据形成快照,保存在内存(不推荐使用)

搜索结果高亮

es支持给搜索出来的关键字加标签,前端在给相应标签写样式就实现了搜索功能高亮

语法:

代码语言:javascript复制
#高亮显示
GET /hotel/_search
{
  "query": {
    "match": {
      "all": "如家"
    }
  },
  "highlight": {
    //开始标签
    "pre_tags": "<em>",
    //结束标签
    "post_tags": "</em>", 
    //是否字段匹配,默认情况下搜索字段需要与高亮字段匹配
    "require_field_match": "false", 
    //高亮字段
    "fields": {
      "name": {},
      "brand": {}
    }
  }
}

0 人点赞