2015-10-22 20 views
18

Tôi đang cố gắng sử dụng ArangoDB để nhận danh sách bạn bè của bạn bè. Không chỉ là một danh sách bạn bè cơ bản của bạn bè, tôi cũng muốn biết có bao nhiêu người bạn mà người dùng và bạn bè của một người bạn có chung và sắp xếp kết quả. Sau nhiều nỗ lực (lại) bằng văn bản cho truy vấn AQL hiệu suất tốt nhất, đây là những gì tôi đã kết thúc với:Truy vấn bạn bè của bạn bè ArangoDB nhanh nhất (với số lượng)

LET friends = (
    FOR f IN GRAPH_NEIGHBORS('graph', @user, {"direction": "any", "includeData": true, "edgeExamples": { name: "FRIENDS_WITH"}}) 
    RETURN f._id 
) 

LET foafs = (FOR friend IN friends 
    FOR foaf in GRAPH_NEIGHBORS('graph', friend, {"direction": "any", "includeData": true, "edgeExamples": { name: "FRIENDS_WITH"}}) 
    FILTER foaf._id != @user AND foaf._id NOT IN friends 
    COLLECT foaf_result = foaf WITH COUNT INTO common_friend_count 
    RETURN { 
     user: foaf_result, 
     common_friend_count: common_friend_count 
    } 
) 
FOR foaf IN foafs 
    SORT foaf.common_friend_count DESC 
    RETURN foaf 

Thật không may, hiệu suất là không tốt như tôi sẽ đã thích. So với các phiên bản Neo4j của cùng một truy vấn (và dữ liệu), AQL có vẻ hơi chậm hơn một chút (5-10x).

Điều tôi muốn biết là ... Làm cách nào để cải thiện truy vấn của mình để làm cho nó hoạt động tốt hơn?

Trả lời

19

Tôi là một trong những nhà phát triển cốt lõi của ArangoDB và đã cố gắng tối ưu hóa truy vấn của bạn. Vì tôi không có số dataset Tôi chỉ có thể nói về bài kiểm tra dataset của mình và sẽ rất vui khi biết nếu bạn có thể xác thực kết quả của mình.

Đầu tiên nếu tất cả tôi đang chạy trên ArangoDB 2.7 nhưng trong trường hợp cụ thể này, tôi không mong đợi sự khác biệt lớn về hiệu suất là 2,6.

Trong số dataset Tôi có thể thực hiện truy vấn của bạn giống như trong ~ 7 giây. Lần sửa đầu tiên: Trong tuyên bố bạn bè của bạn, bạn sử dụng includeData: true và chỉ trả lại _id. Với includeData: falseGRAPH_NEIGHBORS trực tiếp trả về _id và chúng tôi cũng có thể thoát khỏi subquery đây

LET friends = GRAPH_NEIGHBORS('graph', 
           @user, 
           {"direction": "any", 
           "edgeExamples": { 
            name: "FRIENDS_WITH" 
       }}) 

này đã nhận nó xuống ~ 1,1 giây trên máy tính của tôi. Vì vậy, tôi hy vọng rằng điều này sẽ gần với hiệu suất của Neo4J.

Tại sao điều này có tác động lớn? Trong nội bộ chúng tôi tìm thấy giá trị _id mà không thực sự tải các tài liệu JSON. Trong truy vấn của bạn, bạn không cần bất kỳ dữ liệu nào trong số này, vì vậy chúng tôi có thể tiếp tục an toàn khi không mở nó.

Nhưng bây giờ để cải thiện thực

truy vấn của bạn đi cách "logic" và lần đầu tiên được sử dụng hàng xóm, hơn thấy người hàng xóm của họ, đếm một foaf được tìm thấy mức độ thường xuyên và sắp xếp nó. Điều này có để xây dựng mạng foaf hoàn chỉnh trong bộ nhớ và sắp xếp nó như một toàn thể.

Bạn cũng có thể làm điều đó theo một cách khác: 1. Tìm tất cả friends của người dùng (chỉ _ids) 2. Tìm tất cả foaf (tài liệu đầy đủ) 3. Đối với mỗi foaf tất cả foaf_friends (chỉ _ids) 4. Tìm giao điểm của friendsfoaf_friends và COUNT họ

truy vấn này sẽ như thế này:

LET fids = GRAPH_NEIGHBORS("graph", 
          @user, 
          { 
          "direction":"any", 
          "edgeExamples": { 
           "name": "FRIENDS_WITH" 
           } 
          } 
         ) 
FOR foaf IN GRAPH_NEIGHBORS("graph", 
          @user, 
          { 
           "minDepth": 2, 
           "maxDepth": 2, 
           "direction": "any", 
           "includeData": true, 
           "edgeExamples": { 
           "name": "FRIENDS_WITH" 
           } 
          } 
          ) 
    LET commonIds = GRAPH_NEIGHBORS("graph", 
            foaf._id, { 
            "direction": "any", 
            "edgeExamples": { 
             "name": "FRIENDS_WITH" 
            } 
            } 
           ) 
    LET common_friend_count = LENGTH(INTERSECTION(fids, commonIds)) 
    SORT common_friend_count DESC 
    RETURN {user: foaf, common_friend_count: common_friend_count} 

Trong biểu đồ thử nghiệm của tôi được thực hiện trong ~ 0.024 giây

Vì vậy, đây đã cho tôi một yếu tố 250 nhanh hơn thời gian thực hiện và tôi mong chờ điều này là nhanh hơn so với truy vấn hiện tại của bạn trong Neo4j, nhưng như tôi không có dataset của bạn tôi không thể xác minh nó, nó sẽ là tốt nếu bạn có thể làm điều đó và cho tôi biết.

Một điều cuối cùng

Với edgeExamples: {name : "FRIENDS_WITH" } it is the same as with includeData`, trong trường hợp này chúng ta phải tìm ra cạnh thực tế và nhìn vào nó. Điều này có thể tránh được nếu bạn lưu trữ các cạnh của mình trong các bộ sưu tập riêng biệt dựa trên tên của chúng. Và sau đó loại bỏ các cạnhVí dụ là tốt. Điều này sẽ tiếp tục tăng hiệu suất (đặc biệt là nếu có rất nhiều cạnh).

Future

Stay tuned cho phiên bản tiếp theo của chúng tôi, chúng tôi ngay bây giờ thêm một số chức năng hơn để AQL mà sẽ làm cho trường hợp của bạn dễ dàng hơn để truy vấn và nên cung cấp một tăng hiệu suất.

+0

Cảm ơn! Tôi sẽ kiểm tra, xác minh và chấp nhận câu trả lời của bạn thứ hai! Chúng tôi đánh giá cao thực tế là bạn đã dành thời gian để trả lời câu hỏi của chúng tôi;) –

+1

Trong trường hợp của chúng tôi, cải tiến đầu tiên của bạn nhanh hơn đáng kể so với phiên bản của chúng tôi. Đặc biệt là các truy vấn chậm nhất của chúng tôi được hưởng lợi từ những cải tiến của bạn. Nó thực sự mang lại kết quả AQL rất gần với phiên bản Neo4j. Đối với truy vấn thứ 2 - nó đã làm cho các truy vấn foaf tồi tệ nhất của chúng tôi nhanh hơn, nhưng các truy vấn tốt nhất một chút chậm hơn: (Dù bằng cách nào, cải tiến đầu tiên đã giúp chúng tôi rất nhiều;). –

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