Elasticsearch5.X DSL常用用法

Elasticsearch5.X DSL常用用法
主要内容
注意:这里只说明基本,实用的DSL常用语法,接口为python接口
Elasticsearch-py接口
DSL测试环境说明
DOC数据插入
DSL基本属性说明
DSL查询结果格式
DSL实现基本查询
DSL实现查询分类统计
DSL实现查询结果排序
DSL实现查询关键字高亮
Elasticsearch-py接口
Elasticsearch有提供标准的py接口,当然还有其它语言接口,都是基于Elasticsearch的RESTful接口。这里演示的py接口都只是最底层最原始的接口,py还有更高级的接口
py原始接口地址:http://elasticsearch-py.readthedocs.io/en/master/api.html
py高级DSL接口:http://elasticsearch-dsl.readthedocs.io/en/latest/
py接口库安装
3.1. 原始接口安装:pip install elasticsearch
3.2. 高级接口安装:pip install elasticsearch-dsl
DSL测试环境说明
假设已建立索引,用于之后的测试,环境如下:
索引名称:test_test_test
索引类型:test
索引定义:
{
“mappings”: {
“test”: {
“properties”: {
“date”: {
“format”: “yyyy-MM-dd HH:mm:ss”,
“type”: “date”
},
“redunip”: {
“type”: “ip”
}
}
}
}
}

注意:以下所有操作都基于此假设环境,需要测试的,先创建此假设的索引

DOC数据插入
索引建立成功后,需要插入数据,这样才可以使用索引。数据插入有两种方式:单条插入,批量插入
单条数据插入: 一次只插入一条记录数据,用于操作少量数据时使用
官方说明:https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html
示例说明:
from elasticsearch import Elasticsearch
import json
import time

创建对象

