elasticsearch_dsl从懵逼到入坑的经验

一、使用方法

1.闲谈

我一个莫得感情的小运维,小领导跟我说要弄链路追踪,其他系统的运维人员用开源的系统(主要是查es库,有个建单功能)进行二次开发了,然后我就被无情的毒打,就说下我被elasticsearch_dsl打的最惨的过程吧。百度了一下,文章很多,有用的很少。看了官方文档,直接一脸懵逼,讲的啥,什么意思,无奈用最简单的json字符串查询。当然了是简单了不少,缺点也很严重,阅读难受,查询复杂的话,就看这个语句瞅的眼疼,而且官方也说了,后期也可能不支持了,主要推的是操作对象的方式。这篇文章是我以官方文档进行的一些解释,希望可以帮助到新接触到elasticsearch-dsl的小伙伴们。

2.前期准备

GitHub地址:https://github.com/elastic/elasticsearch-dsl-py

安装Python模块:pip install elasticsearch-dsl    
			    pip install elasticsearch-dsl 
	
			    
from elasticsearch_dsl import connections

es = connections.create_connection(hosts=['localhost'], timeout=20)   #连接es主机

肯定有刚接触的小伙伴问了,我不太懂es的查询语句,压根都没接触过es查询的,首先这个elasticsearch_dsl也是基于Query DSL。有个简单的方法,是我小领导跟我说的,利用kibana界面可以找到你想要的es语句,在kibana界面上输入条件,根据下面的图操作即可。
在这里插入图片描述
在这里插入图片描述

3.search查询

该Search对象代表整个搜索请求:
查询 、过滤器 、聚合、种类、分页、附加参数、关联客户

API 被设计为可链接的。除了聚合功能外,这意味着Search对象是不可变的——对对象的所有更改都将导致创建包含更改的浅表副本。这意味着您可以安全地将Search对象传递给外部代码,而不必担心它会修改您的对象,只要它坚持Search对象 API。

3.1 match快捷键Q查询

例子:
from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search ,Q

es = connections.create_connection(hosts=['localhost'], timeout=20)
index="test"
s = s.query('bool', filter=[Q('terms', zhiduan=['内容'])]) # 格式是有要求的,必须是支持多个内容字段=['内容1','内容2']或者字段='内容'
e = s.to_dict() # 出于调试目的,您可以将对象显式序列化为dict,显示你的es
s = s.execute() # 上面的语句只保留在内存中,需要加了才进行es查询

在这里插入图片描述
下面来自官方文档的解释:
您可以使用Q快捷方式使用带有参数的名称或 raw 来构造实例dict:

from elasticsearch_dsl import Q

Q("multi_match", query='python django', fields=['title', 'body'])
Q({"multi_match": {"query": "python django", "fields": ["title", "body"]}})

要将查询添加到Search对象,请使用以下.query()方法:

q = Q("multi_match", query='python django', fields=['title', 'body'])
s = s.query(q)

该方法还接受所有参数作为Q快捷方式:

s = s.query("multi_match", query='python django', fields=['title', 'body'])

如果您已经有一个查询对象或一个dict代表对象,您可以覆盖Search对象中使用的查询:

s.query = Q('bool', must=[Q('match', title='python'), Q('match', body='best')])

3.2 filter过滤器

如果要在过滤器上下文中添加查询, 可以使用该filter()方法使事情变得更容易:

s = Search()
s = s.filter('terms', tags=['search', 'python'])

在幕后,这将产生一个Bool查询并将指定的 terms查询放入其filter分支,使其等效于:

s = Search()
s = s.query('bool', filter=[Q('terms', tags=['search', 'python'])])

如果您想使用 post_filter 元素进行分面导航,请使用该 .post_filter()方法。

您还可以exclude()像这样从查询中获取项目:

s = Search()
s = s.exclude('terms', tags=['search', 'python'])
这是以下的简写:s = s.query('bool', filter=[~Q('terms', tags=['search', 'python'])])

上面是官方的介绍,还一个大坑就是下面这张图,官方的介绍是使用时间范围的方法,然后我直接套入了操作对象的语句中,结果是报错,搞到我怀疑人生,为什么写到match查询下面,又不能用match查询时间,最最最重要的是,语法也不对啊,这官方是想让我猜??坑啊!!!
在这里插入图片描述

下面kibana的调试语法的时间范围也是在filter字段下,大家有不同的方法可以在下面留言交流。
在这里插入图片描述
我把时间范围正确的用法给大家举个例子:

from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search ,Q

es = connections.create_connection(hosts=['localhost'], timeout=20)
index="test"
s = Search(using=es, index=index)
s = Search().filter('range', **{'@timestamp': {'gte': '2022-05-31T08:10:08.130Z', 'lte': '2022-05-31T08:11:03.962Z'}}).query('match', ap="test") #实际用法跟官方的还是有点不一样的,坑死人,搞了我好久
s = s.execute()

下面我们看下es语句:

{'query': {'bool': {'filter': [{'range': {'@timestamp': {'gte': '2022-05-31T08:10:08.130Z', 'lte': '2022-05-31T08:11:03.962Z'}}}], 'must': [{'match': {'ap': 'test'}}]}}}

在这里插入图片描述

4.聚合快捷键A

要定义聚合,您可以使用A快捷方式:

from elasticsearch_dsl import A

A('terms', field='tags')
# {"terms": {"field": "tags"}}

要嵌套聚合,您可以使用.bucket(),.metric()和 .pipeline()方法:

a = A('terms', field='category')
# {'terms': {'field': 'category'}}

a.metric('clicks_per_category', 'sum', field='clicks')\
    .bucket('tags_per_category', 'terms', field='tags')
