У меня есть набор данных в виде:
{
u'geometry': {
u'type': u'Point',
u'coordinates': [157.0625, -24.36573]
},
u'_id': ObjectId('5ad70f71f2119236741ffad6'),
u'type': u'Feature',
u'properties': {
u'STATUS': u'8',
u'TIMESTAMP': u'2013-12-31 17:03:00.000',
u'MMSI': u'636015036',
u'SPEED': u'98'
}
}
Я создаю запрос, который возвращает позиции (координаты) кораблей, сгруппированных по MMSI и отсортированных. Total: количество записей с одним и тем же MMSI, COORDINATES: координаты для одного и того же MMSI, собранные в массиве, и _id: MMSI судна.
Запрос (пимонго):
getPositionsOfshipsgrouped = db.samplecol.aggregate([
{ "$match": { "properties.MMSI": { "$exists": "true" } } },
{
"$project": {
"properties.MMSI": "$properties.MMSI",
"geometry.coordinates": "$geometry.coordinates"
}
},
{
"$group": {
"_id": "$properties.MMSI",
"total": { "$sum": 1 },
"COORDINATES": { "$push": "$geometry.coordinates" }
}
},
{ "$match": { "total": { "$gte": 0 } } },
{ "$sort": { "total": -1 } },
{ "$limit": 15 }
])
Полученные результаты:
{
u'total': 10,
u'_id': u'503551000',
u'COORDINATES': [
[141.8705, -12.67311],
[158.1707, -0.9142034],
[157.1707, -0.9142034],
[157.1707, -0.9142034],
[157.1707, -0.9142034],
[157.1707, -0.9142034],
[159.1707, -0.8142034],
[158.2707, -0.8142034],
[159.1707, -0.8142034],
[159.1707, -0.8142034]
]
}
{
u'total': 2,
u'_id': u'416243700',
u'COORDINATES': [
[159.1707, -0.8142034],
[159.0707, -0.7142034]
]
}
Я считаю, что создание индекса здесь - хорошая идея. Итак, сначала я создаю геопространственный индекс в геометрии:
db.samplecol.ensure_index([("geometry", "2dsphere")])
а затем я создаю индексы с одним ключом, например:
db.samplecol.ensure_index([
("properties.MMSI", 1),
("geometry.coordinates", 1),
("properties.TIMESTAMP", 1)
])
Я использую при создании индекса поля из $ project (в запросе выше).
Поэтому у меня вопрос: обеспечат ли создание этих индексов лучшую производительность и правильны ли поля, которые я использую. У меня небольшой набор данных, и я не вижу лучшей производительности с точки зрения времени отклика.
Нет, я могу избавиться от поля $ exists. Ключ "properties.MMSI" существует в каждом поле. Итак, без $ exists этот запрос с этими индексами повлияет на производительность?
Как часть этого, вероятно, одна из самых сложных вещей, с которой можно договориться, в отличие от чего-то вроде SQL, заключается в том, что $project в качестве «выбора» здесь действительно является "антипаттерн". $group фактически уже подразумевает, что поля, на которые он ссылается для вывода, фактически являются единственными обязательными полями документа. И оптимизатор запросов достаточно умен, чтобы понять, что *если вам не помешает.
$exists действительно убивает его, как и $project. В идеале это был бы $sort,$group, а потом и все остальное. Но эти две комбинации в начале могут фактически выбирать и обрабатывать индекс. Как «покрытый», даже если у вас были оба свойства в одном индексе. Поэтому я бы оспорил, что вам это не нужно, а затем просто отбросил бы все результаты null из ключа группировки. Но без значений null он был бы намного более производительным. А может «частичные» индексы
Я меняю свой запрос на следующий: getPositionsOfshipsgrouped = db.samplecol.aggregate ([{"$ group": {"_id": "$ properties.MMSI", "total": {"$ sum": 1}, "COORDINATES" : {"$ push": "$ geometry.coordinates"}}}, {"$ match": {"total": {"$ gte": 0}}}, {"$ sort": {"total": -1}}, {"$ project": {"properties.MMSI": "$ properties.MMSI", "geometry.coordinates": "$ geometry.coordinates"}}, {"$ limit": 15}]) . Я вижу небольшое сокращение времени с 0,0010 до 0,0008. Это ты имеешь в виду. Или мне нужно полностью удалить проекцию $?






К сожалению, ваш конвейер агрегации, о котором идет речь, не получит никакого повышения производительности от индексов. Есть ли причина, по которой вы используете
$existsна первом этапе конвейера? Я спрашиваю, потому что избавление от этого и следующего$projectфактически позволило бы нам перейти на$sort, и что "было бы" влияет на производительность. Так что в идеале ключ"properties.MMSI"должен быть в каждом документе.