Низкая производительность на нескольких агрегатах - PullRequest
0 голосов
/ 02 ноября 2019

У меня есть данные GTFS как коллекции на mongodb. Коллекции выглядят точно так же, как в документации: https://developers.google.com/transit/gtfs/reference

Я пытаюсь вернуть все остановки с их типом транспорта (трамвай, автобус или несколько в моем случае). Чтобы добраться до этого, мне нужно получить все маршруты на этой остановке, потому что в коллекции route есть поле route_type, которое имеет место (значение 0 - трамвай, значение 3 - шина).

(Псевдокод)

Get all stops
Join stoptimes on stops.stop_id = stoptimes.stop_id
Join trips on stoptimes.trip_id = trips.trip_id
Join routes on trips.trip_id = routes.route_id
Compare routes.route_type for each stop according to documentation and return type

В моих данных GTFS есть правило, что каждая технологическая колея имеет один или два символа идентификатора, а шина имеет 3 символа. Эти идентификаторы являются полем route_id в моей GTFS. Так что это дает мне возможность пропустить одно соединение:

(псевдокод):

Get all stops
Join stoptimes on stop_id = stoptimes.stop_id
Join trips on stoptimes.trip_id = trips.trip_id
Compare trips.route_id for each stop by length and return type

Ниже приведен мой запрос. Я добавил $limit: 10 для целей отладки. Запрос занимает 2028 мс для 10 остановок.

Длина сборов:

stops: 6724 documents,
stoptimes: 4823250 documents,
trips: 174698 documents,
routes: 350 documents 

Вопросы:

  • Как сделать это быстрее? Для 1000 остановок выполнение занимает около 75 секунд ...

  • Когда $group ing, я добавляю выражение $first, чтобы не потерять поля, которые мне нужны в конечном результате,Есть ли лучший способ включить их в конечный результат?

  • Я сделал $unwind: '$lines' дважды, потому что запрос создал вложенный массив. Как этого избежать?

    Stop.aggregate([{
      $match: {
        'stop_id': {
          $regex: /^\d{6}$/
        }
      }
    },
    {
      $lookup: {
        from: "stoptimes",
        localField: "stop_id",
        foreignField: "stop_id",
        as: "stoptimes"
      }
    },
    {
      $lookup: {
        from: "trips",
        localField: "stoptimes.trip_id",
        foreignField: "trip_id",
        as: "trips"
      }
    },
    {
      $limit: 10
    },
    {
      $group: {
        _id: '$stop_id',
        stop_name: {
          $first: '$stop_name'
        },
        stop_lat: {
          $first: '$stop_lat'
        },
        stop_lon: {
          $first: '$stop_lon'
        },
        lines: {
          $addToSet: "$trips.route_id"
        }
      }
    },
    {
      $unwind: '$lines'
    },
    {
      $unwind: '$lines'
    },
    {
      $project: {
        _id: 1,
        stop_name: 1,
        stop_lat: 1,
        stop_lon: 1,
        lines: {
          $strLenCP: "$lines"
        }
      }
    },
    {
      $group: {
        _id: {
          stop_id: '$_id',
          stop_name: '$stop_name',
          stop_lat: '$stop_lat',
          stop_lon: '$stop_lon',
          line: '$lines'
        },
        count: {
          $sum: 1
        }
      }
    },
    {
      $project: {
        _id: 0,
        stop_id: '$_id.stop_id',
        stop_name: '$_id.stop_name',
        stop_lat: '$_id.stop_lat',
        stop_lon: '$_id.stop_lon',
        line: '$_id.line'
      }
    },
    {
      $group: {
        _id: '$stop_id',
        stop_name: {
          $first: '$stop_name'
        },
        stop_lat: {
          $first: '$stop_lat'
        },
        stop_lon: {
          $first: '$stop_lon'
        },
        lineNameLengths: {
          $addToSet: '$line'
        }
      }
    },
    {
      $project: {
        _id: 0,
        stop_id: '$_id',
        stop_name: '$stop_name',
        stop_lat: '$stop_lat',
        stop_lon: '$stop_lon',
        type: {
          $switch: {
            branches: [{
                case: {
                  $gte: [{
                    $size: "$lineNameLengths"
                  }, 3]
                },
                then: "multiple"
              },
              {
                case: {
                  $and: [{
                      $eq: [{
                        $size: "$lineNameLengths"
                      }, 2]
                    },
                    {
                      $not: [{
                        $in: [3, '$lineNameLengths']
                      }]
                    }
                  ]
                },
                then: "tram"
              },
              {
                case: {
                  $and: [{
                      $eq: [{
                        $size: "$lineNameLengths"
                      }, 2]
                    },
                    {
                      $in: [3, '$lineNameLengths']
                    }
                  ]
                },
                then: "multiple"
              },
              {
                case: {
                  $and: [{
                      $eq: [{
                        $size: "$lineNameLengths"
                      }, 1]
                    },
                    {
                      $in: [1, '$lineNameLengths']
                    }
                  ]
                },
                then: "tram"
              },
              {
                case: {
                  $and: [{
                      $eq: [{
                        $size: "$lineNameLengths"
                      }, 1]
                    },
                    {
                      $in: [2, '$lineNameLengths']
                    }
                  ]
                },
                then: "tram"
              },
              {
                case: {
                  $and: [{
                      $eq: [{
                        $size: "$lineNameLengths"
                      }, 1]
                    },
                    {
                      $in: [3, '$lineNameLengths']
                    }
                  ]
                },
                then: "bus"
              }
            ],
            default: ""
          }
        }
      }
    }]);
    

Можно ли заставить этот запрос выполняться намного быстрее?

Это мой первый проект mongodb, так что, надеюсь, я мог бы сделать несколькоглупые ошибки, легко исправляемые более опытными коллегами.

...