ElasticSearch学习笔记(3)· ES高级检索(query)

目录

  • 八、ES中高级查询
    • 1、查询方式
    • 2、测试数据
    • 3、URL查询
    • 4、DSL查询
    • 5、DSL高级查询(Query)
        • 查询所有(match_all)
        • 查询结果中返回的指定条数(size)
        • 分页查询(from)
        • 查询结果中返回指定字段(_source)
        • 分词查询(match)
        • 短语匹配(match_phrase)
        • 关键词查询(term)
        • 范围查询(range)
        • 前缀查询(prefix)
        • 通配符查询(wildcard)
        • 多id查询(ids)
        • 模糊查询(fuzzy)
        • 布尔查询(bool)
        • 高亮查询(highlight)
        • 多字段查询(multi_match)
        • 多字段分词查询(query_string)
        • 过滤查询(Filter Query)
          • 1、过滤查询
          • 2、过滤语法
          • 3、常见的过滤器类型

八、ES中高级查询

1、查询方式

ES官方提供了两种检索方式:一种是通过URL参数进行搜索,另一种是通过DSL进行搜索。官方更推荐使用第二种方式,第二种方式是基于传递JSON作为请求体格式与ES进行交互,这种方式更强大,更简洁。

2、测试数据

# 1、删除索引
DELETE /ems

# 2、创建索引并指定类型
PUT /ems
{
	"mappings":{
		"emp":{
			"properties":{
				"name":{
					"type":"keyword"
				}.
				"age":{
					"type":"integer"
				},
				"bir":{
					"type":"date"
				},
				"content":{
					"type":"text"
				},
				"address":{
					"type":"keyword"
				}
			}
		}
	}
}

# 3、插入测试数据
PUT /ems/emp/_bulk
	{"index":{}}
		{"name":"小黑","age":23,"bir":"2020-12-12","content":"未开发团队选择一款优秀的MVC框架是件难事儿,在众多可行的方案中抉择需要很高的经验和水平","address":"北京"}
	{"index":{}}
		{"name":"王小黑","age":24,"bir":"2020-12-12","content":"Spring框架是一个分层架构,由7个定义良好的模块组成,spring模块构建在核心容器之上,核心容器定义了创建、配置和管理bean的方式","address":"上海"}
	{"index":{}}
		{"name":"张小五","age":8,"bir":"2020-12-12","content":"Spring Cloud 作为Java语言的微服务框架,它依赖于SpringBoot,又快速开发,持续较夫和容易部署等特点,Spring Cloud 的组件非常多,涉及微服务的方方面面,并在开源社区Spring和Netflix,pivotal两大公司的推动下越来越完善","address":"无锡"}
	{"index":{}}
		{"name":"win7","age":9,"bir":"2020-12-12","content":"Spring的目标是致力于全方位的简化Java开发,这势必引出更多的解释,Spring是如何简化Java开发的?","address":"南京"}
	{"index":{}}
		{"name":"梅超风","age":43,"bir":"2020-12-12","content":"Redis是一个开源的使用ANSI C语言编写,支持网络,可基于内存亦可持久化的日志型,key-value数据库,并提供多种语言API","address":"杭州"}
	{"index":{}}
		{"name":"张无忌","age":59,"bir":"2020-12-12","content":"ElasticSearch是一个基于Lucene的搜索服务器,他提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口","address":"北京"}
		

3、URL查询

GET /ems/emp/_search?q=*&sort=age:asc
# _search	搜索的APi
# q=*		匹配所有文档
# sort		以结果中的指定字段排序

4、DSL查询

GET /ems/emp/_search
{
	"query":{"match_all":{}},
	"sort":[
		{
			"age":{
				"order":"asc"
			}
		}
	]
}
# 等价于上面URL检索的方式

5、DSL高级查询(Query)

查询所有(match_all)

match_all关键字:返回索引中的全部文档

GET /ems/emp/_search
{
	"query":{"match_all":{}}
}
查询结果中返回的指定条数(size)

size关键字:指定查询结果中返回指定条数,默认返回值10条

GET /ems/emp/_search
{
	"query":{"match_all":{}},
	"size":1
}
分页查询(from)

from关键字:用来指定起始返回位置,和size关键字连用可实现分页效果

GET /ems/emp/_search
{
	"query":{"match_all":{}},
	"sort":[
		{
			"age":{
				"order":"desc"
			}
		}
	],
	"size":2,
	"from":1
}
查询结果中返回指定字段(_source)

_source关键字:是一个数组,在数组中可以用来显示展示哪些字段

GET /ems/emp/_search
{
	"query":{"match_all":{}}
	"_source":["account_number","balance"]
}
分词查询(match)

match关键字:会根据你的查询词进行分词

NOTE:好像match不管字段类型都会自动分词,term会根据字段的类型来决定是否分词

GET /ems/emp/_search
{
	"query":{
		"match":{
			"address":"北京"
		}
	}
}
短语匹配(match_phrase)

