在es中搜索是非常重要的核心功能(说白了使用es存储数据主要目的就是为了更好更快更准确的搜索)而Elasticsearch提供了一种json风格的查询语言,称为Query DSL(Query domain-specific language)。查询语言功能很全面能结果我们生产中绝大部分的查询需求。下面跟随笔者一起来学习一下DSL查询的功能。
GET请求: http://ip:port/{index_name}/{type}/_search
GET: http://xxx.xx.x.xxx:9200/singers/singer/_search
DSL搜索 请求url是如上固定的,我们只需要修改json类型的查询条件
//1. 设置相关映射关系
{
"properties": {
"name": {
//字符串
"type": "text",
"index": "true",
"analyzer": "ik_max_word",
//为name添加 keyword字段用于term精确查找
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
}
},
"desc": {
//日期类型
"type": "text",
"index": "true",
//分词器
"analyzer": "ik_max_word",
//为desc添加 keyword字段用于term精确查找
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
}
}
}
}
//2. 填充数据 不会bulk批量插入 见谅
POST http://xxx.xx.x.xx:9200/singers/singer/
{
"id": 42,
"name": "音阙诗听",
"signer_id": 1288409,
"images": "http://y.gtimg.cn/music/photo_new/T001R150x150M000002vALgR3hRRlv.webp",
"height": 1.64,
"bitthday": "1994-10-21",
"status": true,
"desc": "音阙诗听音乐社,成立于2016年11月1日,由殇小瑾与李俊羽发起组织,聚集了全国各地一群对传统与流行音乐有相同和理念的朋友。成员在曲,词,演奏,演唱,后期制作,MV制作,美工,宣传等方面各展其长"
}
//查询全部
{
"query": { "match_all": {} }
}
match 查询可操作文本、数值和日期类型的数据,
{
"query": {
"match": {
"desc": "Eason Chan 香港"
}
},
//用来设置设置返回的数据字段
"_source":[
"id",
"name",
"desc"
]
//从当前index开始获取
"from": 3,
//每页获取数量
"size": 5
}
主要是针对查询的**"desc"字段的值中的搜索词进行分词(依据standard分词器 分成 ‘Eason‘,’Chan,’香‘,’港‘)** 每个词组搜索命中最终将所有命中数据汇总到一起返回。
由 match 构建的 boolean 查询语句默认是逻辑或(or),当然,我们可以通过 operator 参数来改变这个默认行为。
minimum_should_match:最低匹配度 如果operator 为or的情况下 用于控制分词条件在倒排索引中最少的数量。
{
"query": {
"match" : {
"desc" : {
"query" : "Eason Chan 香港",
"operator" : "and"
}
}
}
}
{
"query": {
"match" : {
"desc" : {
"query" : "Eason Chan 香港 歌手",
"minimum_should_match" : 6
}
}
}
}
这样再次支持只查询出来 一条"陈奕迅"
match_phrase有点类似match 但是却比match更加严格,是一种短语匹配 主要用于文本、数值和日期类型的数据查询。
短语之前有严格的距离限制 默认为紧邻距离为0 如果不符合则匹配不上(标签符号除外)。
{
"query": {
"match_phrase": {
"desc":{
//符合‘歌’和‘制’两者之间的距离为3的记录才会被查询出来
"query":"歌 制",
//不写slop 默认为1
"slop":"3"
}
}
}
}
与match_phrase查询类似,但是会对最后一个Token在倒排序索引列表中进行通配符搜索。Token的模糊匹配数控制:max_expansions 默认值为50
{
"query": {
"match_phrase_prefix": {
"desc":{
"query":"演员"
"max_expansions": 1
}
}
}
}
mutil_match 用于多字段匹配查询
{
"query" : {
"multi_match": {
"query": "周传雄",
"fields": ["name", "desc"]
}
}
}
我们知道,全文查询在执行查询之前,会先对提供的查询文本进行分析。
然而,Term-level 查询是直接查询倒排索引中的确切的值。
Term-level 查询通常用于结构化的数据,如数值、日期、枚举值或关键字,而不是文本分词查找类似于Mysql的范围查找
{
"query": {
"term" :
{
"name" : "周传雄"
}
}
}
该查询会将name中的“周传雄” 作为一个完整的词组(不分词)进行查询。
注意:此处name字段使用了ik中文分词器,所以中文分词器会对name进行分词如果直接对name进行查询有可能在分词器的作用下查找不到。 但是此处映射创建的时候为其创建了一个keyword字段(type也是keyword)所以查询的时候可以使用name.keyword这样就可以查询到了
{
"query": {
"term" :
{
"name.keyword" : "汪苏泷"}
}
}
{
"query": {
"terms" :
{ "name" :["汪苏泷", "周传雄"]
}
}
}
{
"query": {
"terms" :
{ "name.keyword" :["汪苏泷", "周传雄"]
}
}
}
与term类似 只是查询字段支持数组类型类似于mysql 的in条件
range查询找出落在指定区间内的数字或者时间
{
"query": {
"range" :
{
"height" :{
"gte" : 1.50,
"lte" : 1.60,
"boost" : 2.0
}
}
}
}
我们可以通过指定一个boost值来控制每个查询子句的相对权重,该值默认为1。一个大于1的boost会增加该查询子句的相对权重。一个高的boost值会产生一个高的_score。
exists 返回字段值不为 null 的记录。
{
"query": {
"exists" : { "field" : "name" }
}
}
返回字段的 term 以确切的前缀(前缀不会被分析)开头的记录。
{
"query": {
"prefix" : { "name" : "周" }
}
}
wildcard 指的是通配符查询。
支持的通配符主要有:
{
"query": {
"wildcard" : { "name.keyword" : "陈??" }
}
}
正则匹配查询
{
"query": {
"regexp" : { "name" : "jo.*" }
}
}
fuzzy在es中可以理解为模糊查询,搜索本身很多时候是不精确的,很多时候我们需要在用户的查询词中有部分错误的情况下也能返回正确的结果
{
"query": {
"fuzzy" : {
"name.keyword" : {
"value":"周杰雄",
"fuzziness":2,
"prefix_length":0,
"max_expansions":100
}
}
}
}
fuzziness :本次查询允许的最大编辑距离,默认不开启模糊查询,相当于fuzziness=0。编辑距离是对两个字符串差异长度的量化,及一个字符至少需要处理多少次才能变成另一个字符,比如lucene和lucece只差了一个字符他们的编辑距离是1。
prefix_length : 控制两个字符串匹配的最小相同的前缀大小,也即是前n个字符不允许编辑,必须与查询词相同,默认是0,prefix_length作用在分词后的词组级 比如prefix_length =2 则“周杰雄”前两个字需要完全匹配
type 查询指的是根据文档的 type 来查询。
这里的 type 就是文档的类别(逻辑分组),类似于 MySQL 的数据表。
查询type名为singer (singer表)的所有数据。
{
"query": {
"type" : {
"value" : "singer"
}
}
}
ids 查询指的是根据文档的 _id 集合来查询。
{
"query": {
"ids" : { "values" : ["J03cQn4BYNmJPaeL-JQr"] }
}
}
Bool查询现在包括四种子句,must,filter,should,must_not
minimum_should_match
参数定义了至少满足几个子句。{
"query": {
"bool": {
"must": [{
"match": {
"name": "周传雄"
}
}],
"must_not": [{
"match": {
"name": "陈奕迅"
}
}],
"should": [{
"range": {
"height": {
"gte": "1.60",
"lte": "1.80"
}
}
}]
}
}
}
上述的3,4小节主要对es的查询语句进行了,下面我们来学习如何使es的DSL的过滤。
#查询height大于1.80的记录(过滤)
{
"query" : {
"constant_score": {
"filter": {
"range": {
"height": {
"gte": 1.80
}
}
}
}
}
}
#使用布尔查询添加过滤
{
"query": {
"bool": {
"filter": {
"multi_match": {
"query": "周传雄",
"fields": ["name", "desc"]
}
}
}
}
}
当我们不关心检索词频率TF(Term Frequency)对搜索结果排序的影响时,可以使用constant_score将查询语句query或者过滤语句filter包装起来
相对于上述在查询阶段进行过滤不同,该后置过滤器是对查询后的结果在进行过滤返回结果
//查询符合desc字段 并过滤出来height 大于等于1.60的记录
{
"query": {
"match": {
"desc": "Eason Chan 香港"
}
},
"post_filter":{
"range":{
"height":{
"gte":1.60
}
}
}
}