2016-12-06 69 views
2

我是使用3.0版neo4j的新手。我有一個巨大的事務數據集,我將其轉換爲圖形模型。我需要將下面的SQL查詢翻譯成密碼。如何以最佳方式將SQL查詢轉換爲密碼?

create table calc_base as 
select a.ticket_id ticket_id, b.product_id, b.product_desc, 
     a.promotion_flag promo_flag, 
     sum(quantity) sum_units, 
     sum(sales) sum_sales 
from fact a 
    inner join dimproduct b on a.product_id = b.product_id  
where store_id in (select store_id from dimstore) 
and b.product_id in (select product_id from fact group by 1 order by count(distinct ticket_id) desc limit 5000) 
group by 1,2,3,4; 

這是我的ER diagram和相應的graph model。我對這個查詢的關係是:

MATCH (a:PRODUCT) 
MATCH (b:FACT {PRODUCT_ID: a.PRODUCT_ID}) 
CREATE (b)-[:HAS_PRODUCT]->(a); 

MATCH (a:STORE) 
MATCH (b:FACT {STORE_ID: a.STORE_ID}) 
CREATE (b)-[:HAS_STORE]->(a); 

我的暗號翻譯這個查詢:

PROFILE 
MATCH (b:PRODUCT) 
MATCH (a:FACT) 
MATCH (c:STORE) 
CREATE (d:CALC_BASE {TICKET_ID: a.TICKET_ID, PRODUCT_ID: a.PRODUCT_ID, PRODUCT_DESC: b.PRODUCT_DESC, 
     PROMO_FLAG: a.PROMOTION_FLAG, KPI_UNITS: SUM(a.QUANTITY_ABS), KPI_SALES: SUM(a.SALES_ABS) }) 
    Q = (MATCH (e:FACT) 
    WITH count(PRODUCT_ID) AS PRO_ID_NUM , COUNT(DISTINCT TICKET_ID) AS TICKET_ID_NUM 
    ORDER BY TICKET_ID_NUM DESC) 
WHERE b.PRODUCT_ID = Q 
ORDER BY TICKET_ID, PRODUCT_ID, PRODUCT_DESC, PROMO_FLAG 

我的主要問題是界定在暗號group by和子查詢。 如何以最佳方式將此查詢寫入密碼?

+2