elkClient = Elasticsearch([“http://ip:9200”])

根据索引定义构造数据

testData = {“date”:time.strftime(’%Y-%m-%d %H:%M:%S’),“redunip”:“192.168.11.10”}

插入数据

test = elkClient.index(index=“test_test_test”, doc_type=“test”, body=testData)
print json.dumps(test)

插入数据时还可以指定数据ID,使用数据ID可以达到数据入索引时去重效果(相当ID数据会自动覆盖)

test = elkClient.index(index=“test_test_test”, doc_type=“test”, body=testData, id=testData[“redunip”])
print json.dumps(test)

批量数据插入: 一次插入一批数据,默认一次最大插入500条数据,也可以在参数中修改
注意:py有提供高级接口来方便使用,批量操作时使用高级接口更方便
官方说明:https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
示例说明:
from elasticsearch import Elasticsearch
from elasticsearch import helpers
import json
import time

创建对象

elkClient = Elasticsearch([“http://ip:9200”])

批量操作使用bulk方法

testIndex = 0
testList = []

测试使用20条数据

while testIndex < 20:
testIndex += 1
testList.append({“date”:time.strftime(’%Y-%m-%d %H:%M:%S’),“redunip”:“192.168.11.10”})
# 为了使用时间看起来间隔,特意暂停了1秒
time.sleep(1)

使用helpers的bulk方法更简单

test = helpers.bulk(client=elkClient, actions=testList, index=“test_test_test”, doc_type=“test”)
print json.dumps(test)

DSL基本属性说明
在这里对查询中经常会使用到的一些属性做统一说明,这里不体现DSL的结构
官方说明:主要来源https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html和https://www.elastic.co/guide/en/elasticsearch/reference/5.6/search.html
query: 用于包含查询使用到的语法
1.1. match_all: 最简单的查询,获取索引所有数据,类似搜索 *。如:”query”:{“match_all”:{}}
1.2. bool: 复合查询,可以包含多个查询条件,主要有(must,must_not,should)
1.2.1. must: 用于包含逻辑与查询条件,即所有查询条件都满足才行
1.2.2. must_not: 用于包含逻辑非查询条件,即不包含所有查询的条件数据
1.2.3. should: 用于包含逻辑或查询条件,即其中有一个条件满足即可
1.2.4. filter: 与must一样,包含的所有条件都要满足,但不会参与计算分值,查询速度上会提升不少
1.3. match: 匹配查询,用于匹配指定属性数据,也可以匹配时间,IP等特殊数据
1.3.1. 注意: match匹配不会解析通配符,匹配的效果受到索引属性类型影响,如果索引属性设置了分词,那么match匹配也会分词匹配,他也不解析”“,但可以设置逻辑关系来处理
1.3.2. operator: 匹配逻辑关系,默认是or,可设置为and,这样可达到精确匹配的效果,具体见:https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-match-query.html#query-dsl-match-query-boolean
1.4. query_string: 使用查询解析器来解析查询内容,如port:80 AND server:http。注意:此类型请求有很多选项属性,可以设置一些特殊的行为,具体见:https://www.elastic.co/guide/en/elasticsearch/reference/5.6/query-dsl-query-string-query.html
1.5. term: 术语查询,查找包含在反向索引中指定的确切术语的文档
1.6. terms: 术语查询,筛选具有匹配任何条件的字段,如”terms” : { “user” : [“kimchy”, “elasticsearch”]}
1.7. range: 术语查询,将文档与具有特定范围内的字段相匹配。Lucene查询的类型依赖于字段类型,对于字符串字段,即TermRangeQuery,而对于number/date字段,查询是一个数字的范围。如:”range”:{“port”:{“gte”:10,”lte”:20,”boost”:2.0}}
1.7.1. gte: 大于或等于
1.7.2. gt: 大于
1.7.3. lte: 小于或等于
1.7.4. lt: 小于
1.7.5. boost: 设置查询的boost值,默认值为1.0
1.8. exists: 术语查询,返回在原始字段中至少有一个非空值的文档,注意:”“,”-“这些都不算是空值
1.9. prefix: 术语查询,匹配包含带有指定前缀字段的字段(没有分析),前缀查询映射到Lucene前缀查询,如:”prefix” : { “user” : “ki” },查询user数据前缀为ki的doc
1.10. wildcard: 术语查询,匹配具有匹配通配符表达式的字段(未分析)的文档。支持(通配符)是匹配任何字符序列(包括空的序列)和(?通配符)它匹配任何一个字符。注意,这个查询可能比较慢,因为它需要迭代多个术语。为了防止非常慢的通配符查询,一个通配符项不应该从通配符开始,或者?通配符查询映射到Lucene通配符查询。如:”wildcard” : { “user” : “kiy” }
1.11. regexp: 术语查询,regexp查询允许您使用正则表达式术语查询,意味着Elasticsearch将把regexp应用到该字段的标记器所产生的词汇,而不是该字段的原始文本。regexp查询的性能严重依赖于所选择的正则表达式,通配符往往会降低查询性能。如:”regexp”:{ “name.first”:”s.*y” }
1.12. fuzzy: 术语查询,模糊查询使用基于Levenshtein编辑距离的相似性。如:”fuzzy” : { “user” : “ki” }
1.13. type: 术语查询,过滤文档匹配所提供的文档/映射类型。如:”type”:{ “value” : “my_type” }
1.14. ids: 术语查询,过滤只具有提供的id的文档。注意:这个查询使用了_uid字段,类型是可选的,可以省略,也可以接受一组值。如果没有指定类型,那么将尝试在索引映射中定义的所有类型。如:”ids”:{ “type” : “my_type”,”values” : [“1”,”4”,”100”] }。
highlight: 允许在一个或多个字段中突出显示搜索结果,基于lucene plain highlighter。在默认情况下,高亮显示会将高亮显示的文本包装在 and ,可以通过设置pre_tags 与 post_tags来自定义,如:”highlight”:{ “pre_tags” : [““], “post_tags” : [““], “fields” : {“_all”:{}} }
2.1. pre_tags: 自定义包含搜索关键字的前缀
2.2. post_tags: 自定义包含搜索关键字的后缀
2.3. fields: 用于指定要高亮的属性,_all表示所以属性都需要高亮,如:”fields”:{ “_all” : {} },也可以指定具体属性 “fields”:{ “app” : {} },也可以给每个属性单独指定设置 “fields”:{ “app” : {“fragment_size” : 150, “number_of_fragments” : 3} }
2.4. highlight_query: 可以通过设置highlight_query来突出显示搜索查询之外的查询,通常,最好将搜索查询包含在highlight_query中。如:”highlight_query”:{ “bool”:{“must”:[{“query_string”:{“query”:app:apache,”analyze_wildcard”:True,”all_fields”:True}}]} }
2.5. fragment_size: 用于指定高亮显示时,碎片的长度,如果过短,高亮内容会被切分为多个碎片。默认情况下,当使用高亮显示的内容时,碎片大小会被忽略,因为它会输出句子,而不管它们的长度
2.6. number_of_fragments 用于指定高亮显示时,碎片的数量,如果指定为0,那么就不会产生任何片段
from: 可以通过使用from和size参数来对结果进行分页,from参数指定您想要获取的第一个结果的偏移量
size: 可以通过使用from和size参数来对结果进行分页,size参数指定要返回结果的最大数量
sort: 允许在特定的字段上添加一个或多个排序,排序是在每个字段级别上定义的,用特殊的字段名来排序,然后根据索引排序进行排序,如”sort”: [ { “date”: { “order”: “desc” } } ],desc降序,asc升序
aggs: 简单来说,aggs主要用于分类集合,可以将查询的数据按指定属性进行分类集合统计等,如:”aggs”:{ “deviceType”:{ “terms”:{ “field”:”deviceType”, “size”:6 } } }
6.1. field: 简单来说,用于指定要分类的属性名称
6.2. size: 用于指定分类集合的数量,即只集合前N名
DSL查询结果格式
ELK的查询结果格式都是一致的,所以在这里做统一说明,格式如下
注意: 下面的结果格式包含了查询,高亮,排序,分类聚合等数据格式示例,如果只是进行查询,就只会有结果格式,只有进行了相应的操作,才会有相应的结果
{
# hits包含了所有结果信息,如条目总数等
“hits”: {
# hits包含了具体的结果
“hits”: [
{
# sort包含时间排序值,结果已经是按时间排序了的
“sort”: [
1508408100000
],
# 索引类型
“_type”: “test”,
# 结果原数据
“_source”: {
“redunip”: “122.115.79.2”,
“date”: “2017-10-19T18:15:00+08:00”,
“country”: “中国”
},
“_score”: null,
# 索引名称
“_index”: “test_test_test”,
# 包含对原数据高亮的部分,如果要显示高亮,需要将此数据覆盖原数据
“highlight”: {
“country”: [
中国
]
},
# 索引数据ID
“_id”: “122.115.79.2”
},
{
“sort”: [
1508408100000
],
“_type”: “test”,
“_source”: {
“redunip”: “182.254.216.71”,
“date”: “2017-10-19T18:15:00+08:00”,
“country”: “中国”
},
“_score”: null,
“_index”: “test_test_test”,
“highlight”: {
“country”: [
中国
]
},
“_id”: “182.254.216.71”
}
],
# 查询数据总条目数量
“total”: 18934351,
“max_score”: null
},
# 查询涉及到的数据分块
“_shards”: {
“successful”: 30,
“failed”: 0,
“skipped”: 0,
“total”: 30
},
“took”: 228,
# 查询分类聚合数据
“aggregations”: {
# 分类的名称
“country”: {
# 聚合的结果
“buckets”: [
{
# 聚合的数据
“key”: “中国”,
# 聚合统计的总数量
“doc_count”: 18934351
}
],
“sum_other_doc_count”: 0,
“doc_count_error_upper_bound”: 0
}
},
# 表示查询是否超时
“timed_out”: false
}

DSL实现基本查询
所有的示例使用python验证,从简单到复合查询
常用的简单查询
简单查询: 获取索引所有数据,如下示例
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“match_all”: {}
},
“from”: 0,
“size”: 10
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

简单匹配查询: 获取指定条件查询结果,如下示例
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“match”: {
“redunip”: “177.145.121.214”
}
},
“from”: 0,
“size”: 10
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

因为match不解析通配符,也会受分词的影响,所以可以通过一些属性设置来实现对分词字段进行精准查询,注意:并不是100%的精准,dsl语法如下

dsl = {
“query”: {
“match”: {
“redunip”: {
“query”: “177.145.121.214”,
# 匹配的逻辑选项,默认为or
“operator”: “and”
}
}
},
“from”: 0,
“size”: 10
}

简单语法查询: 获取指定语法条件查询结果,如下示例
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“query_string”:{
“query”:“redunip:177.145.121.214”,
# analyze_wildcard表示要解析语法中的通配符,默认是不解析
“analyze_wildcard”: True
}
},
“from”: 0,
“size”: 10
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

简单的多值匹配: 获取匹配所有指定值的文档,如下示例
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“terms”:{
“redunip”:[“177.145.121.214”,“192.168.11.11”]
}
},
“from”: 0,
“size”: 10
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

