#python #database #mongodb #indexing #pymongo
#python #База данных #mongodb #индексирование #pymongo
Вопрос:
Я использую PyMongo с Flask, и я хотел бы знать, как оптимизировать запрос, поскольку я фильтрую в большой коллекции (8793 документов) с большими документами.
Это одна из структур документов коллекций:
Как вы можете видеть, он имеет 4 свойства (simulationID, simulationPartID, timePass и status, в которых хранится много массивов). Размер этой коллекции составляет 824,4 МБ. Средний размер документов составляет 96,0 КБ.
По сути, я пытаюсь найти документы, которые имеют simulationPartID 7 (1256 документов) и фильтровать по ним индекс массива, равный значению NodeID (которое я получаю в качестве параметра) в свойстве status, и взять четвертый или пятый элемент этого массива (в зависимости от параметра case),в дополнение к добавлению временного интервала.
def node_history(nodeID, case):
coordinates = []
node_data = db['node_data']
db.node_data.create_index([('simulationPartID', 1), ('simulationID', 1)])
if case == 'Temperature':
for document in node_data.find({"simulationPartID": 7}):
coordinates.append([document['timePass'], document['status'][int(nodeID)-1][3]])
elif case == 'Stress':
for document in node_data.find({"simulationPartID": 7}):
coordinates.append([document['timePass'], document['status'][int(nodeID)-1][4]])
else:
pass
coordinates.sort()
return json.dumps(coordinates, default=json_util.default)
Как я уже упоминал, коллекция очень большая, и выполнение запроса занимает около 30-60 секунд, в зависимости от компьютера, но я хочу, чтобы он выполнялся как можно быстрее, потому что я хочу, чтобы мое приложение было максимально интерактивным. Как вы можете видеть, я уже пытался создать индекс как в свойствах simulationID, так и в свойствах simulationPartID.
Я никогда раньше не работал с большими коллекциями, поэтому я не занимаюсь индексацией. Я даже не знаю, правильно ли я это сделал в своем коде. Итак, я хотел бы знать, есть ли способ оптимизировать мой запрос, используя другой подход индексов или любым другим возможным способом, и ускорить его.
Образцы данных:
{
"_id": {
"$oid": "5f83f54d45104462898aba67"
},
"simulationID": "001",
"simulationPartID": 7,
"timePass": 0,
"status": [
[
1,
1.34022987724954e-40,
0.00220799725502729,
20,
114.911392211914
],
[
2,
0.00217749993316829,
0.00220799725502729,
20,
-2.0458550453186
],
[
3,
0.0020274999551475,
0.00235799723304808,
20,
-1.33439755439758
],
[
4,
3.36311631437956e-44,
0.00235799723304808,
20,
148.233413696289
],
[
5,
1.02169119449431e-38,
0.000149997213156894,
20,
-25633.59765625
],
]
},
{
"_id": {
"$oid": "5f83f54d45104462898aba68"
},
"simulationID": "001",
"simulationPartID": 7,
"timePass": 1,
"status": [
[
1,
1.34022987724954e-40,
0.00220799725502729,
20,
114.911392211914
],
[
2,
0.00217749993316829,
0.00220799725502729,
20,
-2.0458550453186
],
[
3,
0.0020274999551475,
0.00235799723304808,
20,
-1.33439755439758
],
[
4,
3.36311631437956e-44,
0.00235799723304808,
20,
148.233413696289
],
[
5,
1.02169119449431e-38,
0.000149997213156894,
20,
-25633.59765625
],
]
},
{
"_id": {
"$oid": "5f83f54d45104462898aba69"
},
"simulationID": "001",
"simulationPartID": 7,
"timePass": 2,
"status": [
[
1,
1.34022987724954e-40,
0.00220799725502729,
20,
114.911392211914
],
[
2,
0.00217749993316829,
0.00220799725502729,
20,
-2.0458550453186
],
[
3,
0.0020274999551475,
0.00235799723304808,
20,
-1.33439755439758
],
[
4,
3.36311631437956e-44,
0.00235799723304808,
20,
148.233413696289
],
[
5,
1.02169119449431e-38,
0.000149997213156894,
20,
-25633.59765625
],
]
}
Спасибо!
Комментарии:
1. Пожалуйста, предоставьте образцы документов в виде текста, а не в виде скриншота. Я отказываюсь копировать образцы данных из изображения.
2. @WernfriedDomscheit Я отредактировал сообщение с примерами
Ответ №1:
Вы создаете индекс для каждого запроса? Индекс создается только один раз при развертывании приложения.
Ваш find
возвращает полный документ, который не нужен. Вы можете ограничить результат с помощью $slice
db.node_data.find({"simulationPartID": 7}, {"timePass": 1, "status": { '$slice': [ 3, 1 ] } } )
Это должно возвращать данные намного быстрее, потому что оно возвращает только те значения, которые вы хотите получить.
Если вы хотите выбрать вложенные элементы из массива, вы можете использовать этот:
db.collection.aggregate([
{ $match: { timePass: 2 } },
{ $set: { status: { $arrayElemAt: [ "$status", 4 ] } } },
{ $set: { status: { $arrayElemAt: [ "$status", 3 ] } } },
])
Комментарии:
1. Спасибо за ваш ответ! Да, индекс создается только один раз, как вы сказали. У меня это в результате вашего запроса:
{ "timePass" : 0, "status" : [ [ 4, 3.36311631437956e-44, 0.00235799723304808, 20, 148.233413696289 ] ] }
etc… Что, если я хотел бы вернуть только четвертый элемент массива состояния, а не весь массив? Я хотел бы иметь что-то вроде этого:{ "timePass" : 0, "status" : [ [ 20] ] }
@Wernfried Domscheit2. Затем вам нужно использовать конвейер агрегации. С помощью simple
find
вы не можете отфильтровать элемент из массива, который является элементом массива. Возможно, я посмотрю позже этим вечером.3. Еще один вопрос: как я могу использовать этот агрегированный запрос, чтобы найти все данные, соответствующие simulationPartID 7, а не только данные, соответствующие заданному мной значению timePass (в вашем примере вы задаете 2 как значение)?