【问题标题】:neo4j - shortest path with conditions include plugin functionsneo4j - 有条件的最短路径包括插件功能
【发布时间】:2018-03-15 00:34:06
【问题描述】:

我对 cypher 的实现有疑问。我的问题是这样的:我有一个数据库模型,这里拍照作为概览:https://www.instpic.de/QTIhBbPgVHBHg5pKwVdk.PNG 解释的缩写。红色节点模拟恒星系统,黄色一个跳跃点。每个跳跃点都有一定的大小,它决定了哪个身体可以通过该点。大小作为属性存储在黄色节点之间的关系中。红色节点中还有代表恒星系统轨道天体的其他节点。 (行星、卫星、空间站等)现在,从太阳系中的任何一点(行星、空间站、月亮),我想找到到同一太阳系或另一个太阳系中另一个躺点的最短路径。此外,我可以使用我编写的插件计算系统内两个天体的距离。这个值现在应该包含在寻找路径中,所以我有数据库上最短的路径,也是太阳系内天体之间的最小距离。我已经有一个查询,不幸的是它失败的部分原因是它的性能。我也觉得这里的路径是非常多变的,所以对数据库模型的改变是很好考虑的。

这是我正在使用的实际查询的一部分:

MATCH (origin:Marketplace)
               WHERE origin.eid = 'c816c4fa501244a48292f5d881103d7f'
               OPTIONAL MATCH (marketplace:Marketplace)-[:Sell]->(currentPrice:Price)-[:Content]->(product:Product)
               OPTIONAL MATCH p = shortestPath((origin)-[:HasMoon|:HasStation|:HasLandingZone|:HasPlanet|:HasJumpPoint|:CanTravel*]-(marketplace))
               WHERE SIZE([rel in relationships(p) WHERE EXISTS(rel.size)]) <= 3 AND ALL(rel IN [rel in relationships(p) WHERE EXISTS(rel.size)] WHERE rel.size IN ['small', 'medium', 'large'])
               WITH origin, marketplace, p, currentPrice, product
               CALL srt.getRoutes(origin, marketplace, p) YIELD node, jump_sizes, jump_gates, jump_distance, hops, distance
               OPTIONAL MATCH (currentPrice)-[:CompletedVotes]->(:Wrapper)-[:CompletedVote]->(voteHistory:CompletedVote)
               OPTIONAL MATCH (currentPrice)-[:CurrentVote]->(vote:Vote)-[:VotedPrices]->(currentVotings)
               WITH node, currentPrice, product, jump_sizes, jump_gates, jump_distance, hops, distance, voteHistory, currentVotings, vote, origin
               WITH {eid: product.eid, displayName: product.displayName, name: product.name, currentPrice: {eid: currentPrice.eid, price: currentPrice.price}, currentVoting: {approved: vote.approved, count: Count(currentVotings), declined: vote.declined, users: Collect(currentVotings.userId), votes: Collect(currentVotings.price), voteAvg: round(100 * avg(currentVotings.price)) / 100}, voteHistory: Collect({votings: voteHistory.votings, users: voteHistory.users, completed: voteHistory.completed, 
               vote: voteHistory.votes}), marketplace: {eid: node.eid, name: node.name, type: node.type, designation: node.designation}, travel: {jumpSizes: jump_sizes, jumpGate: jump_gates, jumpDistance: jump_distance, jumps: hops, totalDistance: distance}} as sellOptions, currentPrice ORDER BY currentPrice.price
               WITH Collect(sellOptions) as sellOptions