match_phrase关键字:查询分析文本并根据分析的文本创建一个短语查询。match_phrase 会将检索关键词分词。match_phrase的分词结果必须在被检索字段的分词中都包含,而且顺序必须相同,而且默认必须都是连续的。

NOTE:还有一个match_phrase_prefix关键字,会对最后一个分词进行前缀扫描,导致始终要扫描大量索引,性能可能很差,这里就不记录了

#假设有四条数据
#{ "id" : 1,"content":"关注我,系统学编程" } 
#{ "id" : 2,"content":"系统学编程,关注我" } 
#{ "id" : 3,"content":"系统编程,关注我" } 
#{ "id" : 4,"content":"关注我,间隔系统学编程" }

# 使用match_phrase查询,ik_smart分词
GET /tehero_index/_doc/_search
{
    "query": {
        "match_phrase": {
            "content.ik_smart_analyzer": {
            	"query": "关注我,系统学"
            }
        }
    }
}
#结果只有id为1的能够匹配,但是使用match查询则可以获取所有数据

分析:上面的例子使用的分词器是ik_smart,所以检索词“关注我,系统学”会被分词为3个Token【关注、我、系统学】;而文档1、文档2和文档4 的content被分词后都包含这3个关键词,但是只有文档1的Token的顺序和检索词一致,且连续。所以使用 match_phrase 查询只能查询到文档1(ps:文档2 Token顺序不一致;文档4 Token不连续;文档3 Token没有完全包含)。使用 match查询可以查询到所有文档,是因为所有文档都有【关注、我】这两个Token

#match_phrase 核心参数:slop 参数-Token之间的位置距离容差值

# 将上面的 match_phrase 查询新增一个 slop参数
GET /tehero_index/_doc/_search
{
    "query": {
        "match_phrase": {
            "content.ik_smart_analyzer": {
            	"query": "关注我,系统学",
            	"slop":1
            }
        }
    }
}
# 结果:文档1和文档4都被检索出来
# 原因:关注我,间隔系统学编程 会被分词为{关注、我、间隔、系统、学、编程},我与系统学之间间隔为1
关键词查询(term)

term关键字:用来使用关键词查询

GET /ems/emp/_search
{
	"query":{
		"term":{
			"address":{
				"value":"北京"
			}
		}
	}
}
# Note1:通过使用term查询得知ES中默认使用分词器为标准分词器(standard Analyzer),标准分词器对于英文单词分词,对于中文单字分词
# Note2:通过使用term查询得知,在ES的Mapping Type中keyword、date、integer、long、double、boolean、ip这些类型不分词,只有text类型分词
范围查询(range)

range关键字:用来指定查询指定范围的围挡

GET /ems/emp/_search
{
	"query":{
		"range":{
			"age":{
				"gte":8,
				"lte":38
			}
		}
	}
}
前缀查询(prefix)

prefix关键字:用来检索含有指定前缀的关键词的相关文档

GET /ems/emp/_search
{
	"query":
		"prefix":{
			"content":{
				"value":"redis"
			}
		}
}
通配符查询(wildcard)

wildcard关键字:通配符查询 ?用来表示一个任意字符 *用来匹配多个任意字符

GET /ems/emp/_search
{
	"query":{
		"wildcard":{
			"content":{
				"value":"re*"
			}
		}
	}
}
多id查询(ids)

ids关键字:值为数组类型,用来根据一组id获取多个对应的文档

GET /ems/emp/_search
{
	"query":{
		"ids":{
			"values":["aod12doj12ihdd1d","dkno1idiosnkf123"]
		}
	}
}
模糊查询(fuzzy)

注意此模糊查询非关系型数据库的模糊查询

fuzzy关键字:用来模糊查询含有指定关键字的文档,注意:允许出现的错误必须在0~2之间

最大错误编辑距离由文本的词长决定

​ 如果文本长度为0~2 则不允许出现错误

​ 如果文本长度为3~5 则允许由一个错误

​ 如果文本长度大于5 则允许由两个错误

GET /ems/emp/_search
{
	"query":{
		"fuzzy":{
			"content":"spoong"
		}
	}
}
# 本意查询spring,因为spring字符为6个所以允许错误2个字符(最大错误距离两个)
布尔查询(bool)

bool关键字:用来组合多个条件实现复杂查询

​ must:相当于 && 同时成立

​ should:相当于 || 成立一个就行

​ must_not:相当于 !不能满足任何一个

GET /ems/emp/_search
{
	"query":{
		"bool":{
			"must":[
				{
					"range":{
						"age":{
							"gte":8,
							"lte":30
						}
					}
				}
			]
		}
	},
	"must_not":[
		{
			"wildcard":{
				"content":{
					"value":"redi?"
				}
			}
		}
	]
}
高亮查询(highlight)

highlight关键字:可以让符合条件的文档中的关键字高亮

GET /ems/emp/_search
{
	"query":{
		"term":{
			"content":{
				"value":"redis"
			}
		}
	},
	"highlight":{
		"fields":{
			"*":{}
		}
	}
}
# 默认高亮标签为

