【发布时间】:2020-04-19 10:17:04
【问题描述】:
我在 elasticsearch 中有一组 11 毫米的文档,每个文档都有一个标识符数组。每个标识符都是一个包含类型、值和日期的字典。这是一个示例记录:
{
"name": "Bob",
"identifiers": [
{
"date": "2019-01-01",
"type": "a",
"value": "abcd"
},
{
"date": "2019-01-01",
"type": "b",
"value": "efgh"
}
]
}
我需要每晚将这些记录传输到 parquet 数据存储,其中只有标识符的值保存在数组中。喜欢:
{
"name": "Bob",
"identifiers": ["abcd", "efgh"]
}
我通过循环遍历所有记录并展平标识符来做到这一点。这是我的扁平化变压器:
def _transform_identifier_values(self, identifiers: List[dict]):
ret = [
identifier['value']
for identifier in identifiers
]
return ret
这可行,但速度很慢。有没有更快的方法来做到这一点?可能是我可以利用的本机实现?
编辑:
尝试了 Sunny 的建议。我惊讶地发现原版实际上表现最好。我的假设是itemgetter 的性能会更好。
这是我的测试方法:
import time
from functools import partial
from operator import itemgetter
def main():
docs = []
for i in range(10_000_000):
docs.append({
'name': 'Bob',
'identifiers': [
{
'date': '2019-01-01',
'type': 'a',
'value': 'abcd'
},
{
'date': '2019-01-01',
'type': 'b',
'value': 'efgh'
}
]
})
start = time.time()
for doc in docs:
_transform_identifier_values_original(doc['identifiers'])
end = time.time()
print(f'Original took {end-start} seconds')
start = time.time()
for doc in docs:
_transform_identifier_values_getter(doc['identifiers'])
end = time.time()
print(f'Item getter took {end-start} seconds')
start = time.time()
for doc in docs:
_transform_identifier_values_partial_lambda(doc['identifiers'])
end = time.time()
print(f'Lambda partial took {end-start} seconds')
start = time.time()
for doc in docs:
_transform_identifier_values_partial(doc['identifiers'])
end = time.time()
print(f'Partial took {end-start} seconds')
def _transform_identifier_values_original(identifiers):
ret = [
identifier['value']
for identifier in identifiers
]
return ret
def _transform_identifier_values_getter(identifiers):
return list(map(itemgetter('value'), identifiers))
def _transform_identifier_values_partial_lambda(identifiers):
flatten_ids = partial(lambda o: list(map(itemgetter('value'), o)))
return flatten_ids(identifiers)
def _transform_identifier_values_partial(identifiers):
flatten = partial(map, itemgetter('value'))
return list(flatten(identifiers))
if __name__ == '__main__':
main()
结果:
原始耗时 4.6204328536987305 秒
项目获取器耗时 7.186180114746094 秒
Lambda 部分耗时 10.534514904022217 秒
部分耗时 9.07079291343689 秒
【问题讨论】:
-
小心,通常弹性不会返回 100% 的文件!
-
@Wonka 如果您正在使用扫描,它将返回 100% 的文档。非扫描查询只会返回前 N 个文档。我正在抓取整个索引。
标签: python elasticsearch parquet