Neo4j Cypher поддерживает сверхограничительное понимание шаблонов — или я использую его неправильно?

#neo4j #&raphql #cypher

#neo4j #&raphql #cypher

Вопрос:

Недавно я выбрал Neo4j, поскольку он показался мне лучшим типом базы данных для хранения данных, которые я в настоящее время просматриваю на нескольких онлайн-форумах. Основная структура графика — Сообщество -&&t; Форум -&&t; Тема -&&t; Сообщение -&&t; Автор

Я пытаюсь написать запросы Cypher для разрешения запросов GraphQL и хотел бы разбить на страницы (например) соединение Форум -&&t; Поток. Связь CONTAINS, которая содержит order свойство, т. е. (f:Forum)-[:CONTAINS]-&&t;(t:Thread)

Из библиотеки neo4j-&raphql-js я узнал об их использовании понимания шаблонов для запуска «внутреннего запроса» на дочерних узлах. Например:

 MATCH (f:Forum { id: $id })
RETURN f { .id, .name, .url, threads: [(f)-[:CONTAINS]-&&t;(t:Thread) | t { .id, .title, .url }] }
  

Мне бы очень хотелось использовать ORDER BY , LIMIT и SKIP для понимания внутренних шаблонов, но, к сожалению, это не поддерживается: https://&ithub.com/opencypher/openCypher/issues/202 — библиотека neo4j-&raphql-js решает эту проблему с помощью apoc.coll.sortMulti но я заметил, что производительность невелика и намного медленнее, чем если бы я использовал предложение ORDER BY для эквивалента шаблона верхнего уровня.

Поскольку я новичок в &raph DBMS, это заставило меня задуматься, не мог ли я неправильно понять, как предполагается использовать &raph DB. С точки зрения «внешнего интерфейса», возможность реализации разбивки на страницы на языке запросов самого низкого уровня кажется важной частью, но опять же, возможно, я что-то неправильно понял. Квадратная привязка, круглое отверстие и все такое!

Справедлива ли это оценка? Есть ли в Cypher другой вариант, который решит эту проблему? Или я должен просто вернуться к использованию базы данных SQL для этого варианта использования?

Ответ №1:

[ОТРЕДАКТИРОВАНО]

Если вы переместили order свойство в Thread узлы (которое должно быть допустимым, если каждый Thread узел подключен только к одному Forum ), то вы можете создать индекс (или ограничение уникальности) для :Thread(order) , чтобы ускорить ваш запрос.

Например, этот запрос должен использовать индекс для более быстрого разбиения на страницы (при условии, что f.id , order значение, используемое для целей разбиения на страницы, и limit значение передаются как параметры id , order и limit ):

 MATCH (f:Forum)-[:CONTAINS]-&&t;(t:Thread)
WHERE f.id = $id AND t.order &&t; $order
WITH f, t
ORDER BY t.order
LIMIT $limit
RETURN f{.id, .name, .URL,
  firstOrder: MIN(t.order),
  lastOrder: MAX(t.order),
  threads: [x IN COLLECT(t) | x{.id, .title, .URL}]}
  

И вот (немного более сложный, но также быстрый) запрос для обратной разбивки на страницы:

 MATCH (f:Forum)-[:CONTAINS]-&&t;(t:Thread)
WHERE f.id = $id AND t.order < $order
WITH f, t
ORDER BY t.order DESC
LIMIT $limit
WITH f, t
ORDER BY t.order
RETURN f{.id, .name, .URL,
  firstOrder: MIN(t.order),
  lastOrder: MAX(t.order),
  threads: [x IN COLLECT(t) | x{.id, .title, .URL}]}
  

Если вы проанализируете ПРОФИЛЬ приведенных выше запросов с различными $limit значениями, вы должны увидеть, что сложность попадания в БД равна O(F*L) , где F — количество Forum узлов (которое, вероятно, относительно постоянно), а L $limit значение. Итак, эти запросы должны выполняться значительно быстрее — с индексом — при условии, что:

 F*L << (avera&e number of `Threads` per `Forum`).
  

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

1. Блестящий @cybersam — вы знаете, какая часть спецификации Cypher гарантирует, что внутренняя COLLECT система собирает только правильные темы для каждого форума? Я удалил предложение WHERE и выполнил запрос, и, к моему удивлению, он не собрал одинаковый набор потоков для каждого результата, вместо этого он разделил их на форумы. Не уверен, что я хорошо объясняю, но, в отличие от этого, если collect() находился за пределами «f { … }» расширение, оно будет собирать все потоки из любого места, верно?

2. Также жаль, что у вас не может быть индексов для свойств отношений. Я не могу переместить свойство order, потому что существуют другие представления списка потоков из других узлов, которым также требуется свойство order для отношения. Знаете ли вы, действительно ли нет способа улучшить производительность сортировки в свойстве relationship или в чем-либо еще в конвейере, что поможет решить эту проблему?

3. Неясно, почему order узлы действительно необходимы для взаимосвязи. Вы хотите сказать, что Thread узел может иметь несколько CONTAINS взаимосвязей или что-то в этом роде? В любом случае, wrt COLLECT , почитайте о функциях агрегирования и о том, как они используют «ключи группировки» — результат, который вы видели, — это именно то, что должно произойти с учетом скорректированного запроса.

4. Я просто изменил свой ответ, чтобы предоставлять запросы как для прямой, так и для обратной разбивки на страницы.

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