Повышение производительности запросов в большой коллекции с большими документами с использованием индексов или любым другим возможным способом

#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 ] } } },
])
 

Игровая площадка Mongo

Комментарии:

1. Спасибо за ваш ответ! Да, индекс создается только один раз, как вы сказали. У меня это в результате вашего запроса: { "timePass" : 0, "status" : [ [ 4, 3.36311631437956e-44, 0.00235799723304808, 20, 148.233413696289 ] ] } etc… Что, если я хотел бы вернуть только четвертый элемент массива состояния, а не весь массив? Я хотел бы иметь что-то вроде этого: { "timePass" : 0, "status" : [ [ 20] ] } @Wernfried Domscheit

2. Затем вам нужно использовать конвейер агрегации. С помощью simple find вы не можете отфильтровать элемент из массива, который является элементом массива. Возможно, я посмотрю позже этим вечером.

3. Еще один вопрос: как я могу использовать этот агрегированный запрос, чтобы найти все данные, соответствующие simulationPartID 7, а не только данные, соответствующие заданному мной значению timePass (в вашем примере вы задаете 2 как значение)?