2015-01-15 4 views
16

Предположим, вы Twitter, а также:Neo4j: метка против индексированного свойства?

  • Вы (:User) и (:Tweet) узлы;
  • Твиты могут быть помечены; и
  • Вы хотите, чтобы запросить список отмеченных твитов, ожидающих модерации.

Вы можете добавить ярлык для этих твитов, например. :AwaitingModeration, или добавить и проиндексировать имущество, т.е. isAwaitingModeration = true|false.

Один из вариантов по качеству лучше другого?

Я знаю, что лучший ответ - это, вероятно, попробовать и загрузить тест как :), но есть ли что-либо из реализации POV от Neo4j, что делает один вариант более надежным или подходящим для такого рода запросов?

В зависимости от объема твитов в этом состоянии в любой момент? Если это в 10-е и 1000-е годы, это имеет значение?

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

Спасибо!

+0

Я действительно не знаю, но я думаю, что ярлык будет более эффективным. Если вы используете метку, вы можете исключить все узлы '(: Tweet), даже не сопоставляя их. Если вы используете метод свойства на узле '(: Tweet)', то ваш матч по-прежнему будет содержать метку 'Tweet' в матче. В реляционных или каталогах миров я не думаю, что вы бы указали значение свойства, поскольку оно имело бы низкую избирательность. Однако мне интересно узнать ответы. –

ответ

27

ОБНОВЛЕНИЕ: Последующий отчет blog post опубликован.

Это распространенный вопрос, когда мы моделируем наборы данных для клиентов и типичный пример использования для активных/неактивных объектов.

Это немного обратная связь о том, что я испытал действительно для Neo4j2.1.6:

Пункта 1. Вы не будете иметь разницы в дБ доступы между согласованием на этикетке или на индексированном имущество и возврате узлы

Пункт 2. разница будет встречаться, когда такие узлы находятся в конце узора, например

MATCH (n:User {id:1}) 
WITH n 
MATCH (n)-[:WRITTEN]->(post:Post) 
WHERE post.published = true 
RETURN n, collect(post) as posts; 

-

PROFILE MATCH (n:User) WHERE n._id = 'c084e0ca-22b6-35f8-a786-c07891f108fc' 
> WITH n 
> MATCH (n)-[:WRITTEN]->(post:BlogPost) 
> WHERE post.active = true 
> RETURN n, size(collect(post)) as posts; 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| n                                       | posts | 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| Node[118]{_id:"c084e0ca-22b6-35f8-a786-c07891f108fc",login:"joy.wiza",password:"7425b990a544ae26ea764a4473c1863253240128",email:"[email protected]"} | 1  | 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
1 row 

ColumnFilter(0) 
    | 
    +Extract 
    | 
    +ColumnFilter(1) 
     | 
     +EagerAggregation 
     | 
     +Filter 
      | 
      +SimplePatternMatcher 
      | 
      +SchemaIndex 

+----------------------+------+--------+----------------------+----------------------------------------------------------------------------+ 
|    Operator | Rows | DbHits |   Identifiers |                  Other | 
+----------------------+------+--------+----------------------+----------------------------------------------------------------------------+ 
|  ColumnFilter(0) | 1 |  0 |      |              keep columns n, posts | 
|    Extract | 1 |  0 |      |                  posts | 
|  ColumnFilter(1) | 1 |  0 |      |           keep columns n, AGGREGATION153 | 
|  EagerAggregation | 1 |  0 |      |                   n | 
|    Filter | 1 |  3 |      | (hasLabel(post:BlogPost(1)) AND Property(post,active(8)) == { AUTOBOOL1}) | 
| SimplePatternMatcher | 1 |  12 | n, post, UNNAMED84 |                   | 
|   SchemaIndex | 1 |  2 |     n, n |            { AUTOSTRING0}; :User(_id) | 
+----------------------+------+--------+----------------------+----------------------------------------------------------------------------+ 

Total database accesses: 17 

В этом случае Cypher не будет использовать индекс :Post(published).

Таким образом, использование этикеток является более эффективным в том случае, если у вас есть ярлык ActivePost, например. :

neo4j-sh (?)$ PROFILE MATCH (n:User) WHERE n._id = 'c084e0ca-22b6-35f8-a786-c07891f108fc' 
> WITH n 
> MATCH (n)-[:WRITTEN]->(post:ActivePost) 
> RETURN n, size(collect(post)) as posts; 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| n                                       | posts | 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| Node[118]{_id:"c084e0ca-22b6-35f8-a786-c07891f108fc",login:"joy.wiza",password:"7425b990a544ae26ea764a4473c1863253240128",email:"[email protected]"} | 1  | 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
1 row 

ColumnFilter(0) 
    | 
    +Extract 
    | 
    +ColumnFilter(1) 
     | 
     +EagerAggregation 
     | 
     +Filter 
      | 
      +SimplePatternMatcher 
      | 
      +SchemaIndex 

+----------------------+------+--------+----------------------+----------------------------------+ 
|    Operator | Rows | DbHits |   Identifiers |       Other | 
+----------------------+------+--------+----------------------+----------------------------------+ 
|  ColumnFilter(0) | 1 |  0 |      |   keep columns n, posts | 
|    Extract | 1 |  0 |      |       posts | 
|  ColumnFilter(1) | 1 |  0 |      | keep columns n, AGGREGATION130 | 
|  EagerAggregation | 1 |  0 |      |        n | 
|    Filter | 1 |  1 |      |  hasLabel(post:ActivePost(2)) | 
| SimplePatternMatcher | 1 |  4 | n, post, UNNAMED84 |         | 
|   SchemaIndex | 1 |  2 |     n, n |  { AUTOSTRING0}; :User(_id) | 
+----------------------+------+--------+----------------------+----------------------------------+ 

