最近一段时间用户推荐开发,专门去调用去调研了elasticsearch
的基本用法。
es
中的text
类型的数据最让人奇怪,需要特别注意一下。
另外在7.0
版本之上,es
简化了type
的设计,默认使用_doc
类型,后续版本可能会删除type
的设计。
索引操作
1、查看索引
curl --location --request GET 'http://127.0.0.1:9200/member_minicity'
成功返回之后的结果类似下面内容,
aliases
下面的member_minicity2
,member_minicity3
都是别名,通过5、设置索引别名
的方式产生。
mappings
中properties
是当前的索引对应字段,settings
是索引的基本描述。
{
"member_minicity": {
"aliases": {
"member_minicity2": {},
"member_minicity3": {}
},
"mappings": {
"properties": {
"age": {
"type": "short"
},
"city": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 100
}
}
},
"member_id": {
"type": "long"
},
"member_status": {
"type": "short"
},
"province_id": {
"type": "short"
},
"sex": {
"type": "byte"
},
"unionid": {
"type": "keyword"
}
}
},
"settings": {
"index": {
"creation_date": "1624515549327",
"number_of_shards": "1",
"number_of_replicas": "1",
"uuid": "o69OTNTbQvCyI9dHeYSVKg",
"version": {
"created": "7050199"
},
"provided_name": "member_minicity"
}
}
}
}
2、创建索引
curl --location --request PUT 'http://127.0.0.1:9200/member_minicity' \
--header 'Content-Type: application/json' \
--data-raw '{
"mappings": {
"properties": {
"member_id": {
"type": "long"
}
}
}
}'
3、重建索引(同步数据)
curl --location --request POST 'http://127.0.0.1:9200/_reindex' \
--header 'Content-Type: application/json' \
--data-raw '{
"source": {
"index": "member_mini_city"
},
"dest": {
"index": "member_minicity"
}
}'
4、删除索引
curl --location --request DELETE 'http://127.0.0.1:9200/member_minicity'
5、设置索引别名
actions
中的index
为原始索引名称,alias
为新的索引名称。
curl --location --request POST 'http://127.0.0.1:9200/_aliases' \
--header 'Content-Type: application/json' \
--data-raw '{
"actions": [
{
"add": {
"index": "member_minicity",
"alias": "member_minicity2"
}
}
]
}'
查询说明
1、字符串类型
这里主要指的是text
和keyword
,text
和keyword
都可以用于表示字符串,text
前者会分词,keyword
完全匹配。
2、数字类型
使用时,尽量选择最小满足条件的类型。
3、对象类型
manager
类型下面包括了age
和name
字段,name
下面包括了first
和last
字段。
{
"mappings": {
"properties": {
"region": {
"type": "keyword"
},
"manager": {
"properties": {
"age": { "type": "integer" },
"name": {
"properties": {
"first": { "type": "text" },
"last": { "type": "text" }
}
}
}
}
}
}
}
es
中索引数据的方式,
{
"manager.age": "",
"manager.name.first": "",
"manager.name.last": ""
}
mapping
可以针对不同的字段进行不同的设置。
{
"mappings": {
"properties": {
"name": {
"type": "keyword"
},
"manager": {
"properties": {
"age": { "type": "integer" },
"name": {
"properties": {
"first": { "type": "text" },
"last": { "type": "text" }
}
}
}
}
}
}
}
注意: term是查询时对关键字不分词,keyword是索引时不分词。
如何让字段同时设置keyword
和text
属性?使用fields
扩展字段属性。
下面例子中的title
字段,使用fields
扩展title
的属性,使其同时具备keyword
和text
属性。
{
"settings": {
"index": {
"number_of_shards" : "2",
"number_of_replicas" : "0"
}
},
"mappings": {
"properties": {
"itemId" : {
"type": "keyword",
"ignore_above": 64
},
"title" : {
"type": "text",
"fields": {
"keyword" : {"ignore_above" : 256, "type" : "keyword"}
}
},
"desc" : {"type": "text", "analyzer": "ik_max_word"},
"num" : {"type": "integer"},
"price" : {"type": "long"}
}
}
}
实战演示
假设上面的例子中,title
初始化了值{"title": "苏泊尔煮饭SL3200"}
,因为使用了text
的类型来定义数据类型,所以title
会被分词处理,假设分成了{ "苏泊尔","煮饭", "sl3200", "sl","3200"}
中的多个字段,es
存储的方式也是存放的各个字段,而不是苏泊尔煮饭SL3200
完整字符串。
1、使用match
查询(精确查询)
如果要完整的匹配,只能使用fields
增加keyword
属性,搜素的时候需要显示的设置title.keyword
来查询,否则无法匹配到。
{
"query": {
"bool": {
"must": {
"match": {"title.keyword": "苏泊尔煮饭SL3200"}
}
}
}
}
2、使用match
查询(分词查询)
模糊查询会去对比分词集合中是不是有给出的关键字,比如下面的例子苏泊尔
,关键字在分词集合中存在,返回的结果中元字段_score
有评分。
{
"query": {
"bool": {
"must": {"match": {"title": "苏泊尔"}}
}
}
}
可以使用数组来替代,用于判断多个条件。
{
"query": {
"bool": {
"must": [{"match": {"title": "苏泊尔"}]}
}
}
}
3、使用term
查询(精确查询)
{
"query": {
"bool": {
"must": {
"term": {"title.keyword": "苏泊尔煮饭SL3200"}
}
}
}
}
terms
能够实现sql中的in的效果。
格式为:
{
"query": {
"terms": {
"{FIELD}": [
"{VALUE1}",
"{VALUE2}"
]
}
}
}
{FIELD} - 就是我们需要匹配的字段名 {VALUE1}, {VALUE2} .... {VALUE N} - 就是我们需要匹配的内容,除了TEXT类型字段以外的任意类型。
{
"query": {
"bool": {
"must": {
"terms": { "shop_id": [123,100,300]}
}
}
}
}
4、范围查询
查询范围参数说明,
gt - 大于 ( > )
gte - 大于且等于 ( >= )
lt - 小于 ( < )
lte - 小于且等于 ( <= )
基本格式,
{
"query": {
"range": {
"{FIELD}": {
"gte": 10,
"lte": 20
}
}
}
}
5、bool组合查询
基本语法格式如下,上面的说的match
,term
,range
都可以放到must
,must_not
,should
中。
{
"query": {
"bool": { // bool查询
"must": [], // must条件,类似SQL中的and, 代表必须匹配条件
"must_not": [], // must_not条件,跟must相反,必须不匹配条件
"should": [] // should条件,类似SQL中or, 代表匹配其中一个条件
}
}
}
示例:
{
"query": {
"bool": {
"must": [
{
"term": {
"order_no": "202003131209120999"
}
},
{
"term": {
"shop_id": 123
}
}]
},
"must_not": [
{
"term": {
"shop_id": 1
}
},
{
"term": {
"shop_id": 2
}
}
],
"should": [
{
"match": {
"order_no": "202003131209120999"
}
},
{
"match": {
"order_no": "22222222222222222"
}
}
]
}
}
}
bool
和should
,must
之间可以互相嵌套,如下例子,
GET /order_v2/_search
{
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{
"term": {
"order_no": "2020031312091209991"
}
},
{
"range": {
"shop_id": {
"gte": 10,
"lte": 200
}
}
}
]
}
},
{
"terms": {
"tag": [
1,
2,
3,
4,
5,
12
]
}
}
]
}
}
}
切换成sql可以是,
select * from order_v2 where (order_no='202003131209120999' and (shop_id>=10 and shop_id<=200)) or tag in (1,2,3,4,5)
总结一下,
1、must
,must_not
,should
都使用数组的方式,确保能够灵活增加多个查询条件。
2、must
,must_not
,should
接收的查询条件可以通过term
、terms
、match
、range
等来表示。
3、对于分词查询的字段即设置成text
属性的字段,可以通过fields
来设置keyword
以便能够通过term
条件来精确匹配。
补充查询
1、获取所有
GET /ad/phone/_search
{
"query": {
"match_all": {}
}
}
2、分页
GET /ad/phone/_search
{
"query": {
"match_all": {}
},
"from": 1,
"size": 2
}
这种分页方式如果进行深度分页,比如到100页,每页十条数据,它会从每个分片都查询出100*10条数据,假设有五个分片,就是5000条数据,然后在内存中进行排序,然后返回拍过序之后的集合中的第1000-1010条数据
3、指定查询出来的数据返回的字段
GET /ad/phone/_search
{
"query": {
"match_all": {}
},
"_source": ["name","price"]
}
4、排序
GET /ad/phone/_search
{
"query": {
"match": {
"ad": "white"
}
},
"sort": [
{
"price": {
"order": "asc"
}
}
]
}
5、使用filter不会计算评分
返回的结果中元字段_score
字段等于0,没评分,说明使用filter不会计算评分。
GET /ad/phone/_search
{
"query": {
"bool": {
"filter": {
"range": {
"price": {
"gt": 5000
}
}
}
}
}
}
6、分词匹配逻辑控制
使用operator
来选择and
或者or
,
match 查询还可以接受 operator 操作符作为输入参数,默认情况下该操作符是or
,只要匹配其中的一个分词就可以搜索到。我们可以将它修改成 and 让所有指定词项都必须匹配。
GET /ad/phone/_search
{
"query": {
"match": {
"ad": {
"query": "a red",
"operator": "and"
}
}
}
}
match 查询支持 minimum_should_match 最小匹配参数, 可以指定必须匹配的词项数用来表示一个文档是否相关。 我们可以将其设置为某个具体数字(指需要匹配倒排索引的词的数量),更常用的做法是将其设置为一个百分数,因为我们无法控制用户搜索时输入的单词数量。 只会返回匹配上a和red两个词的文档返回,如果minimum_should_match是1,则只要匹配上其中一个词,文档就会返回。
GET /ad/phone/_search
{
"query": {
"match": {
"ad": {
"query": "a red",
"minimum_should_match": "2"
}
}
}
}
7、multi_match查询
多字段查询,比如查询color
和ad
字段包含单词red的文档。
GET /ad/phone/_search
{
"query": {
"multi_match": {
"query": "red",
"fields": ["color","ad"]
}
}
}
8、有值或者无值查询,exists 查询和 missing 查询
指定name字段有值:
GET /ad/phone/_search
{
"query": {
"bool": {
"filter": {
"exists": {
"field": "name"
}
}
}
}
}
指定name字段无值:
GET /ad/phone/_search
{
"query": {
"bool": {
"filter": {
"missing": {
"field": "name"
}
}
}
}
}