ElasticSearch高级检索
ElasticSearch高级检索
检索方式( _search)
ES官方提供了两中检索方式:一种是通过 URL 参数进行搜索,另一种是通过 DSL(Domain Specified Language) 进行搜索。官方更推荐使用第二种方式第二种方式是基于传递JSON作为请求体(request body)格式与ES进行交互,这种方式更强大,更简洁。
使用语法
URL查询: GET /索引/类型/_search?参数
DSL查询: GET /索引/类型/_search {}
准备工作
开始高级检索之前先来准备一下测试数据
1.删除索引
DELETE /christy
2.创建索引、映射与类型
PUT /christy
{
"mappings": {
"user":{
"properties":{
"name":{
"type":"text"
},
"age":{
"type":"integer"
},
"bir":{
"type":"date"
},
"introduce":{
"type":"text"
},
"address":{
"type":"keyword"
}
}
}
}
}
3.批量插入数据
PUT /christy/user/_bulk
{"index":{}}
{"name":"Christy","age":20,"bir":"2001-01-01","introduce":"不要求很帅,像我这样就可以了","address":"京师"}
{"index":{}}
{"name":"Tide","age":23,"bir":"1998-09-08","introduce":"魔镜魔镜谁是世界上最美的女人","address":"开封"}
{"index":{}}
{"name":"hardy","age":5,"bir":"2016-02-12","introduce":"调皮捣蛋我最行","address":"杭州"}
{"index":{}}
{"name":"Tom","age":18,"bir":"2003-12-12","introduce":"Jerry是我最好的朋友","address":"纽约"}
{"index":{}}
{"name":"Jerry","age":6,"bir":"2015-10-10","introduce":"没有Tom的日子我真的好难过","address":"华盛顿"}
{"index":{}}
{"name":"布什","age":3,"bir":"2018-11-10","introduce":"我不是美国的那个总统,我只是一条普拉多,没有骂人的意思","address":"华盛顿"}
URL查询
1.查询所有(q=*)
语法:GET /index/type/_search?q=*
。例如我想查询索引Christy
下user
类型的所有数据,可以这么写:
GET /christy/user/_search?q=*
上述结果可以看到该指令成功返回了查询结果,也符合我们的预期。对于返回结果中每个字段的意思如下图
2.按字段排序(sort)
语法:GET /index/type/_search?q=*&sort=fileName
。比如上面查询出所有结果之后按年龄来排序,应该像下面这样:
GET /christy/user/_search?q=*&sort=age
3.分页查询(from&size)
语法:GET /index/type/_search?q=*&sort=fileName&size=count&from=(pageNumber-1)*size
。例如:我想取出按年龄排序后结果中的前两天数据,应该像下面这样写
GET /christy/user/_search?q=*&sort=age&size=2&from=0
4.返回指定字段的查询结果(source)
语法:GET /index/type/_search?q=*&size=1&from=0&_source=filedName1,...
。这个意思就是不需要返回每条记录的所有字段信息,比如我只想查询并返回用户的姓名和年龄,那么可以像下面这样写:
GET /christy/user/_search?q=*&size=1&from=0&_source=name,age
根据查询的返回结果我们可以看到只返回了我们定义的name和age两个字段的值
DSL查询
DSL查询是官方推荐的查询方式,相比较与URL,DSL能够根据更复杂的条件来查询,也是需要重点掌握的查询方式
1.查询所有(match_all)
GET /christy/user/_search
{
"query": { "match_all": {} }
}
2.返回指定条数(size)
GET /christy/user/_search
{
"query": { "match_all": {} },
"size": 2
}
3.分页查询(from&size)
GET /christy/user/_search
{
"query": {"match_all": {}},
"size": 2,
"from": 1
}
from是从0开始的,上面的分页中我们从1开始取两条,就将第一条用户christy的数据给过滤掉了,返回结果的第一条数据应该是用户Tide
4.查询的结果集中返回指定字段(_source)
GET /christy/user/_search
{
"query": {"match_all": {}},
"size": 2,
"from": 1,
"_source":["name","age"]
}
通过返回结果我们可以看到在上面分页结果的基础上只返回用户的name和age也是没有问题的。这里要注意的是命令中_source的参数是以数组的方式传递的
5.关键字查询(term)
GET /christy/user/_search
{
"query": {
"term": {
"address": {
"value": "开封"
}
}
}
}
NOTE1: 通过使用term查询得知ES中默认使用分词器为标准分词器(StandardAnalyzer),标准分词器对于英文单词分词,对于中文单字分词。
NOTE2: 通过使用term查询得知,在ES的Mapping Type 中 keyword , date ,integer, long , double , boolean or ip 这些类型不分词,只有text类型分词。
上面两条NOTE是什么意思呢?标准分词器将type类型为text的字段值分词后,只能按照单个汉字或者英文单词来查询,否则查询不到数据;比如我们测试数据的name
类型是text,其中有一条名字叫做"布什"的普拉多,我们这个时候直接搜索布什是什么都搜索不到的,但是搜索单个的布或者什是可以找到这只可爱的普拉多的,就像下图演示的一样
6.范围查询(range)
GET /christy/user/_search
{
"query": {
"range": {
"age": {
"gte": 8,
"lte": 30
}
}
}
}
上面我们看到的gte
和lte
分别是大于等于
和小于等于
的意思,上面的命令查询的是年龄大于等于8岁并且小于等于30岁的用户。如果需要查询大于8岁并且小于30岁的用户我们只需要把gte和lte改成gt和lt就行了;
7.前缀查询(prefix)
GET /christy/user/_search
{
"query": {
"prefix": {
"content": {
"introduce": "最"
}
}
}
}
前缀查询关键字prefix用来检索含有指定前缀关键字的相关文档。比如上面我们查询introduce字段包含
最
的用户。
8.通配符查询(wildcard)
通配符查询关键字wildcard说明:
?
:用来匹配一个字符
*
:用来匹配任意多个字符
GET /christy/user/_search
{
"query": {
"wildcard": {
"introduce": {
"value": "jerr*"
}
}
}
}
NOTE:我们目前还没有配置分词器,ES用的是自带的标准分词器,一个汉字一个词,所以这里通配符查询不能测试汉字,只能测试英文。
9.多id查询(ids)
顾名思义,多id查询就是可以根据多个记录的id来查询多条记录。这个一般都是在实际应用中查询多个记录列表或者详情
GET /christy/user/_search
{
"query": {
"ids": {
"values": ["OKEuB3kBVQPOYI_dp2GY","PKEuB3kBVQPOYI_dp2GY"]
}
}
}
10.模糊查询(fuzzy)
# fuzzy 模糊查询 最大模糊错误 必须在0-2之间
# 搜索关键词长度为 2 不允许存在模糊 0
# 搜索关键词长度为3-5 允许一次模糊 0 1
# 搜索关键词长度大于5 允许最大2模糊
GET /christy/user/_search
{
"query": {
"fuzzy": {
"introduce":"jerry"
}
}
}
首先,我们先演示第一种情况:搜索关键词长度为2,不允许存在模糊
address的类型是
keyword
不分词,我们输入京师是可以查到数据的,但是我们输入京湿是查询不到的
现在我们来演示第二种情况:搜索关键字长度3-5,最大只允许一个模糊字符
按照
introduce
查找jerry是可以查询到数据的,我们改错一个字符也没有问题,但是改错两个字符就不行了
最后我们来演示最后一种情况,搜索关键字大于5时,最大只允许模糊两个字符,为此我们先准备一条数据
PUT /christy/user/_bulk
{"index":{}}
{"name":"ElasticSearch","age":20,"bir":"2001-01-01","introduce":"ElasticSearch是最牛逼的搜索的引擎","address":"china"}
然后我们就以elasticsearch
为搜索关键字进行查询
效果如上图,这里就不解释了
11.布尔查询(bool)
bool关键字用来组合多个条件实现复杂查询,这也是bool查询的强大之处
must
:相当于&&,同时成立
should
:相当于||,满足一个条件就行
must_not
:相当于!,不能满足任何一个
GET /christy/user/_search
{
"query": {
"bool": {
"must": [
{
"range": {
"age": {
"gte": 0,
"lte": 30
}
}
}
],
"must_not": [
{"wildcard": {
"introduce": {
"value": "jerr*"
}
}}
],
"should": [
{
"term": {
"age": {
"value": "20"
}
}
},
{
"term": {
"introduce": {
"value": "tom"
}
}
}
]
}
}
}
12.高亮查询(highlight)
高亮关键字highlight可以让符合条件的文档中的关键字高亮,类似于下面这样
GET /christy/user/_search
{
"query": {
"term": {
"introduce": {
"value": "elasticsearch"
}
}
},
# highlight不是直接对结果进行高亮,而是对结果二次渲染高亮
"highlight": {
# fields意思是对哪些字段匹配出来的结果进行高亮,虽然我们上面是查询introduce里面的elasticsearch,但是如果我们其他的字段比如‘name’中也有elasticsearch或者其他字段中也有,并且我们也希望高亮,那么我们像下面这样写成*即可
"fields": {
"*": {}
}
}
}
查询结果我们也看到了,ES确实将查询出来的关键字特别处理了,前后加上了,这是斜体的意思,如果我们想实现百度的那种加红处理,需要自定义
pre_tags
和post_tags
有人说上面的测试结果只把
introduce
里面查询出来的结果高亮了,name
里面的没有高亮啊?那是因为没有加上require_field_match
这个属性,他的意思是是否只开启查询字段高亮。属性值必须设置成false才能针对所有字段高亮
GET /christy/user/_search
{
"query":{
"term":{
"introduce":"elasticsearch"
}
},
"highlight": {
"pre_tags": ["<span style='color:red'>"],
"post_tags": ["</span>"],
"require_field_match":false,
"fields": {
"*":{}
}
}
}
13.多字段查询(multi_match)
GET /christy/user/_search
{
"query": {
"multi_match": {
"query": "tom",
"fields": ["name","introduce"] #这里写要检索的指定字段
}
}
}
多字段查询需要注意
1.如果搜索的字段分词,他会对query进行先分词,后查询
2.如果搜索的字段部分词,他会直接使用query字符串整体进行搜索
我们使用tom纽约
进行搜索,由于introduce
是text类型的,他是分词的;address
是keyword类型的部分词,所以在搜索introduce的时候先对query进行分词,而查询address的时候不分词,直接使用整体进行查询。所以在使用多字段查询的时候,查询的字段最好是分词的字段
14.多字段分词查询(query_string)
多字段分词查询顾名思义可以对查询关键字进行分词,而且可以指定分词器,就是这样一个牛逼的存在
GET /christy/user/_search
{
"query": {
"query_string": {
"default_field": "introduce",
"query": "tom和jerry"
}
}
}
当然们也可以像下面这样写
GET /christy/user/_search
{
"query": {
"query_string": {
"fields": ["address","introduce"],
"query": "tom和jerry"
}
}
}
这就实现了一个类似上面我们说的多字段查询。上面我们也说了这个可以指定分词器,可以像下面这样
GET /christy/user/_search
{
"query": {
"query_string": {
"fields": ["address","introduce"],
"query": "jerry华盛顿",
"analyzer": "ik_max_word"
}
}
}
这里我们除了标准分词器还没有安装其他分词器,上面我们提到的ik_max_word
下节我们再讲<( ̄▽ ̄)/