上篇文章已经讲过elasticsearch scan scroll的用途, 他们是用来解决获取大数据返回时的性能问题. 有兴趣的朋友可以回顾下 scan,scroll的作用一篇. http://xiaorui.cc/?p=3072
这次聊下elasticsearch python客户端的实现。
该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新。
这里再废话说下scan scroll的作用:
scroll用来避免深度分页查找数据时的性能消耗,他会像curosr那样做数据的快照。
scan能避免scroll的排序性能消耗,from size分页查询模式会对数据集进行整体排序, 性能损耗是很大的. 如果我们关闭排序,那么可以消耗极少资源返回所有的文档。scan就是不去,而是仅仅从每个有结果的分片中返回数据.
下面是python elasticsearch helpers.scan的源码。对照elasticsearch scroll scan基本用法,很容易就能理解下面的代码。 话说elasticsearch-py把高性能的功能都继承在了helpers模块里,比如helpers.scan helpers.reindex streaming_bulk helpers.bulk parallel_bulk .
elasticsearch.helpers.scan(client, query=None, scroll=u'5m', raise_on_error=True, preserve_order=False, **kwargs) 参数介绍: client – elasticsearch的连接对象 query – elasticsearch dsl查询语句 scroll – 你想让scroll的结果集在server端标记多久 raise_on_error – raise的error class preserve_order – 这里其实对应的是search_type,是否要求排序
file: helpers/__init__.py
#xiaorui.cc
#默认是5m分钟, 默认是search_type是scan扫描模式
def scan(client, query=None, scroll='5m', preserve_order=False, **kwargs):
if not preserve_order: #是否需要scan模式
kwargs['search_type'] = 'scan'
resp = client.search(body=query, scroll=scroll, **kwargs)
scroll_id = resp.get('_scroll_id') #第一次查询拿到_scroll_id token
if scroll_id is None:
return
first_run = True
while True:
#如果你server_type不是scan,那么第一次的结果里是包含数据的。
if preserve_order and first_run:
first_run = False
else:
resp = client.scroll(scroll_id, scroll=scroll)
if not resp['hits']['hits']:
break
for hit in resp['hits']['hits']:
yield hit #通过yield生成器来返回数据
scroll_id = resp.get('_scroll_id')
if scroll_id is None:
break
file: client/__init__.py
#xiaorui.cc
@query_params('scroll')
def scroll(self, scroll_id, params=None):
# 第二次scroll的数据请求是直接 /_search/scroll,方法用的是GET
_, data = self.transport.perform_request('GET', '/_search/scroll',params=params, body=scroll_id)
return data
对于elasticsearch scanscroll的使用方法, 大家注意一下异常情况.
#xiaorui.cc
data = scan(es,
query={"query": {"match": {"domain": "xiaorui.cc"}}},
index="xiaorui_index",
doc_type="blog"
)
for one in data:
print one
Elasticsearch博大精深… … 经过我的线下线上测试,使用scroll scan的性能还是不错的,返回的速度不错,明显比那种from size分页要快速,而且节省了elasticsearch的检索资源。

django 中的api开发 使用helper.scan 获取个50M左右的数据 就报 timeout 是什么原因呢