2015-01-15 24 views
16

Giả sử bạn Twitter, và:Neo4j: nhãn so với thuộc tính được lập chỉ mục?

  • Bạn có (:User)(:Tweet) nút;
  • Tweet có thể bị gắn cờ; và
  • Bạn muốn truy vấn danh sách các tweet bị gắn cờ hiện đang chờ kiểm duyệt.

Bạn có thể thêm nhãn cho các tweet đó, ví dụ: :AwaitingModeration hoặc thêm và lập chỉ mục một thuộc tính , ví dụ: isAwaitingModeration = true|false.

Có một tùy chọn nào tốt hơn tùy chọn kia không?

Tôi biết câu trả lời tốt nhất có thể là thử và tải thử nghiệm cả :), nhưng có điều gì từ POV thực hiện của Neo4j làm cho một tùy chọn mạnh mẽ hơn hoặc phù hợp cho loại truy vấn này không?

Điều đó có phụ thuộc vào khối lượng tweet ở trạng thái này tại bất kỳ thời điểm cụ thể nào không? Nếu đó là trong 10s so với 1000s, điều đó có tạo nên sự khác biệt không?

Ấn tượng của tôi là nhãn phù hợp hơn với khối lượng lớn các nút, trong khi các thuộc tính được lập chỉ mục tốt hơn cho các khối nhỏ hơn (lý tưởng, các nút duy nhất), nhưng tôi không chắc liệu đó có thực sự đúng hay không.

Cảm ơn!

+0

Tôi thực sự không biết nhưng tôi nghĩ nhãn sẽ hiệu quả hơn. Nếu bạn sử dụng nhãn thì bạn có thể loại trừ tất cả các nút '(: Tweet)' bằng cách thậm chí không khớp với chúng. Nếu bạn sử dụng phương thức thuộc tính trên nút '(: Tweet)' thì đối sánh của bạn sẽ vẫn bao gồm nhãn 'Tweet' trong trận đấu. Trong thế giới quan hệ hoặc thư mục tôi không nghĩ rằng bạn sẽ lập chỉ mục giá trị tài sản vì nó sẽ có chọn lọc thấp. Tôi được quan tâm để xem câu trả lời mặc dù. –

Trả lời

27

CẬP NHẬT: Theo dõi blog post xuất bản.

Đây là câu hỏi phổ biến khi chúng tôi lập mô hình bộ dữ liệu cho khách hàng và trường hợp sử dụng điển hình cho các thực thể Hoạt động/Không hoạt động.

Đây là một thông tin phản hồi rất ít về những gì tôi đã có kinh nghiệm có giá trị trong Neo4j2.1.6:

Point 1. Bạn sẽ không có sự khác biệt trong db truy cập giữa khớp trên nhãn hoặc trên một tài sản được lập chỉ mục và trở lại các nút

Point 2. sự khác biệt sẽ được gặp phải khi các nút như vậy là ở phần cuối của một mô hình, ví dụ

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 

Trong trường hợp này, Cypher sẽ không tận dụng chỉ mục :Post(published).

Do đó việc sử dụng nhãn hiệu quả hơn trong trường hợp bạn có nhãn ActivePost, ví dụ: :

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 

điểm 3. Luôn luôn sử dụng nhãn cho mặt tích cực, có nghĩa là đối với trường hợp trên, có một nhãn Thư nháp sẽ buộc bạn phải thực hiện các truy vấn sau đây:

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

Nghĩa là Cypher sẽ mở ra mỗi nút tiêu đề nhãn và làm một bộ lọc vào nó.

Point 4. Tránh có nhu cầu để phù hợp trên nhiều nhãn

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 

này sẽ cho kết quả trong quá trình tương tự cho Cypher rằng ở điểm 3.

Point 5. Nếu có thể , tránh sự cần thiết phải đối sánh trên nhãn bằng cách nhập các mối quan hệ được đặt tên tốt

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 

Sẽ là performant hơn, bởi vì nó sẽ sử dụng tất cả sức mạnh của đồ thị và chỉ cần làm theo các mối quan hệ từ nút kết quả là không có db nhiều truy cập hơn phù hợp với các nút dùng và do đó không có lọc trên nhãn.

Đây là 0,02 €

+4

Câu trả lời xuất sắc và toàn diện. Tôi học được rất nhiều, và tôi thích học tập. Dường như với tôi một số nguyên tắc của chiến lược mô hình neo4j tốt vẫn đang phát triển. Sẽ rất tốt nếu cộng đồng có thể thu thập thêm các nguyên tắc mô hình hóa này trong tài liệu, vì nhiều người dùng mới là biểu đồ neophytes. – FrobberOfBits

+0

Tôi rất vinh dự nhận được nhận xét đó của bạn. Cảm ơn ;-) –

+2

Đồng ý, cảm ơn bạn đã trả lời kỹ lưỡng. Tôi có một số câu hỏi tiếp theo; quá xấu hộp bình luận nhỏ bé này là nơi duy nhất cho nó. Điểm 2: Tôi không tin rằng các nhãn tạo * lượt truyền tải * nhanh hơn nữa. Chỉ có loại mối quan hệ sau đó, phải không? Điểm 4: Tại sao chỉ định nhiều nhãn sẽ chậm hơn? Không phải là Cypher đủ thông minh để sử dụng một với cardinality thấp hơn đầu tiên? Nói chung, có thể là tốt đẹp khi gắn vào ví dụ trong q ban đầu: * chỉ * tra cứu toàn cầu, * không * một sự truyền tải từ ví dụ: một nút người dùng. Vì vậy, tôi nghĩ rằng takeaway của tôi cho kịch bản đó là: cả hai tùy chọn là tương đương? –

Các vấn đề liên quan