Эффективный способ получить самый последний из многих узлов транзакций, подключенных к одному узлу учетной записи, по дате - PullRequest
1 голос
/ 08 марта 2019

У меня есть большое количество узлов, представляющих учетные записи, которые мы могли бы пометить как, скажем, (a :Account). Каждый (:Account) может иметь потенциально десятки тысяч (t :Transaction) узлов, связанных с ним, каждый из которых представляет данные для транзакции, которая произошла с этой учетной записью.

Узлы (:Transaction) имеют свойство date. Учитывая дату запроса о том, что было бы наиболее эффективным способом получить последний (:Transaction) узел для каждого (a :Account), который происходит до или в дату запроса? Это может быть один из способов сделать это:

// run for all address nodes
match (a :Address)
with distinct a
optional match (a)-->(t :Transaction)
where t.timestamp <= date("2014-03-07")
with a, t
where t.date = max(t.date)
return a, t

Однако я не уверен, что этот метод очень эффективен, когда число (t), подключенных к каждому (a), становится очень большим. Есть ли способ написать запрос или проиндексировать базу данных так, чтобы время запроса линейно масштабировалось с количеством учетных записей, независимо от количества транзакций, подключенных к этим узлам учетных записей?

Для раскрытия информации я разместил версию этого вопроса на форуме сообщества neo4j , но я надеюсь, что увеличение трафика на этом сайте сделает этот вопрос более открытым.

1 Ответ

2 голосов
/ 08 марта 2019

В neo4j 3.5 был добавлен новый "индексный порядок с оптимизацией" .Это означает, что если вы создадите «собственный» индекс (подробности см. здесь ), то индекс будет сохранен в отсортированном порядке, а предложение ORDER BY для свойства, для которого используется индексфактически не нужно будет выполнять какую-либо сортировку.

Итак, предположим, что вы создали индекс в :Transaction(timestamp), например:

CREATE INDEX ON :Transaction(timestamp);

, затем в neo4j 3.5+ этоВ запросе (с дополнительным указанием на использование этого индекса) следует избегать сортировки при поиске Transaction с максимальным timestamp для каждого Address:

MATCH (a:Address)-->(t:Transaction)
USING INDEX t:Transaction(timestamp)
WHERE t.timestamp <= date("2014-03-07")
WITH a, t
ORDER BY t.timestamp DESC
RETURN a, COLLECT(t)[0] AS transaction

Этот запрос должен выполнять следующие действия:

  1. Используйте индекс для получения всех Transaction узлов с соответствующими timestamp (в порядке убывания, без сортировки).
  2. Получите Address узлов, связанных с каждым Transaction.
  3. Для каждого отдельного узла Address создайте список всех связанных Transaction узлов (в порядке убывания timestamp, без сортировки) и получите первый из списка.
  4. Возвращает каждый отдельный узел Address и его самый последний соответствующий узел Transaction.

Этот запрос будет масштабироваться линейно с количеством соответствующих Transactions.Если ваш сценарий использования позволяет это, вы можете получить более быстрые результаты, сократив число соответствующих Transactions, также поместив нижнюю границу в ваше предложение WHERE.

...