简单范围查询: 获取指定范围的数据,如下示例:获取一个IP范围的数据
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“range”:{
“redunip”:{“lte”:“177.145.121.255”,“gte”:“177.145.121.0”}
}
},
“from”: 0,
“size”: 10
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

全索引查询
即对集群中所有索引查询,_all表示所有索引,示例如下
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“match”: {
“redunip”: “177.145.121.214”
}
},
“from”: 0,
“size”: 10
}

_all表示所有索引,None表示不指定类型

test = elkClient.search(index=’_all’,doc_type=None,body=dsl)
print json.dumps(test)

常用的复合查询
复合查询可以嵌套多种语法进行查询,可以构造比较复杂的查询
复合查询只是具备了复杂嵌套结构,其结构里的语法与上面的简单查询是一样的,所以这里不做过多示例
must逻辑与复合查询: 所有条件都必须满足,示例如下
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“bool”: {
“must”: [
{
“term”: {
“redunip”: “177.145.121.255”
}
},
{
“term”: {
“date”: “2015-10-19T16:00:28+08:00”
}
}
]
}
},
“from”: 0,
“size”: 10
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

must_not逻辑非复合查询: 排除指定条件的数据,示例如下
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“bool”: {
“must_not”: [
{
“term”: {
“redunip”: “177.145.121.255”
}
},
{
“term”: {
“date”: “2015-10-19T16:00:28+08:00”
}
}
]
}
},
“from”: 0,
“size”: 10
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