# {
#   'terms': {'field': 'category'},
#   'aggs': {
#     'clicks_per_category': {'sum': {'field': 'clicks'}},
#     'tags_per_category': {'terms': {'field': 'tags'}}
#   }
# }

要将聚合添加到Search对象,请使用.aggs属性,它充当顶级聚合:

s = Search()
a = A('terms', field='category')
s.aggs.bucket('category_terms', a)
# {
#   'aggs': {
#     'category_terms': {
#       'terms': {
#         'field': 'category'
#       }
#     }
#   }
# }

或者

s = Search()
s.aggs.bucket('articles_per_day', 'date_histogram', field='publish_date', interval='day')\
    .metric('clicks_per_day', 'sum', field='clicks')\
    .pipeline('moving_click_average', 'moving_avg', buckets_path='clicks_per_day')\
    .bucket('tags_per_day', 'terms', field='tags')

s.to_dict()
# {
#   "aggs": {
#     "articles_per_day": {
#       "date_histogram": { "interval": "day", "field": "publish_date" },
#       "aggs": {
#         "clicks_per_day": { "sum": { "field": "clicks" } },
#         "moving_click_average": { "moving_avg": { "buckets_path": "clicks_per_day" } },
#         "tags_per_day": { "terms": { "field": "tags" } }
#       }
#     }
#   }
# }

上面官方的文档介绍的很详细,也很容易懂,我就不在解释了,给大家分享一个我写算平均时间的例子:

	def avgRspTime(self, es_q ):
		es_q = Q('bool',
					   should=[Q('match_phrase', timestamp="2022-04-01 11:45")], # 查询4月1号11点45分的数据,是根据一分钟计算一次
					   minimum_should_match=1
					   ) & Q('bool',
							 should=[Q('match_phrase', ap='test')], #这里是搜索条件
							 minimum_should_match=1
							 )
		t_avg = Search(using=es, index=index_search).query('bool', filter=es_q ) #根据搜索条件筛选的数据
		a_avg = A('stats', field='costMillis') #根据costMillis这个字段进行聚合
		t_avg.aggs.bucket('costMillis', a_avg) #加入查询语句中
		# {'query': {'bool': {'filter': [{'bool': {'must': [{'match_phrase': {'timestamp': '2022-04-01 11:45'}}, {'match_phrase': {'ap': 'api'}}]}}]}}, 'aggs': {'costMillis': {'stats': {'field': 'costMillis'}}}} 这个是es查询语句,经过反序列化过的

		res_avg = t_avg.execute()
		t_avgtime = res_avg.aggregations.costMillis.avg
		# print(res_avg.aggregations.costMillis)
		# 保留2位小数点
		return round(t_avgtime, 2)

再给大家分享一下经验,关于es库索引字段的问题:
默认是text,支持模糊查询,支持饼图(有些字段用饼图挺直观的),不支持聚合,但是某些时候text的.keyword是偶尔支持聚合的,万一不能用聚合还是老实的用keyword字段。
keyword字段是支持聚合,饼图的,不支持模糊查询。
数字和小数点,支持聚合,统计,计算的,不支持饼图。

5.Index索引

大家可以看官方的介绍,我就不一一介绍了,就是一个api的介绍。分享我写的给大家一个参考:

	def init_index(self, index_n):
		imp_code_mapping = {
			"a": "float",
			"b": "long",
			"c": "float",
			"d": "float",
			"e": "float",
			"f": "float",
			"g": "long",
			"h": "float",
			"i": "keyword",
			"j": "short"
		} # 这个是索引字典,下面会用到这个字典的
		i = Index(index_n, using=es)
		index_info = i.exists() 
		if index_info is False:
			print("未检测到es索引" + index_n + ", 开始创建索引......")
			i.create() # 在 elasticsearch 中创建索引。
			m = Mapping() # 将映射(的实例 Mapping)与此索引相关联。这意味着,当创建此索引时,它将包含由这些映射定义的文档类型的映射
			# m.field('category', 'text', fields={'category': es_dsl.Keyword()})
			for k, v in imp_code_mapping.items():
				m.field(k, v)
			print(m.to_dict())
			m.save(index_n)
			print(index_n + "索引创建成功!!!")

总结:

我暂时就使用了怎么多的功能,也就研究和踩坑了怎么多,第一次看一脸懵逼,我要是能看的懂官方的文档,也不会写这篇文章了,实在是太坑了,搞了好久才弄明白的。唉!太坑了,大家点赞,不过分吧。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用elasticsearch_dsl的示例代码: ```python # 引必要的包 from elasticsearch_dsl import connections, Search from elasticsearch import Elasticsearch # 连接到elasticsearch es = connections.create_connection(hosts=["127.0.0.1:9200"], timeout=20) # 查询操作 search = Search(using=es, index="account_info") response = search.query("match", firstname="John").execute() for hit in response: print(hit.firstname, hit.lastname) # 更新文档 doc = search.get(id="1") doc.balance += 100 doc.save() # 删除文档 search.delete(id="2") # 关闭连接 es.close() ``` 以上示例代码展示了elasticsearch_dsl的基本用法。首先我们连接到elasticsearch实例,然后可以执行查询、更新和删除操作。在查询操作中,我们使用`Search`对象来构建查询条件,并执行`execute()`方法获取查询结果。在更新操作中,我们通过获取文档对象并修改其属性值,然后调用`save()`方法保存修改。在删除操作中,我们使用`delete()`方法指定要删除的文档id。最后,我们关闭连接。 请注意,以上示例中的索引名为"account_info",如果你使用的是不同的索引,请将其替换为你的索引名。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [pythonelasticsearch_dsl模块用法详解](https://blog.csdn.net/m0_72557783/article/details/126957624)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值