Total database accesses: 7 

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

MATCH (n:User {id:1}) 
WITH n 
MATCH (n)-[:POST]->(post:Post) 
WHERE NOT post :Draft 
RETURN n, collect(post) as posts; 

Это означает, что Cypher будет открывать каждый заголовки меток узлов и сделать фильтр на нем.

Пункт 4. Избегайте имея необходимость согласования на нескольких лейблах

MATCH (n:User {id:1}) 
WITH n 
MATCH (n)-[:POST]->(post:Post:ActivePost) 
RETURN n, collect(post) as posts; 

neo4j-sh (?)$ PROFILE MATCH (n:User) WHERE n._id = 'c084e0ca-22b6-35f8-a786-c07891f108fc' 
> WITH n 
> MATCH (n)-[:WRITTEN]->(post:BlogPost:ActivePost) 
> RETURN n, size(collect(post)) as posts; 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| n                                       | posts | 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| Node[118]{_id:"c084e0ca-22b6-35f8-a786-c07891f108fc",login:"joy.wiza",password:"7425b990a544ae26ea764a4473c1863253240128",email:"[email protected]"} | 1  | 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
1 row 

ColumnFilter(0) 
    | 
    +Extract 
    | 
    +ColumnFilter(1) 
     | 
     +EagerAggregation 
     | 
     +Filter 
      | 
      +SimplePatternMatcher 
      | 
      +SchemaIndex 

+----------------------+------+--------+----------------------+---------------------------------------------------------------+ 
|    Operator | Rows | DbHits |   Identifiers |               Other | 
+----------------------+------+--------+----------------------+---------------------------------------------------------------+ 
|  ColumnFilter(0) | 1 |  0 |      |           keep columns n, posts | 
|    Extract | 1 |  0 |      |               posts | 
|  ColumnFilter(1) | 1 |  0 |      |        keep columns n, AGGREGATION139 | 
|  EagerAggregation | 1 |  0 |      |                n | 
|    Filter | 1 |  2 |      | (hasLabel(post:BlogPost(1)) AND hasLabel(post:ActivePost(2))) | 
| SimplePatternMatcher | 1 |  8 | n, post, UNNAMED84 |                | 
|   SchemaIndex | 1 |  2 |     n, n |         { AUTOSTRING0}; :User(_id) | 
+----------------------+------+--------+----------------------+---------------------------------------------------------------+ 

Total database accesses: 12 

Это приведет к тому же процессу для Cypher, что на пункте 3.

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

MATCH (n:User {id:1}) 
WITH n 
MATCH (n)-[:PUBLISHED]->(p) 
RETURN n, collect(p) as posts 

-

MATCH (n:User {id:1}) 
WITH n 
MATCH (n)-[:DRAFTED]->(post) 
RETURN n, collect(post) as posts; 

neo4j-sh (?)$ PROFILE MATCH (n:User) WHERE n._id = 'c084e0ca-22b6-35f8-a786-c07891f108fc' 
> WITH n 
> MATCH (n)-[:DRAFTED]->(post) 
> RETURN n, size(collect(post)) as posts; 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| n                                       | posts | 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| Node[118]{_id:"c084e0ca-22b6-35f8-a786-c07891f108fc",login:"joy.wiza",password:"7425b990a544ae26ea764a4473c1863253240128",email:"[email protected]"} | 3  | 
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
1 row 

ColumnFilter(0) 
    | 
    +Extract 
    | 
    +ColumnFilter(1) 
     | 
     +EagerAggregation 
     | 
     +SimplePatternMatcher 
      | 
      +SchemaIndex 

+----------------------+------+--------+----------------------+----------------------------------+ 
|    Operator | Rows | DbHits |   Identifiers |       Other | 
+----------------------+------+--------+----------------------+----------------------------------+ 
|  ColumnFilter(0) | 1 |  0 |      |   keep columns n, posts | 
|    Extract | 1 |  0 |      |       posts | 
|  ColumnFilter(1) | 1 |  0 |      | keep columns n, AGGREGATION119 | 
|  EagerAggregation | 1 |  0 |      |        n | 
| SimplePatternMatcher | 3 |  0 | n, post, UNNAMED84 |         | 
|   SchemaIndex | 1 |  2 |     n, n |  { AUTOSTRING0}; :User(_id) | 
+----------------------+------+--------+----------------------+----------------------------------+ 

Total database accesses: 2 

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

Это был мой 0,02 €

+4

Отличный ответ и всеобъемлющий. Я многому научился, и мне нравится учиться. Мне кажется, что некоторые принципы хорошей стратегии моделирования neo4j все еще развиваются. Было бы хорошо, если бы сообщество могло собрать больше этих принципов моделирования в документации, поскольку многие новые пользователи представляют собой неофиты графиков. – FrobberOfBits

+0

Для меня большая честь получить такой комментарий от вас. Спасибо ;-) –

+2

Согласен, спасибо за подробный ответ. У меня есть некоторые последующие вопросы; слишком плохо этот крошечный блок комментариев - единственное место для него. Пункт 2: Я не считаю, что ярлыки совершают * обходы * и быстрее. Тогда имеет значение только тип отношения, верно? Пункт 4: Почему указание большего количества меток будет медленнее? Разве Cypher не достаточно умен, чтобы использовать первую с более низкой мощностью? В общем, неплохо бы придерживаться примера в оригинале q: * просто * глобальный поиск, * не * обход от, например. пользовательский узел. Итак, я думаю, что мой взнос для этого сценария: оба варианта эквивалентны? –

Смежные вопросы