should逻辑或复合查询: 只要有一个条件满足即可,示例如下
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“bool”: {
“should”: [
{
“term”: {
“redunip”: “177.145.121.255”
}
},
{
“term”: {
“date”: “2015-10-19T16:00:28+08:00”
}
}
]
}
},
“from”: 0,
“size”: 10
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

filter逻辑与复合查询: 情况与must一样,只是查询结果不计算分值,示例如下
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“bool”: {
“filter”: [
{
“term”: {
“redunip”: “177.145.121.255”
}
},
{
“term”: {
“date”: “2015-10-19T16:00:28+08:00”
}
}
]
}
},
“from”: 0,
“size”: 10
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

包含多个逻辑: 复合查询中可以同时包含多个查询逻辑,这里只给出简单的dsl示例
dsl = {
“query”: {
“bool”: {
“must”: [
{
“term”: {
“redunip”: “177.145.121.255”
}
},
{
“term”: {
“date”: “2015-10-19T16:00:28+08:00”
}
}
],
“must_not”: [],
“should”: [],
“filter”: []
}
},
“from”: 0,
“size”: 10
}

DSL实现查询分类统计
这里只给出简单示例,其实分类聚合基本用不到复杂的语法,示例如下
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“bool”: {
“must”: [
{
“term”: {
“redunip”: “177.145.121.255”
}
}
]
}
},
“from”: 0,
“size”: 10,
# 对查询结果的date进行分类聚合
“aggs”: {
# 指定分类名称为date,这个是可以自定义
“date”: {
“terms”: {
# 要聚合的数据属性
“field”: “date”,
# 获取聚合结果的条目数
“size”: 6
}
}
}
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

