Python Elasticsearch DSL 使用简介
连接 Es:
import elasticsearch
clinet = elasticsearch.Elasticsearch([{"host": "10.44.99.102", "port": 9200}])
or
clinet = Elasticsearch(["10.44.99.102:9200"])
先看一下搜索,q 是指搜索内容,空格对 q 查询结果没有影响,size 指定个数,from_ 指定起始位置,filter_path 可以指定需要显示的数据,如本例中显示在最后的结果中的只有 _id 和 _type。
res_3 = clinet .search(index="bank", q="Holmes", size=1, from_=1)
res_4 = clinet .search(index="bank", q=" 39225 5686 ", size=1000, filter_path=["hits.hits._id", "hits.hits._type"])
查询指定索引的所有数据:
其中,index 指定索引,字符串表示一个索引;列表表示多个索引,如 index=["bank", "banner", "country"];正则形式表示符合条件的多个索引,如 index=["apple*"],表示以 apple 开头的全部索引。
search 中同样可以指定具体 doc-type。
from elasticsearch_dsl import Search
s = Search(using=clinet,index="situation-event").execute()
logging.warning(s.to_dict())
忽略不可用的
from elasticsearch_dsl import Search
s = Search(using=clinet,index="situation-event")
s = s.params(ignore_unavailable=True)
根据某个字段查询,可以多个查询条件叠加:
s = Search(using=clinet, index="situation-event").query("match", event_type="002")
s.query("match", event_title="aaa")
logging.warning(s.execute().to_dict())
多字段查询:
from elasticsearch_dsl.query import MultiMatch
multi_match = MultiMatch(query="aaa",fields=["event_type","event_title"])
s = Search(using=clinet,index="situation-event").query(multi_match)
s = s.execute()
logging.warning(s.to_dict())
还可以用 Q() 对象进行多字段查询,fields 是一个列表,query 为所要查询的值。
q = Q("multi_match",query="aaa",fields=["event_type","event_title"])
s = Search(using=clinet, index="situation-event").query(q)
s = s.execute()
logging.warning(s.to_dict())
Q() 第一个参数是查询方法,还可以是 bool。
q = Q("bool",must=[Q("match",event_type="002"),Q("match",event_title="aaa")])
s = Search(using=clinet,index="situation-event").query(q)
s = s.execute()
logging.warning(s.to_dict())
通过 Q() 进行组合查询,相当于上面查询的另一种写法。
q = Q("match", event_type="002") | Q("match", event_type="003")
s = Search(using=clinet,index="situation-event").query(q).execute()
logging.warning(s.to_dict())
# {"query": {"bool": {"should": [{"match": {"event_type": "002"}}, {"match": {"event_type": "003"}}]}}}
q = Q("match", event_type="002") & Q("match", event_type="003")
s = Search(using=clinet,index="situation-event").query(q)
logging.warning(s.to_dict())
# {"query": {"bool": {"must": [{"match": {"event_type": "002"}}, {"match": {"event_type": "003"}}]}}}
q = ~Q("match", event_type="002")
s = Search(using=clinet,index="situation-event").query(q).execute()
logging.warning(s.to_dict())
# {"query": {"bool": {"must_not": [{"match": {"event_type": "002"}}]}}}
过滤,在此为范围过滤,range 是方法,timestamp 是所要查询的 field 名字,gte 为大于等于,lt 为小于,根据需要设定即可。
关于 term 和 match 的区别,term 是精确匹配,match 会模糊化,会进行分词,返回匹配度分数,(term 如果查询小写字母的字符串,有大写会返回空即没有命中,match 则是不区分大小写都可以进行查询,返回结果也一样)
# 范围查询
s = Search(using=clinet, index="situation-event").filter("range", update_time={"gte": 0, "lt": time.time()})
.query("match", event_type="003")
logging.warning(s.to_dict())
#
# 普通查询
s = Search(using=clinet, index="situation-event").filter("terms", event_type=["002", "003"]).execute()
logging.warning(s.to_dict())
# {"query": {"bool": {"filter": [{"terms": {"event_type": ["002", "003"]}}]}}}
其他写法
s = Search(using=clinet, index="situation-event").filter("terms", event_type=["002", "003"])
logging.warning(s.to_dict())
# {"query": {"bool": {"filter": [{"terms": {"event_type": ["002", "003"]}}]}}}
s = Search(using=clinet, index="situation-event").query("bool", filter=[Q("terms", event_type=["002", "003"])])
logging.warning(s.to_dict())
# {"query": {"bool": {"filter": [{"terms": {"event_type": ["002", "003"]}}]}}}
s = Search(using=clinet, index="situation-event").query("bool", filter=[~Q("terms", event_type=["002", "003"])])
logging.warning(s.to_dict())
# {"query": {"bool": {"filter": [{"bool": {"must_not": [{"terms": {"event_type": ["002", "003"]}}]}}]}}}
聚合可以放在查询,过滤等操作的后面叠加,需要加 aggs。
bucket 即为分组,其中第一个参数是分组的名字,自己指定即可,第二个参数是方法,第三个是指定的 field。
metric 也是同样,metric 的方法有 sum、avg、max、min 等,但是需要指出的是,有两个方法可以一次性返回这些值,stats 和 extended_stats,后者还可以返回方差等值。
# 单层聚合
s = Search(using=clinet, index="situation-event")
s.aggs.bucket("per_one","terms",field="event_type")
res = s.execute()
logging.warning(res.to_dict())
# {"query": {"match_all": {}}, "aggs": {"per_one": {"terms": {"field": "event_type"}}}}
#双层聚合
s = Search(using=clinet, index="situation-event")
s.aggs.bucket("per_one", "terms", field="event_type").bucket("per_two", "terms", field="event_level")
res = s.execute()
logging.warning(res.to_dict())
# {"query": {"match_all": {}}, "aggs": {"per_one": {"terms": {"field": "event_type"}, "aggs": {"per_two": {"terms": {"field": "event_level"}}}}}}
# 单层聚合
s = Search(using=clinet,index="situation-event")
s.aggs.metric("sum_system_id","stats",field="system_id")
res = s.execute()
logging.warning(res.to_dict())
# {"query": {"match_all": {}}, "aggs": {"sum_system_id": {"stats": {"field": "system_id"}}}}
# 双层聚合
s = Search(using=clinet,index="situation-event")
s.aggs.bucket("pre_one","terms",field="system_id").metric("sum_system_id","stats",field="system_id")
res = s.execute()
logging.warning(res.to_dict())
# {"query": {"match_all": {}}, "aggs": {"pre_one": {"terms": {"field": "system_id"}, "aggs": {"sum_system_id": {"stats": {"field": "system_id"}}}}}}
最后依然要执行 execute(),此处需要注意,s.aggs 操作不能用变量接收(如 res=s.aggs,这个操作是错误的),聚合的结果会保存到 res 中显示。
排序
s = Search().sort(
"category",
"-title",
{"lines" : {"order" : "asc", "mode" : "avg"}}
)
分页
s = s[10:20]
# {"from": 10, "size": 10}
一些扩展方法,感兴趣的同学可以看看:
s = Search()
# 设置扩展属性使用`.extra()`方法
s = s.extra(explain=True)
# 设置参数使用`.params()`
s = s.params(search_type="count")
# 如要要限制返回字段,可以使用`source()`方法
# only return the selected fields
s = s.source(["title", "body"])
# don"t return any fields, just the metadata
s = s.source(False)
# explicitly include/exclude fields
s = s.source(include=["title"], exclude=["user.*"])
# reset the field selection
s = s.source(None)
# 使用dict序列化一个查询
s = Search.from_dict({"query": {"match": {"title": "python"}}})
# 修改已经存在的查询
s.update_from_dict({"query": {"match": {"title": "python"}}, "size": 42})