前言
目前正在出一个Es专题
系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~
承接上文,把上节剩下的部分给大家整一下, 本节带大家学习一下文档查询API
基本操作。
本文偏实战一些,好了, 废话不多说直接开整吧~
查询文档 & 基本操作
为了方便学习, 本节中所有示例沿用上节的索引
按照ID单个
GET class_1/_doc/1 复制代码
查询结果:
{ "_index" : "class_1", "_type" : "_doc", "_id" : "1", "_version" : 4, "_seq_no" : 4, "_primary_term" : 3, "found" : true, "_source" : { "name" : "l", "num" : 6 } } 复制代码
按照ID批量
GET class_1/_mget { "ids":[1,2,3] } 复制代码
返回:
{ "docs" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "1", "_version" : 4, "_seq_no" : 4, "_primary_term" : 3, "found" : true, "_source" : { "name" : "l", "num" : 6 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "2", "found" : false }, { "_index" : "class_1", "_type" : "_doc", "_id" : "3", "_version" : 3, "_seq_no" : 10, "_primary_term" : 4, "found" : true, "_source" : { "num" : 9, "name" : "e", "age" : 9, "desc" : [ "hhhh" ] } } ] } 复制代码
查询文档是否存在 & 通过id判断
HEAD class_1/_doc/1 复制代码
返回:
200 - OK 复制代码
HEAD class_1/_doc/1000 复制代码
返回:
404 - Not Found 复制代码
查询部分字段内容
GET class_1/_doc/1?_source_includes=name 复制代码
返回:
{ "_index" : "class_1", "_type" : "_doc", "_id" : "1", "_version" : 4, "_seq_no" : 4, "_primary_term" : 3, "found" : true, "_source" : { "name" : "l" } } 复制代码
可以看到只返回了name
字段, 以上是一个基本的操作,下面给大家讲下条件查询
~
查询文档 & 条件查询
查询的复杂度取决于它附加的条件约束,跟我们写sql
一样。下面就带大家一步一步看一下ES
中如何进行条件查询~
不附加任何条件
GET class_1/_search 复制代码
返回:
{ "took" : 15, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 8, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "h2Fg-4UBECmbBdQA6VLg", "_score" : 1.0, "_source" : { "name" : "b", "num" : 6 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "iGFt-4UBECmbBdQAnVJe", "_score" : 1.0, "_source" : { "name" : "g", "age" : 8 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "iWFt-4UBECmbBdQAnVJg", "_score" : 1.0, "_source" : { "name" : "h", "age" : 9 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "imFt-4UBECmbBdQAnVJg", "_score" : 1.0, "_source" : { "name" : "i", "age" : 10 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "3", "_score" : 1.0, "_source" : { "num" : 9, "name" : "e", "age" : 9, "desc" : [ "hhhh" ] } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "4", "_score" : 1.0, "_source" : { "name" : "f", "age" : 10, "num" : 10 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "RWlfBIUBDuA8yW5cu9wu", "_score" : 1.0, "_source" : { "name" : "一年级", "num" : 20 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "1", "_score" : 1.0, "_source" : { "name" : "l", "num" : 6 } } ] } } 复制代码
可以看到索引class_1
中的所有数据都是上节添加的。这里提一下,我们也可以添加多个索引一起查,然后返回,用,逗号
隔开就可以了
GET class_1,class_2,class_3/_search 复制代码
{ "took" : 7, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 9, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "h2Fg-4UBECmbBdQA6VLg", "_score" : 1.0, "_source" : { "name" : "b", "num" : 6 } }, { "_index" : "class_2", "_type" : "_doc", "_id" : "RWlfBIUBDuA8yW5cu9wu", "_score" : 1.0, "_source" : { "name" : "一年级", "num" : 20 } }, .... ] } } 复制代码
可以看到返回了索引class_2
中的数据,并且合并到了一起。
相关字段解释
有的小伙伴可能对返回的字段有点陌生,这里给大家统一解释一下:
{ "took":"查询操作耗时,单位毫秒", "timed_out":"是否超时", "_shards":{ "total":"分片总数", "successful":"执行成功分片数", "skipped":"执行忽略分片数", "failed":"执行失败分片数" }, "hits":{ "total":{ "value":"条件查询命中数", "relation":"计数规则(eq计数准确/gte计数不准确)" }, "max_score":"最大匹配度分值", "hits":[ { "_index":"命中结果索引", "_id":"命中结果ID", "_score":"命中结果分数", "_source":"命中结果原文档信息" } ] } } 复制代码
下面我们看下带条件的查询~
基础分页查询
基本语法: es
中通过参数size
和from
来进行基础分页
的控制
from
:指定跳过
多少条数据size
:指定返回
多少条数据
下面看下示例:
url参数
GET class_1/_search?from=2&size=2 复制代码
返回:
{ "took" : 5, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 8, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "iWFt-4UBECmbBdQAnVJg", "_score" : 1.0, "_source" : { "name" : "h", "age" : 9 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "imFt-4UBECmbBdQAnVJg", "_score" : 1.0, "_source" : { "name" : "i", "age" : 10 } } ] } } 复制代码
body 参数
GET class_1/_search { "from" : 2, "size" : 2 } 复制代码
返回结果和上面是一样的~
单字段全文索引查询
这个大家应该不陌生,前面几节都见过。使用query.match
进行查询,match
适用与对单个字段基于全文索引
进行数据检索。对于全文字段,match
使用特定的分词
进行全文检索
。而对于那些精确值,match
同样可以进行精确匹配
,match
查询短语时,会对短语进行分词
,再针对每个词条
进行全文检索
。
GET class_1/_search { "query": { "match": { "name":"i" } } } 复制代码
返回:
{ "took" : 4, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 1.3862942, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "imFt-4UBECmbBdQAnVJg", "_score" : 1.3862942, "_source" : { "name" : "i", "age" : 10 } } ] } } 复制代码
单字段不分词查询
使用query.match_phrase
进行查询, 它与match
的区别就是不进行分词
,干说,可能有点抽象,下面我们通过一个例子给大家分清楚:
先造点数据进去:
PUT class_1/_bulk { "create":{ } } {"name":"I eat apple so haochi1~","num": 1} { "create":{ } } { "name":"I eat apple so zhen haochi2~","num": 1} { "create":{ } } {"name":"I eat apple so haochi3~","num": 1} 复制代码
假设有这么几个句子,现在我有一个需求我要把I eat apple so zhen haochi2~
这句话匹配出来
match分词结果
GET class_1/_search { "query": { "match": { "name": "apple so zhen" } } } 复制代码
返回:
{ "took" : 15, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 2.2169428, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "cMfcCoYB090miyjed7YE", "_score" : 2.2169428, "_source" : { "name" : "I eat apple so zhen haochi2~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "b8fcCoYB090miyjed7YE", "_score" : 1.505254, "_source" : { "name" : "I eat apple so haochi1~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "ccfcCoYB090miyjed7YE", "_score" : 1.505254, "_source" : { "name" : "I eat apple so haochi3~", "num" : 1 } } ] } } 复制代码
从结果来看,刚刚的几句话都被查出来了,但是结果并大符合预期。从score
来看,"_score" : 2.2169428
得分最高,排在了第一,语句是I eat apple so zhen haochi2~
,说明匹配度最高,这个句子正是我们想要的结果~
match_phrase 不分词查询结果
GET class_1/_search { "query": { "match_phrase": { "name": "apple so zhen" } } } 复制代码
结果:
{ "took" : 6, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 2.2169428, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "cMfcCoYB090miyjed7YE", "_score" : 2.2169428, "_source" : { "name" : "I eat apple so zhen haochi2~", "num" : 1 } } ] } } 复制代码
结果符合预期,只返回了我们想要的那句。那么match
为什么都返回了,这就是前面讲到的分词
,首先会对name: apple so zhen
进行分词,也就是说存在apple
的都会被返回。
当然,真正业务中的需求比这个复杂多了,这里只是为了给大家做区分~ 下面接着看~
多字段全文索引查询
相当于对多个字段执行了match
查询, 这里需要注意的是query
的类型要和字段类型一致,不然会报类型异常
GET class_1/_search { "query": { "multi_match": { "query": "apple", "fields": ["name","desc"] } } } 复制代码
{ "took" : 5, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 0.752627, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "b8fcCoYB090miyjed7YE", "_score" : 0.752627, "_source" : { "name" : "I eat apple so haochi1~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "ccfcCoYB090miyjed7YE", "_score" : 0.752627, "_source" : { "name" : "I eat apple so haochi3~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "cMfcCoYB090miyjed7YE", "_score" : 0.7389809, "_source" : { "name" : "I eat apple so zhen haochi2~", "num" : 1 } } ] } } 复制代码
范围查询
使用range
来进行范围查询,适用于数组
,时间
等字段
GET class_1/_search { "query": { "range": { "num": { "gt": 5, "lt": 10 } } } } 复制代码
返回:
{ "took" : 6, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "h2Fg-4UBECmbBdQA6VLg", "_score" : 1.0, "_source" : { "name" : "b", "num" : 6 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "3", "_score" : 1.0, "_source" : { "num" : 9, "name" : "e", "age" : 9, "desc" : [ "hhhh" ] } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "1", "_score" : 1.0, "_source" : { "name" : "l", "num" : 6 } } ] } } 复制代码
单字段精确查询
使用term
进行非分词字段
的精确查询。需要注意的是,对于那些分词的字段,即使查询的value
是一个完全匹配的短语,也无法完成查询
GET class_1/_search { "query": { "term": { "num": { "value": "9" } } } } 复制代码
返回:
{ "took" : 4, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "3", "_score" : 1.0, "_source" : { "num" : 9, "name" : "e", "age" : 9, "desc" : [ "hhhh" ] } } ] } } 复制代码
字段精确查询 & 多值
与term一样, 区别在于可以匹配一个字段的多个值,满足一个即检索成功
GET class_1/_search { "query": { "terms": { "num": [ 9, 1 ] } } } 复制代码
返回:
{ "took" : 8, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 4, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "3", "_score" : 1.0, "_source" : { "num" : 9, "name" : "e", "age" : 9, "desc" : [ "hhhh" ] } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "b8fcCoYB090miyjed7YE", "_score" : 1.0, "_source" : { "name" : "I eat apple so haochi1~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "ccfcCoYB090miyjed7YE", "_score" : 1.0, "_source" : { "name" : "I eat apple so haochi3~", "num" : 1 } }, { "_index" : "class_1", "_type" : "_doc", "_id" : "cMfcCoYB090miyjed7YE", "_score" : 1.0, "_source" : { "name" : "I eat apple so zhen haochi2~", "num" : 1 } } ] } } 复制代码
文档包含字段查询
为了确定当前索引有哪些文档包含了对应的字段,es
中使用exists
来实现
GET class_1/_search { "query": { "exists": { "field": "desc" } } } 复制代码
返回:
{ "took" : 8, "timed_out" : false, "_shards" : { "total" : 3, "successful" : 3, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "class_1", "_type" : "_doc", "_id" : "3", "_score" : 1.0, "_source" : { "num" : 9, "name" : "e", "age" : 9, "desc" : [ "hhhh" ] } } ] } } 复制代码
结束语
本节主要讲了ES
中的文档查询API
操作,该部分内容较多, 下节继续给大家讲,就先消化这么多~API
大家都不要去背,多敲几遍就记住了,关键是多用,多总结 。