目录
请求参数的查询(QueryString)
GET /shop/_doc/_search?q=desc:慕课网
GET /shop/_doc/_search?q=nickname:慕&q=age:25
DSL基本语法
语法格式为一个json object,内容都是key-value键值对,json可以嵌套。
key可以是一些es的关键字,也可以是某个field字段,后面会遇到
# 查询
POST /shop/_doc/_search
{
"query": {
"match": {
"desc": "慕课网"
}
}
}
# 判断某个字段是否存在
{
"query": {
"exists": {
"field": "desc"
}
}
}
1.分页
POST /shop/_doc/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 10
}
{
"query": {
"match_all": {}
},
"_source": [
"id",
"nickname",
"age"
],
"from": 5, 从第几条数据开始
"size": 5 数据的大小
}
2.term精确搜索与match分词搜索
- 注:match会对慕课网先进行分词(其实就是全文检索),在查询,而term则不会,直接把慕课网作为一个整的词汇去搜索。
POST /shop/_doc/_search
{
"query": {
"term": {
"desc": "慕课网"
}
}
}
对比
{
"query": {
"match": {
"desc": "慕课网"
}
}
}
4.terms 多个词语匹配检索
相当于是tag标签查询,比如慕课网的一些课程会打上前端/后端/大数据/就业课这样的标签,可以完全匹配做类似标签的查询
POST /shop/_doc/_search
{
"query": {
"terms": {
"desc": ["慕课网", "学习", "骚年"]
}
}
}
5.match_phrase 短语匹配
match:分词后只要有匹配就返回,match_phrase:分词结果必须在text字段分词中都包含,而且顺序必须相同,而且必须都是连续的。(搜索比较严格)
slop:允许词语间跳过的数量
POST /shop/_doc/_search
{
"query": {
"match_phrase": {
"desc": {
"query": "大学 毕业 研究生",
"slop": 2
}
}
}
}
6.match(operator)/ids
- or:搜索内容分词后,只要存在一个词语匹配就展示结果
- and:搜索内容分词后,都要满足词语匹配
POST /shop/_doc/_search { "query": { "match": { "desc": "慕课网" } } } # 等同于 { "query": { "match": { "desc": { "query": "xbox游戏机", "operator": "or" } } } } # 相当于 select * from shop where desc='xbox' or|and desc='游戏机'
minimum_should_match: 最低匹配精度,至少有[分词后的词语个数]x百分百,得出一个数据值取整。举个例子:当前属性设置为70,若一个用户查询检索内容分词后有10个词语,那么匹配度按照 10x70%=7,则desc中至少需要有7个词语匹配,就展示;若分词后有8个,则 8x70%=5.6,则desc中至少需要有5个词语匹配,就展示。
POST /shop/_doc/_search { "query": { "match": { "desc": { "query": "女友生日送我好玩的xbox游戏机", "minimum_should_match": "60%" } } } }
根据文档主键ids搜索
-
POST /shop/_doc/_search { "query": { "ids": { "type": "_doc", "values": ["1001", "1010", "1008"] } } }
7- multi_match/boost(权重)
满足使用match在多个字段中进行查询的需求
POST /shop/_doc/_search
{
"query": {
"multi_match": {
"query": "皮特帕克慕课网",
"fields": ["desc", "nickname"]
}
}
}
boost:权重,为某个字段设置权重,权重越高,文档相关性得分就越高。通畅来说搜索商品名称要比商品简介的权重更高。
POST /shop/_doc/_search
{
"query": {
"multi_match": {
"query": "皮特帕克慕课网",
"fields": ["desc", "nickname^10"]
}
}
}
nickname^10 代表搜索提升10倍相关性,也就是说用户搜索的时候其实以这个nickname为主,desc为辅,nickname的匹配相关度当然要提高权重比例了。
8.布尔查询:可以组合多重查询
- must:查询必须匹配搜索条件,譬如 and
- should:查询匹配满足1个以上条件,譬如 or
- must_not:不匹配搜索条件,一个都不要满足
POST /shop/_doc/_search { "query": { "bool": { "must": [ { "multi_match": { "query": "慕课网", "fields": ["desc", "nickname"] } }, { "term": { "sex": 1 } }, { "term": { "birthday": "1996-01-14" } } ] } } } { "query": { "bool": { "should(must_not)": [ { "multi_match": { "query": "学习", "fields": ["desc", "nickname"] } }, { "match": { "desc": "游戏" } }, { "term": { "sex": 0 } } ] } } }
为指定词语加权
POST /shop/_doc/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"desc": {
"query": "律师",
"boost": 18
}
}
},
{
"match": {
"desc": {
"query": "进修",
"boost": 2
}
}
}
]
}
}
}
9.过滤器
对搜索出来的结果进行数据过滤。不会到es库里去搜,不会去计算文档的相关度分数,所以过滤的性能会比较高,过滤器可以和全文搜索结合在一起使用。
post_filter元素是一个顶层元素,只会对搜索结果进行过滤。不会计算数据的匹配度相关性分数,不会根据分数去排序,query则相反,会计算分数,也会按照分数去排序。
使用场景:
- query:根据用户搜索条件检索匹配记录
- post_filter:用于查询后,对结果数据的筛选
实操:查询账户金额大于80元,小于160元的用户。并且生日在1998-07-14的用户 - gte:大于等于
- lte:小于等于
- gt:大于
lt:小于
POST /shop/_doc/_search
{
"query": {
"match": {
"desc": "慕课网游戏"
}
},
"post_filter": {
"range": {
"money": {
"gt": 60,
"lt": 1000
}
}
}
}
10.高亮highlight
POST /shop/_doc/_search
{
"query": {
"match": {
"desc": "慕课网"
}
},
"highlight": {
"pre_tags": ["<tag>"],
"post_tags": ["</tag>"],
"fields": {
"desc": {}
}
}
}
11.refix-fuzzy-wildcard
prefix前缀
POST /shop/_doc/_search
{
"query": {
"prefix": {
"desc": "imo"
}
}
}
fuzzy
模糊搜索,并不是指的sql的模糊搜索,而是用户在进行搜索的时候的打字错误现象,搜索引擎会自动纠正,然后尝试匹配索引库中的数据。
POST /shop/_doc/_search
{
"query": {
"fuzzy": {
"desc": "imoov.coom"
}
}
}
# 或多字段搜索
{
"query": {
"multi_match": {
"fields": [ "desc", "nickname"],
"query": "imcoc supor",
"fuzziness": "AUTO"
}
}
}
{
"query": {
"multi_match": {
"fields": [ "desc", "nickname"],
"query": "演说",
"fuzziness": "1"
}
}
}
wildcard:
占位符查询。
?:1个字符 *:1个或多个字符
POST /shop/_doc/_search
{
"query": {
"wildcard": {
"desc": "*oo?"
}
}
}
{
"query": {
"wildcard": {
"desc": "演*"
}
}
}
12.深度分页
分页查询
POST /shop/_doc/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 10
}
深度分页:深度分页其实就是搜索的深浅度,比如第1页,第2页,第10页,第20页,是比较浅的;第10000页,第20000页就是很深了。
{
"query": {
"match_all": {}
},
"from": 9990,
"size": 10
}
{
"query": {
"match_all": {}
},
"from": 9999,
"size": 10
}
我们在获取第9999条到10009条数据的时候,其实每个分片都会拿到10009条数据,然后集合在一起,总共是10009*3=30027条数据,针对30027数据再次做排序处理,最终会获取最后10条数据。
如此一来,搜索得太深,就会造成性能问题,会耗费内存和占用cpu。而且es为了性能,他不支持超过一万条数据以上的分页查询。那么如何解决深度分页带来的性能呢?其实我们应该避免深度分页操作(限制分页页数),比如最多只能提供100页的展示,从第101页开始就没了,毕竟用户也不会搜的那么深,我们平时搜索淘宝或者百度,一般也就看个10来页就顶多了。
提升搜索量:通过设置index.max_result_window来突破10000数据
GET /shop/_settings
PUT /shop/_settings
{
"index.max_result_window": "20000"
}
13.scroll 滚动搜索
一次性查询1万+数据,往往会造成性能影响,因为数据量太多了。这个时候可以使用滚动搜索,也就是 scroll。
滚动搜索可以先查询出一些数据,然后再紧接着依次往下查询。在第一次查询的时候会有一个滚动id,相当于一个锚标记,随后再次滚动搜索会需要上一次搜索的锚标记,根据这个进行下一次的搜索请求。每次搜索都是基于一个历史的数据快照,查询数据的期间,如果有数据变更,那么和搜索是没有关系的,搜索的内容还是快照中的数据。
https://www.elastic.co/guide/cn/elasticsearch/guide/current/scroll.html
scroll=1m,相当于是一个session会话时间,搜索保持的上下文时间为1分钟。
POST /shop/_search?scroll=1m
{
"query": {
"match_all": {
}
},
"sort" : ["_doc"],
"size": 5
}
POST /_search/scroll
{
"scroll": "1m",
"scroll_id" : "your last scroll_id"
}
14.批量查询mget
http://192.168.35.132:9200/shop/_doc/_mget
{
"ids":["1001","1002"]
}
结果:"found": true表示有数据,false表示没有数据
{
"docs": [
{
"_index": "shop",
"_type": "_doc",
"_id": "1001",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"id": 1001,
"age": 18,
"username": "imoocAmazing",
"nickname": "慕课网",
"money": 88.8,
"desc": "我在慕课网学习java和前端,学习到了很多知识",
"sex": 0,
"birthday": "1992-12-24",
"face": "https://www.imooc.com/static/img/index/logo.png"
}
},
{
"_index": "shop",
"_type": "_doc",
"_id": "1002",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"id": 1002,
"age": 19,
"username": "justbuy",
"nickname": "周杰棍",
"money": 77.8,
"desc": "今天上下班都很堵,车流量很大",
"sex": 1,
"birthday": "1993-01-24",
"face": "https://www.imooc.com/static/img/index/logo.png"
}
}
]
}
15.批量操作 bulk
bulk操作和以往的普通请求格式有区别。不要格式化json,不然就不在同一行了,这个需要注意。
action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}代表批量操作的类型,可以是新增、删除或修改
\n是每行结尾必须填写的一个规范,每一行包括最后一行都要写,用于es的解析
{ request body }是请求body,增加和修改操作需要,删除操作则不需要
批量操作的类型
-create新增文档数据,在metadata中指定index以及type
POST /_bulk
{"create": {"_index": "shop2", "_type": "_doc", "_id": "2001"}}
{"id": "2001", "nickname": "name2001"}
{"create": {"_index": "shop2", "_type": "_doc", "_id": "2002"}}
{"id": "2002", "nickname": "name2002"}
{"create": {"_index": "shop2", "_type": "_doc", "_id": "2003"}}
{"id": "2003", "nickname": "name2003"}
- create创建已有id文档,在url中指定index和type
POST /shop/_doc/_bulk
{"create": {"_id": "2003"}}
{"id": "2003", "nickname": "name2003"}
{"create": {"_id": "2004"}}
{"id": "2004", "nickname": "name2004"}
{"create": {"_id": "2005"}}
{"id": "2005", "nickname": "name2005"}
- index创建,已有文档id会被覆盖,不存在的id则新增
POST /shop/_doc/_bulk
{"index": {"_id": "2004"}}
{"id": "2004", "nickname": "index2004"}
{"index": {"_id": "2007"}}
{"id": "2007", "nickname": "name2007"}
{"index": {"_id": "2008"}}
{"id": "2008", "nickname": "name2008"}
- update跟新部分文档数据
POST /shop/_doc/_bulk
{"update": {"_id": "2004"}}
{"doc":{ "id": "3004"}}
{"update": {"_id": "2007"}}
{"doc":{ "nickname": "nameupdate"}}
- delete批量删除
POST /shop/_doc/_bulk
{"delete": {"_id": "2004"}}
{"delete": {"_id": "2007"}}
POST /shop/_doc/_bulk
{"create": {"_id": "8001"}}
{"id": "8001", "nickname": "name8001"}
{"update": {"_id": "2001"}}
{"doc":{ "id": "20010"}}
{"delete": {"_id": "2003"}}
{"delete": {"_id": "2005"}}