DSL实现查询结果排序
这里只给出简单示例,排序的语法相对简单,示例如下
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“bool”: {
“must”: [
{
“term”: {
“redunip”: “177.145.121.255”
}
}
]
}
},
“from”: 0,
“size”: 10,

结果以date数据属性进行排序

"sort": [
    {
        "date":{
            # desc降序,asc升序
            "order": "desc"
        }
    }
]

}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

DSL实现查询关键字高亮
这里只给出两个简单的典型示例,其它复杂情况见:https://www.elastic.co/guide/en/elasticsearch/reference/5.6/search-request-highlighting.html#_highlight_query
简单查询高亮: 使用简单方式的时候,在一些复杂的查询中,不能高亮查询关键字,示例如下
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])

构造DSL查询语法

dsl = {
“query”: {
“bool”: {
“must”: [
{
“term”: {
# 因为高亮针对字符数据,所以这里使用其它字符数据代替演示,如想实现效果,请增加此数据属性到索引
“country”: “中国”
}
}
]
}
},
“from”: 0,
“size”: 10,
# 指定要高亮的属性,默认以来包括查询关键字
“highlight”: {
“fields”: {
# *代表高亮所有属性,也可以指定一个具体的属性,如country

        "*": {
        }
    },
    # 指定关键字标签分块大小
    "fragment_size": 2147483647
}

}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

复杂查询高亮: 在一些复杂查询中,想要高亮查询关键字,需要增加highlight_query属性,示例如下
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])# 构造DSL查询语法
dsl = {
“query”: {
“bool”: {
“must”: [
{
# 因为高亮针对字符数据,所以这里使用其它字符数据代替演示,如想实现效果,请增加此数据属性到索引
“query_string”: {
“query”: “country:中国”,
“analyze_wildcard”: True
}
}
]
}
},
“from”: 0,
“size”: 10,
# 指定要高亮的属性,默认以来包括查询关键字
“highlight”: {
“fields”: {
# 代表高亮所有属性,也可以指定一个具体的属性,如country
"
": {
# 对查询进行高亮
“highlight_query”: {
“bool”: {
“must”: [
{
“query_string”: {
“query”: “country:中国”,
“analyze_wildcard”: True
}
}
]
}
}
}
},
# 指定关键字标签分块大小
“fragment_size”: 2147483647
}
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

特殊高亮: 当有时候需要配合前端进行高亮显示时,需要对一些常用标签进行编码,所以就不能使用<>这种符号对关键字进行包含,所以需要自定义特殊包含符号,示例如下
from elasticsearch import Elasticsearch
import json

连接ELK

elkClient = Elasticsearch([“http://ip:9200”])# 构造DSL查询语法
dsl = {
“query”: {
“bool”: {
“must”: [
{
# 因为高亮针对字符数据,所以这里使用其它字符数据代替演示,如想实现效果,请增加此数据属性到索引
“query_string”: {
“query”: “country:中国”,
“analyze_wildcard”: True
}
}
]
}
},
“from”: 0,
“size”: 10,
# 指定要高亮的属性,默认以来包括查询关键字
“highlight”: {
“pre_tags”: [
“@test_highlight@”
],
“post_tags”: [
“@/test_highlight@”
],
“fields”: {
# 代表高亮所有属性,也可以指定一个具体的属性,如country
"
": {
# 对查询进行高亮
“highlight_query”: {
“bool”: {
“must”: [
{
“query_string”: {
“query”: “country:中国”,
“analyze_wildcard”: True
}
}
]
}
}
}
},
# 指定关键字标签分块大小
“fragment_size”: 2147483647
}
}
test = elkClient.search(index=‘test_test_test’,doc_type=“test”,body=dsl)
print json.dumps(test)

注意:一般前端不方便进行标签替换,所以需要后台或接口直接替换,使用python进行html编码和高亮标签比较方便,如下

“”"
import cgi

对数据进行html编码

data = cgi.escape(data)

对高亮标签进行替换

data = data.replace("@test_highlight@","").replace("@/test_highlight@","")

编码转换后的数据就可以给前端使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值