Я один из основных разработчиков ArangoDB
и попытался оптимизировать ваш запрос. Поскольку у меня нет вашего dataset
, я могу говорить только о своем тесте dataset
и был бы рад узнать, сможете ли вы подтвердить мои результаты.
Во-первых, если все, что я работаю на ArangoDB
2.7, но в этом конкретном случае я не ожидаю большой разницы в производительности по сравнению с 2.6.
В моем dataset
я мог бы выполнить ваш запрос за ~ 7 секунд. Первое исправление: в заявлении о друзьях вы используете includeData: true
и возвращаете только _id
. С includeData: false
GRAPH_NEIGHBORS
напрямую возвращает _id
и здесь мы также можем избавиться от подзапроса
LET friends = GRAPH_NEIGHBORS('graph',
@user,
{"direction": "any",
"edgeExamples": {
name: "FRIENDS_WITH"
}})
Это уменьшило время до ~ 1,1 секунды на моей машине. Поэтому я ожидаю, что это будет близко к производительности Neo4J.
Почему это оказывает большое влияние? Внутри мы сначала находим значение _id
, фактически не загружая документы JSON. В вашем запросе вам не нужны никакие из этих данных, поэтому мы можем смело продолжать не открывать его.
А теперь самое главное
Ваш запрос идет «логическим» путем и сначала получает соседей пользователей, затем находит их соседей, подсчитывает, как часто встречается foaf
, и сортирует его. Это должно создать полную сеть foaf в памяти и отсортировать ее как единое целое.
Вы также можете сделать это по-другому: 1. Найти все friends
пользователя (только _ids
) 2. Найти все foaf
(полный документ) 3. Для каждого foaf
найти все foaf_friends
(только _ids
) 4. Найти пересечение friends
и foaf_friends
и ПОСЧИТАЙТЕ их
Этот запрос будет выглядеть следующим образом:
LET fids = GRAPH_NEIGHBORS("graph",
@user,
{
"direction":"any",
"edgeExamples": {
"name": "FRIENDS_WITH"
}
}
)
FOR foaf IN GRAPH_NEIGHBORS("graph",
@user,
{
"minDepth": 2,
"maxDepth": 2,
"direction": "any",
"includeData": true,
"edgeExamples": {
"name": "FRIENDS_WITH"
}
}
)
LET commonIds = GRAPH_NEIGHBORS("graph",
foaf._id, {
"direction": "any",
"edgeExamples": {
"name": "FRIENDS_WITH"
}
}
)
LET common_friend_count = LENGTH(INTERSECTION(fids, commonIds))
SORT common_friend_count DESC
RETURN {user: foaf, common_friend_count: common_friend_count}
Который на моем тестовом графике выполнялся за ~0,024 сек.
Так что это дало мне время выполнения в 250 раз быстрее, и я ожидаю, что это будет быстрее, чем ваш текущий запрос в Neo4j, но, поскольку у меня нет вашего dataset
, я не могу его проверить, было бы хорошо если бы вы могли это сделать и сказать мне.
И последнее
С edgeExamples: {name : "FRIENDS_WITH" }
то же самое, что и с includeData
, в этом случае мы должны найти реальную грань и заглянуть в нее. Этого можно было бы избежать, если бы вы хранили ребра в отдельных коллекциях в зависимости от их имени. А затем также удалите edgeExamples. Это еще больше повысит производительность (особенно если много ребер).
Будущее
Следите за нашим следующим выпуском, прямо сейчас мы добавляем некоторые дополнительные функции в AQL, которые значительно упростят запросы к вашему делу и должны дать еще один прирост производительности.
person
mchacki
schedule
23.10.2015