繁体   English   中英

Neo4j Cypher查询基于特征增量查找节点

[英]Neo4j Cypher query for finding nodes based on characteristics deltas

在我的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查询参数)相互区分。

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

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

计算看起来像:

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

能否请您展示一个可以找到这类产品的Cypher查询。

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

请记住,使用这种方法无法使产品的处理短路。 如果总产品有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

该解决方案需要在迭代期间传输中间结果。 一个有趣的问题,因为今天cypher没有直接提供这种可能性。 作为练习(草图)使用APOC -library中的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

作为一种替代解决方案,查询速度应该快得多,但需要更多维护和保养以保持正常工作(特别是在快速变化的产品价格数据时),您可以按升序价格顺序在产品节点之间创建关系,并将增量保持为关系属性。

以下是使用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

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

当然,缺点是您需要确保每个影响此链表结构的操作(添加或删除产品和更改产品价格)都能正确调整结构,您可能需要考虑锁定方法以确保线程安全因此,如果产品和/或价格同时更新,则不会破坏链表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM