删除文档信息
想要删除文档信息其实很简单,只是使用 DELETE
方法即可。如下
查询文档信息
检索单条信息
使用HTTP GET 请求,并指定索引、类型和ID进行查询。如下
GET /learn/user/1
_primary_term_seq_no{ "_index" : "learn", "_type" : "user", "_id" : "1", "_version" : 2, "_seq_no" : 3, "_primary_term" : 1, "found" : true, "_source" : { "first_name" : "三", "last_name" : "张", "age" : 25, "about" : "法外狂徒", "interests" : [ "偷盗", "抢劫", "嘿嘿" ] } }
几个字段说明
- _version: 文档版本号,文档进行更新就会自增1
- _seq_no:序列号
- _primary_term:每当主分片发生重新分配时,比如重启,主分片的选举等,_primary_term会递增1。
_primary_term主要是用来恢复数据时处理当多个文档的_seq_no一样时的冲突,比如当一个shard宕机了,raplica需要用到最新的数据,就会根据_primary_term和_seq_no这两个值来拿到最新的document
有的喜欢在请求的查询串上加上pretty参数,如 GET /learn/user/1?pretty,这样只是为了让响应的信息更加可读。
当我们检索一个不存在的文档时,也会给我们返回一个结构体,但是该结构体中的found字段变为了false,同时HTTP响应也会变为 404 Not Found,而不是200 OK,如下所示
{ "_index" : "learn", "_type" : "user", "_id" : "5", "found" : false }
只检索_source字段
只需在请求后加上 _source 限制符即可。
GET /learn/user/1/_source
如我们只想要_source 字段中的某些字段,我们可以将请求改为
GET /learn/user/1/_source/?_source=age,about
检测文档是否存在
从上面我们已经知道,当查询不存在的文档时,HTTP响应会变为404。我们就可以根据这个返回的状态码来确定文档是否存在。
检索多条信息
使用mget
API来完成。
mget
API 要求有一个 docs
数组作为参数,每个元素包含需要检索文档的元数据, 包括 _index
、 _type
和 _id
。同时如果想要指定字段也可以使用source
来指定。
如我们取出learn索引下user的id为1和2的文档,可以写为
GET /_mget { "docs" : [ { "_index" : "learn", "_type" : "user", "_id" : 1 }, { "_index" : "learn", "_type" : "user", "_id" : 2, "_source": "about" } ] }
结果为
{ "docs" : [ { "_index" : "learn", "_type" : "user", "_id" : "1", "_version" : 2, "_seq_no" : 3, "_primary_term" : 1, "found" : true, "_source" : { "first_name" : "三", "last_name" : "张", "age" : 25, "about" : "法外狂徒", "interests" : [ "偷盗", "抢劫", "嘿嘿" ] } }, { "_index" : "learn", "_type" : "user", "_id" : "2", "_version" : 1, "_seq_no" : 1, "_primary_term" : 1, "found" : true, "_source" : { "about" : "基尼太美" } } ] }
也可以将索引和类型放在请求URL上,做到简写的目的,如下
GET /learn/user/_mget { "docs": [ { "_id": 1 }, { "_id": 2, "_source": "about" } ] }
结果同上面相同。
当然会出现多个文档中有部分文档不存在的情况,这时文档正常返回,状态码仍为200,但是查询不到的文档的found
字段显示为false
。
匹配查询 match,match_all
全搜索
最简单的搜索全部用户的请求:
GET /learn/user/_search { "query": { "match_all": {} } }
结果
{ "took" : 7, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "learn", "_type" : "user", "_id" : "2", "_score" : 1.0, "_source" : { "first_name" : "xk", "last_name" : "蔡", "age" : 99, "about" : "基尼太美", "interests" : [ "唱", "跳", "rap", "篮球" ] } }, { "_index" : "learn", "_type" : "user", "_id" : "3", "_score" : 1.0, "_source" : { "first_name" : "倍", "last_name" : "安", "age" : 10, "about" : "散弹枪狂热者", "interests" : [ "盗窃", "篮球" ] } }, { "_index" : "learn", "_type" : "user", "_id" : "1", "_score" : 1.0, "_source" : { "first_name" : "三", "last_name" : "张", "age" : 25, "about" : "法外狂徒", "interests" : [ "偷盗", "抢劫", "嘿嘿" ] } } ] } }
第一部分为:分片副本信息,第二部分 hits 包装的为查询的数据集。
参数解析:
- took
该命令请求花费了多长时间,单位:毫秒。 - timed_out
搜索是否超时。 - shards
搜索分片信息。 - total
搜索分片总数。 - successful
搜索成功的分片数量。 - skipped
没有搜索的分片,跳过的分片。 - failed
搜索失败的分片数量。 - hits
搜索结果集。项目中,我们需要的一切数据都是从hits中获取。 - total
返回多少条数据。 - max_score
返回结果中,最大的匹配度分值。 - hits
默认查询前十条数据,根据分值降序排序。 - _index
索引库名称。 - _type
类型名称。 - _id
该条数据的id。 - _score
关键字与该条数据的匹配度分值。匹配度越高分值就越高。 - _source
索引库中类型,返回结果字段,不指定的话,默认全部显示出来。
根据字段信息搜索
查询爱好中包含篮球的用户
GET /learn/user/_search { "query": { "match": { "interests.keyword": "篮球" } } }
结果
{ "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : 0.646255, "hits" : [ { "_index" : "learn", "_type" : "user", "_id" : "2", "_score" : 0.646255, "_source" : { "first_name" : "xk", "last_name" : "蔡", "age" : 99, "about" : "基尼太美", "interests" : [ "唱", "跳", "rap", "篮球" ] } }, { "_index" : "learn", "_type" : "user", "_id" : "3", "_score" : 0.646255, "_source" : { "first_name" : "倍", "last_name" : "安", "age" : 10, "about" : "散弹枪狂热者", "interests" : [ "盗窃", "篮球" ] } } ] } }
也可以不使用match匹配查询,而是进行查询字符串 (query-string) 搜索,通过一个URL参数来传递查询信息给搜索接口,如下
GET /learn/user/_search?q=interests:篮球
过滤查询 Filter
假如我们同样要找喜欢打篮球的,但是年龄大于50岁的。我们就可以利用 filter 将查询语句进行一些改变。如下
GET /learn/user/_search { "query": { "bool": { "filter": { "range": { "age": { "gt": 50 } } }, "must": { "match": { "interests.keyword": "篮球" } } } } }
这部分是一个 range 过滤器 , 它能找到年龄大于 30 的文档,其中 gt 表示_大于_(great than)。
结果为
{ "took" : 3, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 0.646255, "hits" : [ { "_index" : "learn", "_type" : "user", "_id" : "2", "_score" : 0.646255, "_source" : { "first_name" : "xk", "last_name" : "蔡", "age" : 99, "about" : "基尼太美", "interests" : [ "唱", "跳", "rap", "篮球" ] } } ] } }
短语搜索
我们再为learn索引添一条user文档。
PUT /learn/user/4 { "first_name" : "先森", "last_name" : "双口", "age" : 10, "about" : "散弹批发商", "interests": [ "嘿嘿","游戏" ] }
再进行匹配查询。查询条件为关于中包含散弹枪的。根据上面所说匹配查询,查询应该这么写
GET /learn/user/_search { "query" : { "match" : { "about" : "散弹枪" } } }
结果
_score{ "took" : 444, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : 2.3385136, "hits" : [ { "_index" : "learn", "_type" : "user", "_id" : "3", "_score" : 2.3385136, "_source" : { "first_name" : "倍", "last_name" : "安", "age" : 10, "about" : "散弹枪狂热者", "interests" : [ "盗窃", "篮球" ] } }, { "_index" : "learn", "_type" : "user", "_id" : "4", "_score" : 1.357075, "_source" : { "first_name" : "先森", "last_name" : "双口", "age" : 10, "about" : "散弹批发商", "interests" : [ "嘿嘿", "游戏" ] } } ] } }
这里查询到两个文档,一条是安的,一条是双口的。
但是我们发现两个文档中 _score 字段数字是不同的,_score 是Elasticsearch给查询出来的文档进行的相关性分析得出来的分数,这个分数越高说明匹配程度越高。我们搜索的是“散弹枪”,安的about中就含有“散弹枪”,但双口的about中包含的是“散弹”得分就比安低了。
我们有时候单纯的就只是想要搜索“散弹枪”这个词而不是“散”、“弹”、“枪”,这时候就要用到短语搜索了。
对 match 查询稍作调整,使用一个叫做 match_phrase 的查询,如下
GET /learn/user/_search { "query" : { "match_phrase" : { "about" : "散弹枪" } } }
结果
{ "took" : 19, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 2.3385136, "hits" : [ { "_index" : "learn", "_type" : "user", "_id" : "3", "_score" : 2.3385136, "_source" : { "first_name" : "倍", "last_name" : "安", "age" : 10, "about" : "散弹枪狂热者", "interests" : [ "盗窃", "篮球" ] } } ] } }
就只查询到含有“散弹枪”的文档了。
高亮搜索
许多应用都倾向于在每个搜索结果中 高亮 部分文本片段,以便让用户知道为何该文档符合查询条件。我们可以使用highlight 参数来实现,如下
GET /learn/user/_search { "query" : { "match" : { "about" : "散弹枪" } }, "highlight": { "fields" : { "about" : {} } } }
结果
{ "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : 2.3385136, "hits" : [ { "_index" : "learn", "_type" : "user", "_id" : "3", "_score" : 2.3385136, "_source" : { "first_name" : "倍", "last_name" : "安", "age" : 10, "about" : "散弹枪狂热者", "interests" : [ "盗窃", "篮球" ] }, "highlight" : { "about" : [ "<em>散</em><em>弹</em><em>枪</em>狂热者" ] } }, { "_index" : "learn", "_type" : "user", "_id" : "4", "_score" : 1.357075, "_source" : { "first_name" : "先森", "last_name" : "双口", "age" : 10, "about" : "散弹批发商", "interests" : [ "嘿嘿", "游戏" ] }, "highlight" : { "about" : [ "<em>散</em><em>弹</em>批发商" ] } } ] } }
几种重要的搜素
空搜索
简单的使用 _search ,不提供索引和类型,返回所有文档。
GET /_search
在搜索路径中使用通配符
在 gb
和 us
索引中搜索所有的文档
/gb,us/_search
在任何以 g
或者 u
开头的索引中搜索所有的类型
/g*,u*/_search
检索所有索引下的user
和tweet
类型的所有文档
/_all/user,tweet/_search
分页
主要是使用如下两个关键字。
size
显示应该返回的结果数量,默认是 10
from
显示应该跳过的初始结果数量,默认是 0
类似于关系型数据库中的Limit。
我们规定每页两条数据,则一到三页的数据可写为
GET /learn/user/_search?size=2 GET /learn/user/_search?size=2&from=2 GET /learn/user/_search?size=2&from=4
也可以写为请求体格式。如
GET /learn/user/_search { "size": 2, "from": 2 }
执行过后我们发现他会出现不是按照id分页的,这就涉及到了排序问题。后面会讲到。
exists查询和missing查询
类似于SQL中的IS_NULL(missing)和NOT IS_NULL(exists)。
这种查询经常用于某个字段有值的情况和某个字段缺值的情况。
{ "exists": { "field": "title" } }
区间查询
range
查询找出那些落在指定区间内的数字或者时间:
{ "range": { "age": { "gte": 20, "lt": 30 } } }
被允许的操作符如下:
gt
大于gte
大于等于lt
小于lte
小于等于
如果要实现等于或不等于的操作需要将两个操作符联合使用。