【问题标题】:Neo4j Cypher query for finding nodes based on characteristics deltasNeo4j Cypher 查询,用于根据特征增量查找节点
【发布时间】:2017-02-01 11:12:50
【问题描述】:

在我的 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 和 price delta = 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 会给你一个价格的下限和上限 -/+ delta,但这意味着上限是 200 (50 + 150)。你输出的价格超过了这个,所以我的假设是错误的,但我不知道你想使用什么计算。
  • 类似的东西? WITH 50 AS initPrice, 150 AS delta WITH CASE WHEN (initPrice-delta) > 0 THEN (initPrice-delta) ELSE 0 END AS lowRange, (initPrice+delta) AS highRange MATCH (n:Product) WHERE lowRange
  • 这似乎符合我的假设,但您的示例输出中的价格值不符合该公式(220 和 305 的价格都高于计算的 200 限制)。如果这只是您的示例输出中的一个问题,您能否修复它以避免混淆?
  • 感谢您的回答 - 我用详细的计算算法更新了我的问题
  • 谢谢,添加的细节使这一点更加清晰。

标签: neo4j cypher


【解决方案1】:

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

您可以通过以下方式使用 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() 谓词应该在它达到超过所需增量的关系时切断变量匹配。

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

【讨论】:

  • 谢谢!看起来这是现在最好的方法
  • 这种方法的主要问题是我无法跳过此列表中的某些产品,甚至无法根据查询中的不同条件遍历不同的路径。例如,如果我想添加价格的一些附加条件..比如 WHERE product.color = 'red' 那么这种方法看起来行不通
  • 您将无法跳过产品,但您可以添加其他条件,包括节点本身。在 ALL() 函数中,将其附加到末尾:` AND endNode(rel).color = 'red'`。这将添加额外的要求,即路径中的所有产品都必须是红色的。
【解决方案2】:

这在 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

【讨论】:

  • 非常感谢!是否有任何方法可以优化此模式,以便在寻找产品时不影响性能。也许在目录或其他东西中创建新产品时添加某种关系?性能是该系统的重要标准之一。
  • 我能想到的使用该路线的唯一优化是按价格升序连接产品,并在每个关系上设置一个 delta 属性作为连接节点价格之间的 delta。这将允许您使用 ALL() 执行有效的可变长度匹配,以确保路径中的所有关系增量都低于您的 delta 参数,但如果价格发生变化或产品被定期删除或插入,这将是一项繁重的维护工作。如果您需要更多详细信息,我可以将其添加为单独的答案。
【解决方案3】:

解决方案需要在迭代期间传输中间结果。一个有趣的问题,因为今天 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

【讨论】:

  • 感谢您的回答!您能否也从性能的角度评论这个问题?这种方法如何取决于数据库中的产品编号?
  • @alexanoid 对不起。这只是一个草图,一个想法。没有表现:)
猜你喜欢
  • 2019-08-03
  • 2020-03-04
  • 1970-01-01
  • 1970-01-01
  • 2018-11-17
  • 2014-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多