2013-10-25 71 views
4

我的設置:Neo4j的增加等待時間上的Cypher查詢+ REST API SKIP增加

Java(TM) SE Runtime Environment (build 1.7.0_45-b18) 
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode) 
Neo4j 2.0.0-M06 Enterprise 

首先,我確信我通過執行以下回暖緩存:的

START n=node(*) RETURN COUNT(n); 
START r=relationship(*) RETURN count(r); 

大小表是63,677個節點和7,169,995個關係

現在我有以下查詢:

START u1=node:node_auto_index('uid:39') 
MATCH (u1:user)-[w:WANTS]->(c:card)<-[h:HAS]-(u2:user) 
WHERE u2.uid <> 39 
WITH u2.uid AS uid, (CASE WHEN w.qty < h.qty THEN w.qty ELSE h.qty END) AS have 
RETURN uid, SUM(have) AS total 
ORDER BY total DESC 
SKIP 0 
LIMIT 25 

此UID有大約40k +的結果,我希望能夠分頁。最初的跳躍大約是773ms。我嘗試了第2頁(跳過25),延遲大約在500頁左右,只漲到900ms,所以我沒有真正打擾。現在我嘗試了一些快速尋呼,並跳過了幾千,所以我做了1000,然後是2000,然後是3000.我希望ORDER BY的安排已經被Neo4j緩存,並且使用SKIP只會移動到結果中的那個索引,必須再次遍歷每一個。但是,對於每一千跳過,我都使延遲增加了很多。這不僅僅是高速緩存預熱,因爲一個我已經熱身緩存和兩個,我嘗試同樣跳過幾次對每個跳躍和它產生了相同的結果:

SKIP 0: 773ms 
SKIP 1000: 1369ms 
SKIP 2000: 2491ms 
SKIP 3000: 3899ms 
SKIP 4000: 5686ms 
SKIP 5000: 7424ms 

現在到底會想誰查看5000頁的結果?甚至40K?! :) 好點子!我可能會限制用戶可以查看的最大結果,但我只是對這種現象感到好奇。請問有人請解釋爲什麼Neo4j似乎正在通過似乎已經知道的東西重新迭代?

這裏是我的0跳過分析:

==> ColumnFilter(symKeys=["uid", " INTERNAL_AGGREGATE65c4d6a2-1930-4f32-8fd9-5e4399ce6f14"], returnItemNames=["uid", "total"], _rows=25, _db_hits=0) 
==> Slice(skip="Literal(0)", _rows=25, _db_hits=0) 
==> Top(orderBy=["SortItem(Cached( INTERNAL_AGGREGATE65c4d6a2-1930-4f32-8fd9-5e4399ce6f14 of type Any),false)"], limit="Add(Literal(0),Literal(25))", _rows=25, _db_hits=0) 
==>  EagerAggregation(keys=["uid"], aggregates=["( INTERNAL_AGGREGATE65c4d6a2-1930-4f32-8fd9-5e4399ce6f14,Sum(have))"], _rows=41659, _db_hits=0) 
==>  ColumnFilter(symKeys=["have", "u1", "uid", "c", "h", "w", "u2"], returnItemNames=["uid", "have"], _rows=146826, _db_hits=0) 
==>   Extract(symKeys=["u1", "c", "h", "w", "u2"], exprKeys=["uid", "have"], _rows=146826, _db_hits=587304) 
==>   Filter(pred="((NOT(Product(u2,uid(0),true) == Literal(39)) AND hasLabel(u1:user(0))) AND hasLabel(u2:user(0)))", _rows=146826, _db_hits=146826) 
==>    TraversalMatcher(trail="(u1)-[w:WANTS WHERE (hasLabel(NodeIdentifier():card(1)) AND hasLabel(NodeIdentifier():card(1))) AND true]->(c)<-[h:HAS WHERE (NOT(Product(NodeIdentifier(),uid(0),true) == Literal(39)) AND hasLabel(NodeIdentifier():user(0))) AND true]-(u2)", _rows=146826, _db_hits=293696) 

而對於5000跳過:

==> ColumnFilter(symKeys=["uid", " INTERNAL_AGGREGATE99329ea5-03cd-4d53-a6bc-3ad554b47872"], returnItemNames=["uid", "total"], _rows=25, _db_hits=0) 
==> Slice(skip="Literal(5000)", _rows=25, _db_hits=0) 
==> Top(orderBy=["SortItem(Cached( INTERNAL_AGGREGATE99329ea5-03cd-4d53-a6bc-3ad554b47872 of type Any),false)"], limit="Add(Literal(5000),Literal(25))", _rows=5025, _db_hits=0) 
==>  EagerAggregation(keys=["uid"], aggregates=["( INTERNAL_AGGREGATE99329ea5-03cd-4d53-a6bc-3ad554b47872,Sum(have))"], _rows=41659, _db_hits=0) 
==>  ColumnFilter(symKeys=["have", "u1", "uid", "c", "h", "w", "u2"], returnItemNames=["uid", "have"], _rows=146826, _db_hits=0) 
==>   Extract(symKeys=["u1", "c", "h", "w", "u2"], exprKeys=["uid", "have"], _rows=146826, _db_hits=587304) 
==>   Filter(pred="((NOT(Product(u2,uid(0),true) == Literal(39)) AND hasLabel(u1:user(0))) AND hasLabel(u2:user(0)))", _rows=146826, _db_hits=146826) 
==>    TraversalMatcher(trail="(u1)-[w:WANTS WHERE (hasLabel(NodeIdentifier():card(1)) AND hasLabel(NodeIdentifier():card(1))) AND true]->(c)<-[h:HAS WHERE (NOT(Product(NodeIdentifier(),uid(0),true) == Literal(39)) AND hasLabel(NodeIdentifier():user(0))) AND true]-(u2)", _rows=146826, _db_hits=293696) 

唯一的區別是在頂部的功能LIMIT子句。我希望我們能按預期完成這項工作,我真的不想深入研究爲Web應用程序製作嵌入式Neo4j +我自己的Jetty REST API。

+0

如果您在neo4j-shell或控制檯中描述問題,您是否看到任何值得注意的內容? – jjaderberg

+0

我添加了0和5000跳過的查詢配置文件。結果似乎沒有太大的差異。只有Top功能中的限制。 – voldomazta

回答

2

結果沒有被緩存,否則服務器內部的大量內存將持有很可能不被使用的結果。

而且正如您所說的,人們大多對第一頁或前兩頁感興趣,然後優化搜索。

如果您需要更可預測的分頁性能,請在第一個位置將更多結果從neo中拉出,然後將它們粘貼到您的用戶會話中並從那裏提供服務。您可以使用比數據庫更多的上下文信息(例如,用戶行爲配置文件或高級用戶標誌等)來完成此操作。

+0

我同意我可能問得太多。我猜想將結果提交給MongoDB集合,並對總值進行排序以對其進行排序並不是一個壞主意。我可以將結果緩存到那裏,讓用戶在5分鐘內獲得新的結果。 – voldomazta