# 也可以自定义高亮html标签,在highlight中使用pre_tags和post_tags
GET /ems/emp/_search
{
	"query":{
		"term":{
			"content":"框架"
		}
	},
	"highlight":{
		"pre_tags":[""],
		"post_tags":[""],
		"fields":{
			"*":{}
		}
	}
}

# 多字段高亮 使用require_field_match开启多个字段高亮
GET /ems/emp/_search
{
	"query":{
		"term":{
			"content":"框架"
		}
	},
	"hightlight":{
		"pre_tags":[""],
		"post_tags":[""],
		"require_field_match":"false",
		"fields":{
			"*":{}		# *代表全部字段高亮
		}
	}
}
多字段查询(multi_match)

注意:使用这种方式进行查询时,为了更好获取搜索结果,在查询过程中会先将查询条件根据当前的分词器分词之后进行查询

GET /ems/emp/_search
{
	"query":{
		"multi_match":{
			"query":"中国",
			"fields":["name","content"]	#这里写要检索的指定字段
		}
	}
}
多字段分词查询(query_string)

注意:使用这种方式进行查询时,为了更好获取搜索结果,在查询过程中会先将查询条件根据当前的分词器分词之后进行查询,与上面不同的是,你可以选择分词器

GET /dangdand/book/_search
{
	"query":{
		"query_string":{
			"query":"中国人民共和国".
			"analyzer":"ik_max_word",
			"fields":["name","content"]
		}
	}
}
过滤查询(Filter Query)
1、过滤查询

其实准确来说,ES中的查询操作分为2中,查询(Query)过滤(filter)查询即是之前得到的query查询,它(查询)默认会计算每个返回文档的得分,然后根据得分排序而过滤(filter)直会筛选出符合的文档,并不计算得分,且它可以缓存文档,所以,单从性能考虑,过滤比查询更快

2、过滤语法

必须使用bool表达式将两种query组合在一起

注意:当filterQuery和query组合使用时先执行filterQuery中的语句,然后再去执行query中的语句

# 先过滤年龄大于等于10的再来查询
GET /ems/emp/_search
{
	"query":{
		"bool":{
			"must":{
				{"match_all":{}}
			},
			"filter":{
				"range":{
					"age":{
						"gte":10
					}
				}
			}
		}
	}
}
3、常见的过滤器类型
# 1、使用term过滤	先过滤出content为框架的数据后再去查询name为小黑的文档
GET /ems/emp/_search
{
	"query":{
		"bool":{
			"must":[
				{
					"term":{
						"name":{
							"value":"小黑"
						}
					}
				}
			],
			"filter":{
				"term":{
					"content":"框架"
				}
			}
		}
	}
}
# 2、使用terms过滤	先过滤出content为大黑或者大白的文档再去查询name为小黑的文档数据
GET /dangdang/book/_search
{
	"query":{
		"bool":{
			"must":[
				{
					"term":{
						"name":{
							"value":"小黑"
						}
					}
				}
			],
			"filter":{
				"terms":{
					"content":["大黑","大白"]
				}
			}
		}
	}
}
# 3、ranage filter过滤	先过滤age在7到20岁的文档,再去查询name为小黑的数据
GET /ems/emp/_search
{
	"query":{
		"bool":{
			"must":[
				"term":{
					"name":{
						"value":"小黑"
					}
				}
			],
			"filter":{
				"range":{
					"age":{
						"gte":7,
						"lte":20
					}
				}
			}
		}
	}
}
# 4、exists filter 过滤存在指定字段,获取字段不为空的索引记录使用	过滤存在字段aaa的文档再去查询name为小黑的数据
GET /ems/emp/_search
{
	"query":{
		"bool":{
			"must":[
				"term":{
					"name":{
						"value":"小黑"
					}
				}
			],
			"filter":{
				"exists":{
					"field":"aaa"
				}
			}
		}
	}
}
# 5、ids filter 过滤含有指定字段的索引记录	先过滤出id为1、2、3的数据再去查询名字为小黑的数据
GET /ems/emp/_search
{
	"query":{
		"bool":{
			"must":[
				"term":{
					"name":{
						"value":"小黑"
					}
				}
			],
			"filter":{
				"ids":{
					"values":["1","2","3"]
				}
			}
		}
	}
}

ElasticSearch学习笔记(1)· ES基本概念
ElasticSearch学习笔记(2)· 基于Kibana的基本CRUD
ElasticSearch学习笔记(3)· ES高级检索(query)
ElasticSearch学习笔记(4)· ES IK分词器
ElasticSearch学习笔记(5)· Java操作Elasticsearch6.2.4
ElasticSearch学习笔记(6)· Java操作Elasticsearch7.6.1
ElasticSearch学习笔记(7)· Springboot+SpringData操作ES
ElasticSearch学习笔记(8)· ES集群的搭建

你可能感兴趣的:(ElasticStack,elasticsearch)