歡迎來到堆棧溢出和圖形數據庫! :-)爲了利用圖形數據庫的強大功能,必須將連接映射到邊緣(或Neo4j中的_relationships_)。因此,如果'p_id'屬性上連接了'MYTABLE'和'TMP_P',則應該添加'(:MyTable) - [:REL] - >(:TmpP)'關係。 (請注意,按照慣例,節點標籤是CamelCase,關係是大寫的。)有關RDBMS開發人員的優秀指南:請參見本白皮書(https://neo4j.com/resources/rdbms-developer-graph-white-paper/) )和[post](https://neo4j.com/developer/guide-sql-to-cypher/)。 –

回答

1

其中之一是Cypher中沒有GROUP BY,因爲分組列在每一行中都隱含着非聚合列。

我假設你有約束和索引設置?您需要爲正式查詢正確設置這些設置。

我看到的一個主要的紅旗是在這些查詢中並沒有任何關係,並且可能在您的整個數據模型中。圖形數據庫被用來模擬事物之間的關係,並且這些往往取代關係數據庫中外鍵的概念。我會講更多更好的方法來最終建模數據。

這就是說,我會採取一個刺激,用你當前的數據模型來翻譯它。

我的做法是從內到外。首先讓我們獲取允許的store_id和b.product_id值的集合。

// first collect allowed STORE_IDs 
MATCH (s:STORE) 
WITH COLLECT(s.STORE_ID) as STORE_IDs 
MATCH (e:FACT) 
// now get PRODUCT_IDs with the most associated TICKET_IDs 
WITH STORE_IDs, e.PRODUCT_ID, COUNT(DISTICT e.TICKET_ID) as TICKET_ID_CNT 
ORDER BY TICKET_ID_CNT DESC 
LIMIT 5000 
WITH STORE_IDs, COLLECT(e.PRODUCT_ID) as PRODUCT_IDs 
// we now have 1 row with both collections, and will do membership checking with them later 
// next get only PRODUCT nodes with PRODUCT_ID in the collection of allowed PRODUCT_IDs 
MATCH (b:PRODUCT) 
WHERE b.PRODUCT_ID in PRODUCT_IDs 
WITH b, STORE_IDs 
// now get FACT nodes with STORE_ID in the collection of allowed STORE_IDs 
// and associated with PRODUCT nodes by PRODUCT_ID 
MATCH (a:FACT) 
WHERE a.STORE_ID in STORE_IDs 
AND a.PRODUCT_ID = b.PRODUCT_ID 
WITH a, b 
// grouping is implicit, the non-aggregation columns are the grouping key 
WITH a.TICKET_ID as TICKET_ID, b.PRODUCT_ID as PRODUCT_ID, b.PRODUCT_DESC as PRODUCT_DESC, a.PROMOTION_FLAG as PROMOTION_FLAG, SUM(a.QUANTITY) as SUM_UNITS, SUM(a.SALES) as SUM_SALES 
CREATE (:CALC_BASE {TICKET_ID:TICKET_ID, PRODUCT_ID:PRODUCT_ID, PRODUCT_DESC:PRODUCT_DESC, PROMO_FLAG:PROMOTION_FLAG, SUM_UNITS:SUM_UNITS, SUM_SALES:SUM_SALES}) 

這應該讓你得到你想要的。

現在回到所有這些的主要問題......您正在使用圖形數據庫來處理非圖形數據和查詢。您正在使用外鍵並試圖加入節點,而不是將它們建模爲關係。您還使用縮寫名稱,這使得很難弄清楚數據的含義以及它應該如何相互關聯。

我給你的建議是重新考慮你的數據模型,特別是你的數據如何連接在一起。尋找你使用外鍵加入的地方,而是考慮如何用你的節點之間的關係來替換它,並且結合這些關係的性質。

數據以更加面向圖的方式進行建模,具有更多面向圖形和性能的查詢,以及易於理解和與其他人交流的數據模型。

編輯

現在,你有不同類型的節點之間的關係,我們可以簡化查詢了一下。

該方法將是類似的,我們仍然會從內而外,而不是一些內部子查詢(雖然與Neo4j 3.1,pattern comprehension可以使用像內部查詢在各種情況下)。

// first get products with the most tickets (top 5k) 
MATCH (f:FACT) 
WITH f.PRODUCT_ID as productID, COUNT(DISTICT f.TICKET_ID) as ticketIDCnt 
ORDER BY ticketIDCnt DESC 
LIMIT 5000 
MATCH (p:PRODUCT) 
WHERE p.PRODUCT_ID = productID 
WITH p 
// with those products, get related facts (graph equivalent of a join) 
MATCH (p)<-[:HAS_PRODUCT]-(f:FACT) 
// ensure the fact has a related store. 
// if ALL facts have a related store, you don't need this WHERE clause 
WHERE (f)-[:HAS_STORE]->(:STORE) 
WITH f.TICKET_ID as TICKET_ID, p.PRODUCT_ID as PRODUCT_ID, p.PRODUCT_DESC as PRODUCT_DESC, f.PROMOTION_FLAG as PROMOTION_FLAG, SUM(f.QUANTITY) as SUM_UNITS, SUM(f.SALES) as SUM_SALES 
CREATE (:CALC_BASE {TICKET_ID:TICKET_ID, PRODUCT_ID:PRODUCT_ID, PRODUCT_DESC:PRODUCT_DESC, PROMO_FLAG:PROMOTION_FLAG, SUM_UNITS:SUM_UNITS, SUM_SALES:SUM_SALES}) 

同樣,您需要確保在數據模型中有合適的索引和唯一約束來加速匹配。

還有幾個方面你可能想要考慮修改你的數據模型(當然它有意義)。有一個票證ID的概念,但沒有:票證節點。您已創建:CALC_BASE節點,但未將它們與以下內容相關聯:產品或票證。一般來說,查看你仍在使用外鍵概念的地方是很有用的,並且看看把它們建模爲與其他節點的關係是否會更好。

再次在GROUP BY上,這是在Cypher中爲您處理的。您的行由非聚合列和聚合列組成。 Cypher自動將非聚合列用作分組鍵(相當於按這些列分組)。由於SUM_UNITS和SUM_SALES是作爲聚合函數的SUM()操作的結果,所有其他列將自動用作分組鍵。

+0

非常感謝@InverseFalcon!我用更多的細節和更好的命名約定更新了我的問題。 – Arezoo

+0

很高興看到圖中的關係。問題仍然是關於子查詢和分組?因爲該方法幾乎相同:不要嘗試將sql查詢的結構與內部查詢進行匹配。相反,從內到外的工作。構建稍後用於檢查成員資格的集合,並使用WITH連接查詢的不同部分,並將這些數據傳遞給稍後使用。至於GROUP BY,這是隱含的,基於非聚合列,所以它幾乎爲您處理。 – InverseFalcon

+0

您的方法正在致謝。但現在通過了解FACT.product_id = PRODUCT.product_id和FACT.store_id = STORE.store_id條件下的FACT,STORE和PRODUCT節點之間的關係,我們不需要將所有sql條件轉換爲密碼: 'inner join dimproduct b on a.product_id = b.product_id' '其中store_id(從dimstore選擇store_id)' '和b.product_id in(select product_id from fact)' 我對不對?如果是的話,通過從密碼中刪除上面的連接和條件如何執行「group by」? – Arezoo