Neo4j Cypher查询,用于基于特征delta查找节点



在我的Neo4j/Spring Data Neo4j 4项目中,我有一个实体:Product

每个Product都有一个Integer性质——price

例如,我有以下产品的价格:

Product1.price = 100
Product2.price = 305
Product3.price = 10000
Product4.price = 1000
Product5.price = 220

产品之间没有相互联系的关系。

我需要根据初始价格值(Cypher查询参数)找到一组产品(路径),这些产品通过最大价格增量(Cypher查询参数)相互区分。

例如,我需要在Neo4j数据库中查找从price=50和pricedelta=150开始的所有产品。作为输出,我希望得到以下产品:

Product1.price = 100
Product5.price = 220
Product2.price = 305

计算结果如下:

起点价格=50,因此第一个产品的价格应不低于50且不超过200(50+150)。因此,基于此,我们从我们的目录中找到了一种价格为100的产品。第二种产品的价格应不低于100且不超过250(100+150)。。这是一个价格为220的产品。第三个价格不低于220且不超过370。这是一款价格=305 的产品

你能展示一个Cypher查询,可以找到这类产品吗。

作为一种替代解决方案,它的查询速度应该更快,但需要更多的维护和维护才能正常工作(尤其是在产品价格数据快速变化的情况下),您可以在产品节点之间按升序创建关系,并将delta作为关系属性。

以下是如何使用APOC程序创建此文件:

MATCH (p:Product)
WITH p 
ORDER BY p.price ASC
WITH apoc.coll.pairsMin(COLLECT(p)) as products
UNWIND products as prodPairs
WITH prodPairs[0] as prod1, prodPairs[1] as prod2
CREATE (prod1)-[r:NextProd]->(prod2)
SET r.delta = prod2.price - prod1.price

以下是设置好后可以查询的方法。

WITH {startPrice:50, delta:150} as params
WITH params, params.startPrice + params.delta as ceiling
MATCH (start:Product)
WHERE params.startPrice <= start.price <= ceiling
WITH start, params
ORDER BY start.price ASC
LIMIT 1
MATCH (start)-[r:NextProd*0..]->(product:Product)
WHERE ALL(rel in r WHERE rel.delta <= params.delta)
RETURN DISTINCT product

这应该是一个相当快的查询,因为当变量匹配达到一个超过所需delta的关系时,ALL()谓词应该切断它。

当然,不利的一面是,你需要确保影响这个链表结构的每个操作(添加或删除产品以及更改产品价格)都能正确地调整结构,你可能需要考虑锁定方法来确保线程安全,这样在产品和/或价格同时更新时,你就不会破坏链表。

这在Cypher中执行相当复杂。我想到的唯一方法是使用REDUCE()函数和CASE语句,如果产品在列表中最后一个产品的价格增量内,则有条件地将产品添加到列表的末尾。

请记住,使用这种方法无法缩短产品的加工时间。如果总共有100万个产品,并且我们在订购的产品列表中发现只有前两个产品在该delta模式中,则此查询将继续检查这100万个商品中的每一个剩余商品,尽管它们都不会添加到我们的列表中。

此查询应该适用于您。

WITH {startPrice:50, delta:150} as params
MATCH (p:Product)
WHERE p.price >= params.startPrice
WITH params, p
ORDER BY p.price asc
WITH params, COLLECT(p) as products
WITH params, TAIL(products) as products, HEAD(products) as first
WHERE first.price <= params.startPrice + params.delta
WITH REDUCE(prods = [first], prod in products | 
CASE WHEN prod.price <= LAST(prods).price + params.delta 
THEN prods + prod 
ELSE prods END) as products
RETURN products

解决方案需要在迭代过程中传递中间结果。一个有趣的问题,因为今天的密码并没有直接提供这种可能性。作为练习(草图),使用APOC库中的apoc.periodic.commit程序:

CALL apoc.create.uuid() YIELD uuid
CALL apoc.periodic.commit("
MERGE (H:tmpVars {id: {tmpId}})
ON CREATE SET H.prices = [],
H.lastPrice = {lastPrice}, 
H.delta = {delta} 
WITH H
MATCH (P:Product) WHERE P.price > H.lastPrice AND 
P.price < H.lastPrice + H.delta
WITH H, max(P.price) as lastPrice
SET H.lastPrice = lastPrice, 
H.prices = H.prices + lastPrice
RETURN 1
", {tmpId: uuid, delta: 150, lastPrice: 50}
) YIELD updates, executions, runtime
MATCH (T:tmpVars {id: uuid}) 
WITH T, T.prices as prices DETACH DELETE T
WITH prices 
UNWIND prices as price
MATCH (P:Product) WHERE P.price = price
RETURN P ORDER BY P.price ASC

最新更新