目前,此查询运行良好,但现在我想过滤(在“.... dium ',' large '] 之后)”-> 第 5 行)您需要到达的最小总距离你的目的地,我想用我写的插件来实现这一点,它计算路径中的总距离 (getTotalDistance (path AS PATH))

另外:当我从可能的跳跃大小中删除“大”时,我没有得到任何结果,但我的图表中仍然有一条路径可以引导我到达目标。

另外 2:我正在开发 neo4j 3.3.1,我已经设置了这些配置:

cypher.forbid_shortestpath_common_nodes=false

在 3.3.3 中不起作用

EIDT 1:(更详细的解释)

我有一个地方。然后我搜索销售某些产品的市场。为此,我可以指定更多过滤器。我可以例如说我只能通过“大”大小的跳跃点。另外,我只想要 4 个系统之外的市场。

现在,在数据库中查找上述限制,我搜索到我找到的市场的最短路径。 很可能我有几条满足条件的路径。如果是这种情况,我想过滤掉所有最短路径,即必须克服每个太阳系内最小距离的路径。

这足够准确吗?否则,请报告。

【问题讨论】:

  • 您可以在边缘写下您使用插件计算的所有距离,然后使用或修改 apoc 程序中的最短路径算法。你已经试过了吗?或者你有理由不使用它吗?距离可变吗?
  • 如果我没看错,您正在寻找性能更高的 shortestPath?除了尺寸限制之外,您能否更详细地口头描述这方面的要求?看起来您希望限制路径中的跳跃次数?另外,为什么是关系的大小而不是跳跃点节点?
  • 你能不能也PROFILE这个查询并添加查询计划(扩展所有元素)?我们可能会找到一些可以优化的东西。可能至少有一个主要的基数问题正在减慢这一速度。
  • 另一个观察结果...每对相邻的跳跃点之间有两个关系,每个方向都有一个关系(并且可能是同一类型)。是否需要,关系上的属性存在一些差异,或者某些对只存在一种关系而不是两种关系?如果没有,您可以考虑重构,以便每个跳转点对之间仅存在一个关系。
  • 我今天把所有的cmet都过一遍,这里是提前查询计划:instpic.de/KmItH20rwZN9F01dxY8p.png

标签: neo4j cypher graph-databases


【解决方案1】:

尽管 APOC 路径扩展器最适合标签和关系类型,但最新的 APOC 版本可能会有所帮助,因此可能需要对您的模型稍作更改。

尤其是跳跃点的大小。现在这是它们之间关系的一个属性,但是为了使 APOC 以最佳方式工作,这些可能会更好地使用大小作为 :JumpPoint 节点本身的标签来建模,所以你可能有 :JumpPoint:Small, :JumpPoint:Medium , 和 :JumpPoint:Large (如果您愿意,可以在 rel 属性之外添加它)。

请记住,这种方法比 shortestPath() 更复杂,因为我们试图在一定数量的跳转内找到系统,然后找到 :Marketplaces 在这些星系统上可达,然后根据是否过滤他们出售我们想要的产品,我们会在找到碎片时将路径缝合在一起。

MATCH localSystemPath = (origin:Marketplace)-[*]-(s:Solarsystem)
WHERE origin.eid = $originId
WITH origin, localSystemPath, s
LIMIT 1
WITH origin, localSystemPath, s, 
 CASE WHEN coalesce($maxJumps, -1) = -1 
      THEN -1, 
      ELSE 3*$maxJumps 
 END as maxJumps,
 CASE $shipSize 
  WHEN 'small' THEN '' 
  WHEN 'medium' THEN '|-Small' 
  ELSE '|-Small|-Medium' 
 END as sizeBlacklist
CALL apoc.path.spanningTree(s, 
 {relationshipFilter:'HasJumpPoint|CanTravel>', maxLevel:maxJumps, 
 labelFilter:'>Solarsystem' + sizeBlacklist, filterStartNode:true}) YIELD path as jumpSystemPath
WITH origin, localSystemPath, jumpSystemPath, length(jumpSystemPath) / 3 as jumps, last(nodes(jumpSystemPath)) as destSystem
MATCH destSystemPath = (destSystem)-[*]-(marketplace:Market)
WHERE none(rel in relationships(destSystemPath) WHERE type(rel) = 'HasJumpPoint')
AND <insert predicate for filtering which :Markets you want>
WITH origin, apoc.path.combine(apoc.path.combine(localSystemPath, jumpSystemPath), destSystemPath) as fullPath, jumps, destSystem, marketplace
CALL srt.getRoutes(origin, marketplace, fullPath) YIELD node, jump_sizes, jump_gates, jump_distance, hops, distance
...

这假设 $shipSize 的参数输入是所有要通过的跳转门的最小尺寸,$originId 作为原点的 id :Marketplace(另外,您肯定需要在 :Marketplace(eid) 上使用索引或唯一约束,以便在此处快速查找) 和 $maxJumps,表示到达目标系统的最大跳转次数。

请记住,使用的扩展过程spanningTree() 只会找到通往另一个系统的最短路径。如果您需要所有可能的路径,包括通向同一系统的多条路径,请将过程改为expandConfig()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多