найти все предметы, которые не были куплены человеком, и посчитать, сколько раз они были куплены - PullRequest
0 голосов
/ 20 января 2019

У меня есть график, который выглядит следующим образом.

enter image description here

Я хочу найти все предметы, купленные людьми, купившими одинаковые предметыкак Gremlin с использованием cypher.

По сути, я хочу имитировать запрос в gremlin примерах, которые выглядят так

g.V().has("name","gremlin")
    .out("bought").aggregate("stash")
    .in("bought").out("bought")
        .where(not(within("stash")))
    .groupCount()
        .order(local).by(values,desc) 

Я пытался сделать это следующим образом

MATCH (n)-[:BOUGHT]->(g_item)<-[:BOUGHT]-(r),
      (r)-[:BOUGHT]->(n_item)
WHERE 
    n.name = 'Gremlin' 
    AND NOT (n)-[:BOUGHT]->(n_item)
RETURN n_item.id, count(*) as frequency
ORDER by frequency DESC

но, похоже, он не считается frequencies должным образом - они кажутся в два раза больше.

4 - 4
5 - 2
3 - 2

В то время как 3 и 5 были куплены только один рази 4 был куплен 2 раза.В чем проблема?

1 Ответ

0 голосов
/ 21 января 2019

Сайфер интересуется путями, и ваш МАТЧ находит следующее:

  • 2 пути к элементу 3 через Rexter (через элементы 2 и 1)
  • 2 пути к элементу5 сквозных труб (через пункты 1 и 2)
  • 4 пути к пункту 4 через Рекстер и трубы (через пункты 1 и 2 для каждого человека)

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

Чтобы получить точные подсчеты, вам нужно либо сопоставить с разными r пользователями, и только затем сопоставить с предметами, купленными r пользователями (если их нет в наборе купленных предметов).от Gremlin), ИЛИ вам нужно выполнить весь матч, но перед подсчетом получите отдельные предметы по каждому человеку, чтобы каждый предмет на человека встречался только один раз ... затем подсчитайте количество по каждому предмету (подсчитывается по всем лицам).

Вот запрос, который использует второй подход

MATCH (n:Person)-[:BOUGHT]->(g_item) 
WHERE n.name = 'Gremlin' 
WITH n, collect(g_item) as excluded
UNWIND excluded as g_item // now you have excluded list to use later
MATCH (g_item)<-[:BOUGHT]-(r)-[:BOUGHT]->(n_item)
WHERE r <> n AND NOT n_item in excluded
WITH DISTINCT r, n_item
WITH n_item, count(*) as frequency
RETURN n_item.id, frequency
ORDER by frequency DESC

Вы должны использовать метки на вашем графике, и вы должны использовать их в своем запросе, чтобы использовать индексы и быстро найтиотправная точка на графике.В вашем случае индекс: Person (имя) и использование метки: Person в запросе должны сделать это быстрым, даже если будет добавлено больше узлов и больше: Person добавлены в график.

EDIT

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

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

MATCH (n:Person)-[:BOUGHT*2]-(r)-[:BOUGHT]->(n_item)
WHERE n.name = 'Gremlin' 
WITH DISTINCT n, r, n_item
WHERE NOT (n)-[:BOUGHT]->(n_item)
RETURN n_item.id, count(*) as frequency
ORDER by frequency DESC

Я добавляю быстрый ярлык в ваш матч, используя: BOUGHT *2 для обозначения двух: BOUGHT hops to r, так как нас не волнует промежуточный элемент.

...