我在Elasticsearch中有一组11mm的文档,每个文档都有一个标识符数组。每个标识符都是一个包含类型,值和日期的字典。这是一个示例记录:
{
"name": "Bob",
"identifiers": [
{
"date": "2019-01-01",
"type": "a",
"value": "abcd"
},
{
"date": "2019-01-01",
"type": "b",
"value": "efgh"
}
]
}
我需要每晚将这些记录传输到一个镶木地板数据存储区,在该存储区中仅将标识符的值保存在数组中。喜欢:
{
"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秒
答案 0 :(得分:0)
这是我想出的解决方案:
def changeJSON(dictionary):
new_dict = {'name': dictionary['name'], 'identifiers': []}
for i in dictionary['identifiers']:
new_dict['identifiers'].append(i['value'])
return new_dict
此函数将使用一个字典,并以您所需的新格式返回字典。然后,您可以从内置的json库中json.dumps()
函数。它接收字典列表并将其转储到json文件中。
答案 1 :(得分:0)
您可以尝试使用operator.itemgetter
。
from operator import itemgetter
def _transform_identifier_values(self, identifiers: List[dict]):
return list(map(itemgetter('value'), identifiers))
甚至可以用它来制作partial function:
from operator import itemgetter
from functools import partial
flatten_ids = partial(lambda o: list(map(itemgetter('value'), o['identifiers'])))
print(flatten_ids(obj))
如果您想避免使用lambda,可以尝试:
flatten = partial(map, itemgetter('value'))
print(list(flatten(obj['identifiers'])))
我很好奇看到这些结果。