2015-12-25 35 views
1

你們中的一些人可能會爭辯說,這是programmers.stackexchange.com的問題,但是通過了解Stack Overflow的Help Center我相信這是一個特定的編程問題,而我更有可能在這裏得到答覆。如何使用具有不同跳過和限制值的相同查詢對搜索結果進行分頁

我有一個使用ExpressJS和Neo4j數據庫作爲後端的web應用程序。我有一個搜索屏幕,我想使用Neo4j的關係的力量。搜索屏幕接受一個或多個值(即製造年份,燃料類型,變速箱等),然後向ExpressJS發出發佈請求,在此我使用POST請求的參數構建密碼查詢,如下所示,例如:

MATCH 
    (v:VEHICLE),(v)-[:VGEARBOX_IS]->(:VGBOX{type:'MANUAL'}), 
    (v)-[:VCONDITION_IS]->(:VCONDITION{condition:'USED'}) 
WITH DISTINCT v 
WHERE v.manufacture_year = 1990 
MATCH (v)-[r]->(info) 
RETURN v AS vehicle, COLLECT({type:type(r), data:info}) AS details 

比方說,上面的查詢運行,返回以下三輛車和它的屬性

enter image description here

如果有超過20輛的結果,那麼我想分頁的結果,我知道如何工作的,我們使用SKIP和LIMIT,如下所示:

MATCH 
    (v:VEHICLE) 
OPTIONAL MATCH (v)-[r:VFUEL_TYPE|:VGEARBOX_IS|:VHAVING_COLOR|...]->(info) 
RETURN 
    v.vehicle_id AS vehicle_id, 
    v.engine_size AS engine_size, 
    v.published_date AS published_date, 
    COUNT(v) AS count, 
    COLLECT({type:type(r), data:info}) as data 
ORDER BY v.published_date DESC 
SKIP 20 
LIMIT 16 

這裏是工作流,

  • 用戶導航到搜索屏幕這與POST方法和各種輸入字段的表格。
  • 用戶根據他/她希望搜索的內容選擇一些選項。
  • 用戶然後提交表單,該表單向服務器發出發佈請求。
  • 此請求由ROUTE處理,ROUTE使用請求的參數構造上面顯示的密碼查詢。它針對Neo4j數據庫運行密碼並收到結果。
  • 讓我們假設,有200輛車匹配搜索結果。然後我只想顯示20個結果並提供下一個/上一個按鈕。
  • 當用戶看完前20個時,他/她想看到下20個,也就是說當我不得不重新運行用戶初始提交的相同查詢,但是,SKIP值爲20(SKIP值不斷遞增20,當用戶導航到下一頁時,當你移動到上一頁時遞減20)。

我的問題是,什麼是保存的搜索請求(或原始請求產生的暗號),這樣當用戶點擊下一頁/上一頁最好的方法,我重新運行具有不同原始搜索CYPHER查詢SKIP值?每次用戶轉到下一頁/上一頁時,我都不想發出新的POST請求。這個問題可以通過以下方式解決,但不確定哪一個更適合於性能?

  1. 每當用戶點擊一個或下一個頁面中,我提出一個新的POST請求與原始請求的保存價值和重建CYPHER查詢(樁可以是昂貴的 - 我想避免這種情況,請說明爲什麼這是更好的選擇)
  2. 我在Redis中存儲原始密碼查詢,並且每當用戶單擊下一個或上一個時,我從Redis中檢索特定於該用戶的查詢(需要通過cookie,會話或某種隱藏的uuid處理此問題) ,爲SKIP提供新的值並重新運行它(當我從Redis中刪除這個條目時,我必須處理 - 當用戶改變他的搜索或者放棄頁面/站點時刪除應該發生)。
  3. 我存儲在會話查詢(用戶不必先登錄)或其他一些臨時存儲(比Redis的),提供快速訪問(不知道這是安全和有效的)

我肯定有人遇到這個問題,並以有效的方式處理,這就是爲什麼我在這裏發佈問題。請告訴我如何最好地解決這個問題。

回答

1

就性能而言,您應該絕對做的第一件事是使用Cypher parameters。這是將查詢字符串與動態數據分開的一種方法。這樣做的好處是可以防範注入攻擊,但性能更高,因爲如果查詢字符串沒有更改,Neo4j可以爲查詢緩存查詢計劃並反覆使用它。使用參數,您的第一個查詢將如下所示:

MATCH 
    (v:VEHICLE),(v)-[:VGEARBOX_IS]->(:VGBOX{type: {vgearbox_type}}), 
    (v)-[:VCONDITION_IS]->(:VCONDITION{condition: {vcondition}}) 
WITH DISTINCT v 
WHERE v.manufacture_year = {manufacture_year} 
MATCH (v)-[r]->(info) 
RETURN v AS vehicle, COLLECT({type:type(r), data:info}) AS details 
SKIP ({page} - 1) * {per_page} 
LIMIT {per_page} 

您的用於Neo4j的JavaScript庫應該允許您傳遞一個單獨的對象。這裏是對象會是什麼樣子代表了JSON:

{ 
    "vgearbox_type": "MANUAL", 
    "vcondition": "USED", 
    "manufacture_year": 1990, 
    "page": 1, 
    "per_page": 20 
} 

我實在看不出太大的問題,從節點每次做一個新的數據庫查詢。您應該測試實際需要多長時間才能確定它是否真的存在問題。

如果這是您想要緩存的地址,它取決於您的服務器設置。如果Node應用程序和數據庫在同一臺機器上或彼此非常接近,可能這並不重要。否則,您可以使用redis來緩存,該密鑰是您正在查詢的值的組合。如果您正在考慮針對每個用戶進行緩存,那麼您甚至可以使用瀏覽器的本地存儲,但用戶是否經常反覆訪問相同的頁面?您的數據的靜態程度如何,數據是否因用戶而異?

+0

感謝密碼參數的建議,我肯定會考慮注入問題。關於每次用戶轉到下一頁/上一頁時創建新的POST,我應該如何保留原始請求中的帖子值?隱藏的領域?會議? – Raf

+0

我建議發送每個POST的所有表單參數。它根本不應該增加您的請求大小。這可能是隱藏的字段,也可能是您的javascript編寫方式,具體取決於您製作POST的方式。如果你使用類似會話的東西,我懷疑你最終會遇到至少另外一個bug,否則你會試圖跟蹤事情。 –

+0

謝謝您的回覆,感謝您的意見。 – Raf

相關問題