前言
单独写一期关于查询的内容。主要是因为es的数据检索几乎是最重要的部分,也因为这一块的文档资料有限、可参考的例子也不多,查询的语法规则也不像 SQL语句那样具有公认的标准化的语法。就不容易入手。
目录
- 1、建立索引、准备一些测试的数据
- 2、查询API 的说明
- 3、Query 查询
- 4、FIlter 查询
- 5、更多的例子
一、建立索引,准备数据
字段名 | 字段含义 | 类型 | 是否能被索引 |
---|---|---|---|
studentNo | 学号 | keyword | 是 |
name | 姓名 | keyword | 是 |
sex | 性别 | keyword | 是 |
age | 年龄 | integer | 是 |
birthday | 出生年月 | date | 是 |
address | 家庭住址 | text | 是 |
classNo | 班级 | keyword | 是 |
isLeader | 是否为班干部 | boolean | 是 |
interests | 兴趣描述 | text | 是 |
- 创建索引,设置_settings和_mapping
类型说明、参考文档 https://www.elastic.co/guide/en/elasticsearch/reference/7.6/mapping.html#field-datatypes
可 使用确切的mapping字段描述创建index
可 向已有的mapping中添加字段
不可 修改已有的字段的数据类型(会导致已有数据条目的类型不匹配),建议重建索引,数据导过去
不可 修改已有的字段的数据名称 ,建议新建字段,用alias name的方式
(后面测试查询中很多关系到keyword和分词的问题,所以在建立索引前一定要考虑清楚数据类型和分词的使用)
一些常用的查询
GET /test_student
GET /test_student/_settings
GET /test_student/_mapping
GET /test_student/_count
GET /test_student/_search
PUT /test_student
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"studentNo": {"type": "keyword"},
"name": {"type": "keyword" },
"male": { "type": "keyword"},
"age": { "type": "integer"},
"birthday": {"type": "date", "format": "yyyy-MM-dd"},
"address": { "type": "text"},
"classNo": {"type": "keyword"},
"isLeader": {"type": "boolean"},
"interests":{"type": "text"}
}
}
}
- 插入准备的数据
studentNo | name | male | age | birthday | classNo | address | isLeader | interests |
---|---|---|---|---|---|---|---|---|
1 | 刘备 | 男 | 24 | 1985-02-03 | 1 | 湖南省长沙市 | true | 喜欢打篮球、唱歌 |
2 | 关羽 | 男 | 22 | 1987-08-23 | 2 | 四川省成都市 | false | 喜欢游泳和跑步,经常撸铁 |
3 | 糜夫人 | 女 | 19 | 1990-06-12 | 1 | 上海市 | false | 会一点日语,书法很好 |
4 | 张飞 | 男 | 20 | 1989-07-30 | 3 | 北京市 | false | 经常钓鱼,喜欢打篮球 |
5 | 诸葛亮 | 男 | 18 | 1992-04-27 | 2 | 江苏省南京市 | true | 喜欢下象棋围棋,偶尔撸铁书法贼溜 |
6 | 孙尚香 | 女 | 16 | 1994-05-21 | 3 | false | cosplay爱好者,精通日语 | |
7 | 马超 | 男 | 19 | 1991-10-20 | 1 | 黑龙江省哈尔滨市 | false | 喜欢高尔夫和马术,偶尔钓鱼 |
8 | 赵云 | 男 | 23 | 1986-10-26 | 2 | 浙江省杭州市 | false | 马术贼溜, 撸铁大师 |
POST /test_student/_doc/
{
"studentNo":1,
"name":"刘备",
"male":"男",
"age": 32,
"birthday":"1988-03-28",
"address":"湖南省长沙市",
"classNo":"1",
"isLeader": true,
"interests":"喜欢打篮球、唱歌"
}
POST /test_student/_doc/
{
"studentNo":2,
"name":"关羽",
"male":"男",
"age": 30,
"birthday":"1990-07-18",
"address":"四川省成都市",
"classNo":"1",
"isLeader": false,
"interests":"喜欢打游泳和跑步,经常撸铁"
}
POST /test_student/_doc/
{
"studentNo":3,
"name":"糜夫人",
"male":"女",
"age": 19,
"birthday":"2001-11-10",
"address":"上海市",
"classNo":"1",
"isLeader": false,
"interests":"会一点点日语,书法很好"
}
POST /test_student/_doc/
{
"studentNo":4,
"name":"张飞",
"male":"男",
"age": 20,
"birthday":"2000-02-08",
"address":"北京市",
"classNo":"3",
"isLeader": false,
"interests":"经常钓鱼,喜欢打篮球"
}
POST /test_student/_doc/
{
"studentNo":5,
"name":"诸葛亮",
"male":"男",
"age": 19,
"birthday":"2001-09-28",
"address":"江苏省南京市",
"classNo":"2",
"isLeader": true,
"interests":"喜欢下象棋围棋,偶尔撸铁,书法贼溜"
}
POST /test_student/_doc/
{
"studentNo":6,
"name":"孙尚香",
"male":"女",
"age": 16,
"birthday":"2004-06-18",
"address":"湖南省长沙市",
"classNo":"3",
"isLeader": false,
"interests":"cosplay爱好者,精通日语"
}
POST /test_student/_doc/
{
"studentNo":7,
"name":"马超",
"male":"男",
"age": 19,
"birthday":"2001-03-28",
"address":"黑龙江哈尔滨",
"classNo":"1",
"isLeader": false,
"interests":"喜欢高尔夫和钓鱼,偶尔钓鱼"
}
POST /test_student/_doc/
{
"studentNo":8,
"name":"赵云",
"male":"男",
"age": 23,
"birthday":"1997-05-05",
"address":"浙江杭州市",
"classNo":"2",
"isLeader": false,
"interests":"马术贼溜,撸铁大师"
}
二、查询API 的说明
(摘抄,感觉查询语法并不友好)
ES中的查询非常灵活,为用户提供了非常方便而强大的API。个人觉得ES的调用接口设计得非常好,所有接口合理且风格一致,值得好好研究!
Query和Filter
ES为用户提供两类查询API,一类是在查询阶段就进行条件过滤的query查询,另一类是在query查询出来的数据基础上再进行过滤的filter查询。这两类查询的区别是:
query方法会计算查询条件与待查询数据之间的相关性,计算结果写入一个score字段,类似于搜索引擎。filter仅仅做字符串匹配,不会计算相关性,类似于一般的数据查询,所以filter得查询速度比query快。
filter查询出来的数据会自动被缓存,而query不能。
query和filter可以单独使用,也可以相互嵌套使用,非常灵活。
Query查询
下面的情况下适合使用query查询:
需要进行全文搜索。
查询结果依赖于相关性,即需要计算查询串和数据的相关性。
三、query查询的各种方式
term/terms查询、range查询、bool查询、prefix查询、wildcard查询、regexp查询。以及广泛的bool嵌套
#================查询=========================
POST /test_student/_search
{
"query": {"match_all": {}}
}
POST /test_student/_search
{
"query": {"match_all": {}},
"from": 2,
"size": 5,
"sort":
{
"classNo": {"order": "asc"},
"birthday": {"order": "desc"}
}
}
# term 精确查询,对未分词的字段 匹配值
POST /test_student/_search
{
"query": {
"term": {
"name": {
"value": "诸葛亮"
}
}
}
}
POST /test_student/_search
{
"query": {
"term": {
"name": "诸葛亮"
}
}
}
POST /test_student/_search
{
"query": {
"terms": {
"name": [
"诸葛亮",
"孙尚香"
]
}
}
}
POST /test_student/_search
{
"query": {
"terms": {
"interests": [
"篮球",
"撸铁"
]
}
}
}
POST /test_student/_search
{
"query": {
"terms": {
"address": [
"江苏省南京市",
"北京市"
]
}
}
}
# bool查询 ,主要用于复合查询中,含有三类 ,must ,should, must_not ,决定结果的筛选 必须满足、部分满足条件
POST /test_student/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"classNo": 3
}
},
{
"term": {
"male" : "女"
}
}
]
}
}
}
# [term] query doesn't support multiple fields ...
POST /test_student/_search
{
"query": {
"term": {
"classNo": 3,
"male":"女"
}
}
}
# ids 查询, 查询某个索引下的指定 _id 值(默认是自己生成的那个序号)
POST /test_student/_search
{
"query": {
"ids": {
"type": "_doc",
"values": ["FkkrSnUBlOj8Ks4LAS7U", "F0kzSnUBlOj8Ks4Lri5D"]
}
}
}
POST /test_student/_search
{
"query": {
"ids": {
"values": ["FkkrSnUBlOj8Ks4LAS7U", "F0kzSnUBlOj8Ks4Lri5D"]
}
}
}
# prefix 前缀匹配
POST /test_student/_search
{
"query": {
"prefix": {
"name": {
"value": "赵"
}
}
}
}
POST /test_student/_search
{
"query": {
"bool": {
"should": [
{
"prefix": {
"name": "刘"
}
},
{
"prefix": {
"name": "关"
}
},
{
"prefix": {
"name": "张"
}
},
{
"prefix": {
"name": {
"value": "诸葛"
}
}
}
]
}
}
}
POST /test_student/_search
{
"query": {
"prefix": {
"address": {
"value": "湖"
}
}
}
}
# 不清楚为什么 text类型的数据 前缀匹配,中文只能匹配一个字
# keyword 类型就能匹配多个字, 也许和分词器有关系
POST /test_student/_search
{
"query": {
"prefix": {
"address": {
"value": "湖南"
}
}
}
}
# range 查询, 查找范围值
POST /test_student/_search
{
"query": {
"range": {
"age": {
"gte": 20,
"lte": 24
}
}
},
"sort": [
{
"age": {
"order": "desc"
}
}
]
}
POST /test_student/_search
{
"query": {
"range": {
"birthday": {
"gte": "1995-01-01",
"lte": "2002-01-01"
}
}
},
"sort":
{
"age": {"order": "asc" },
"classNo": {"order": "asc" }
}
}
# Wildcard 简化的正则查询, 使用两个通配符 * 代表任意(包括0个)多个字符 ? 代表任意一个字符
POST /test_student/_search
{
"query": {
"wildcard": {
"name": {
"value": "*亮"
}
}
}
}
POST /test_student/_search
{
"query": {
"wildcard": {
"name": {
"value": "诸葛*"
}
}
}
}
POST /test_student/_search
{
"query": {
"wildcard": {
"name": {
"value": "诸葛*"
}
}
}
}
# text 类型的对字符串的前后缀匹配都不怎么好事, 默认分词器 分成了全部单一的汉字
POST /test_student/_search
{
"query": {
"wildcard": {
"interests": {
"value": "*铁*"
}
}
}
}
POST /test_student/_search
{
"query": {
"wildcard": {
"interests": {
"value": "*撸铁*"
}
}
}
}
POST /test_student/_search
{
"query": {
"wildcard": {
"name": "???"
}
}
}
# regx 正则查询,最完整的串匹配规则
POST /test_student/_search
{
"query": {
"regexp": {
"address": "湖南*"
}
}
}
POST /test_student/_search
{
"query": {
"regexp": {
"address": "湖南省*"
}
}
}
POST /test_student/_search
{
"query": {
"regexp": {
"address": "*长沙*"
}
}
}
POST /test_student/_search
{
"query": {
"regexp": {
"address": "*长*"
}
}
}
POST /test_student/_search
{
"query": {
"wildcard": {
"interests": "cosplay*"
}
}
}
POST /test_student/_search
{
"query": {
"regexp": {
"interests": "cosplay*"
}
}
}
POST /test_student/_search
{
"query": {
"wildcard": {
"interests": "cos*"
}
}
}
POST /test_student/_search
{
"query": {
"regexp": {
"interests": "c*"
}
}
}
POST /test_student/_search
{
"query": {
"wildcard": {
"name": "孙*"
}
}
}
POST /test_student/_search
{
"query": {
"regexp": {
"name": "孙尚*"
}
}
}
POST /test_student/_search
{
"query": {
"regexp": {
"name": "孙尚香*"
}
}
}
# 关于 filter 的查询, 把上面query 换成filter就行 ,不重复写了,可以附带_cache 来提高效率
五、更多的例子
# 更多的例子####################################
# 查询年龄大于二十的人
# 查询年龄大于二十的男性
# 查询三班的男生
# 查询小于20岁的领导
# 查询名字只有两个字的人
# 查询兴趣包含撸铁的人
# 查询兴趣包含撸铁和跑步的人
# 查询兴趣包含撸铁或跑步的人
# 查询住址 符合××省××市的格式的人
# 查询住址在湖南的人
POST /test_student/_search
{
"query": {
"range": {
"age": {
"gte": 20,
"lte": 100
}
}
}
}
POST /test_student/_search
{
"query": {
"bool": {
"must": [
{
"range": {
"age": {
"gte": 20,
"lte": 100
}
}
},
{
"term": {
"male": "男"
}
}
]
}
}
}
POST /test_student/_search
{
"query": {
"bool": {
"must": [
{
"term":{
"classNo": 3
}
},
{
"term": {
"male": "男"
}
}
]
}
}
}
POST /test_student/_search
{
"query": {
"bool": {
"must": [
{
"range": {
"age": {
"gte": 0,
"lte": 20
}
}
},
{
"term": {
"isLeader": true
}
}
]
}
}
}
POST /test_student/_search
{
"query":{
"wildcard": {
"name": {
"value": "??"
}
}
}
}
# 分词器的原因, 撸铁查不到
POST /test_student/_search
{
"query": {
"wildcard": {
"interests": {
"value": "*撸*"
}
}
}
}
POST /test_student/_search
{
"query": {
"bool": {
"must": [
{
"wildcard": {
"interests": {
"value": "*撸*"
}
}
},
{
"wildcard": {
"interests": {
"value": "*跑*"
}
}
}
]
}
}
}
POST /test_student/_search
{
"query": {
"bool": {
"should": [
{
"wildcard": {
"interests": {
"value": "*撸*"
}
}
},
{
"wildcard": {
"interests": {
"value": "*跑*"
}
}
}
]
}
}
}
# 分词器的原因,查不出来, 需要使用bool嵌套(一度怀疑分词器有什么破用处。。。)
POST /test_student/_search
{
"query": {
"wildcard": {
"address": {
"value": "*省*市"
}
}
}
}
POST /test_student/_search
{
"query": {
"bool": {
"must": [
{
"wildcard": {
"address": {
"value": "*省*"
}
}
},
{
"wildcard": {
"address": {
"value": "*市"
}
}
}
]
}
}
}
POST /test_student/_search
{
"query": {
"regexp": {
"address": ".*湖南.*"
}
}
}
POST /test_student/_search
{
"query": {
"regexp": {
"address": ".*湖.*"
}
}
}
网友评论