首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >逗号分隔匹配与多匹配的区别

逗号分隔匹配与多匹配的区别
EN

Stack Overflow用户
提问于 2019-11-29 14:59:54
回答 2查看 127关注 0票数 1

上下文:我们正在Neo4J数据库中导入csv文件。

我们遇到了批处理的性能问题

代码语言:javascript
复制
CALL apoc.periodic.iterate('
CALL apoc.load.csv(\'file:///myfile.csv\') yield map as row return row
','
WITH
    row.Source AS sourceName,
    row.Quote AS quoteName,
    row.Type AS type,
    row.CurveIndex AS curveIndexName,
    row.Entity AS entityName,
    row.FreeParam AS freeParamName,
    row.Location AS locationName,
    row.Maturity AS maturityName,
    row.DepMaturity AS depMaturityName,
    row.Seniority AS seniorityName,
    row.Tray AS trayName,
    row.VolatilityModel AS volatilityModelName
MATCH (marketData:MarketData {source:sourceName, quoteName:quoteName, type:type})
OPTIONAL MATCH  (curveIndex:CurveIndex {name:curveIndexName})
OPTIONAL MATCH  (entity:Entity {name:entityName})
OPTIONAL MATCH  (maturity:Maturity {name:maturityName})
OPTIONAL MATCH  (depMaturity:Maturity {name:depMaturityName})
OPTIONAL MATCH  (seniority:Seniority {name:seniorityName})
OPTIONAL MATCH  (tray:Tray {name:trayName})
OPTIONAL MATCH  (volatilityModel:VolatilityModel {name:volatilityModelName})

FOREACH (f1 IN CASE WHEN curveIndex IS NULL THEN [] ELSE [curveIndex] END |
    MERGE (marketData)-[:CURVE_INDEX]->(curveIndex))
FOREACH (f1 IN CASE WHEN entity IS NULL THEN [] ELSE [entity] END |
    MERGE (marketData)-[:ENTITY]->(entity))
FOREACH (f1 IN CASE WHEN maturity IS NULL THEN [] ELSE [maturity] END |
    MERGE (marketData)-[:MATURITY]->(maturity))
FOREACH (f1 IN CASE WHEN depMaturity IS NULL THEN [] ELSE [depMaturity] END |
    MERGE (marketData)-[:DEP_MATURITY]->(depMaturity))
FOREACH (f1 IN CASE WHEN seniority IS NULL THEN [] ELSE [seniority] END |
    MERGE (marketData)-[:SENIORITY]->(seniority))
FOREACH (f1 IN CASE WHEN tray IS NULL THEN [] ELSE [tray] END |
    MERGE (marketData)-[:TRAY]->(tray))
FOREACH (f1 IN CASE WHEN volatilityModel IS NULL THEN [] ELSE [volatilityModel] END |
    MERGE (marketData)-[:VOLATILITY_MODEL]->(volatilityModel))
', {batchSize:1000, iterateList:true, parallel:true, concurrency:4});

这个命令使用大量内存(很多是stop-the-world gc,有些>10s),并且在一个900k行的文件上执行需要几个小时。

经过几次尝试,我们发现这个命令要高效得多:

代码语言:javascript
复制
CALL apoc.periodic.iterate('
CALL apoc.load.csv(\'file:///myfile.csv\') yield map as row return row
','
WITH
    row.Source AS sourceName,
    row.Quote AS quoteName,
    row.Type AS type,
    row.CurveIndex AS curveIndexName,
    row.Entity AS entityName,
    row.FreeParam AS freeParamName,
    row.Location AS locationName,
    row.Maturity AS maturityName,
    row.DepMaturity AS depMaturityName,
    row.Seniority AS seniorityName,
    row.Tray AS trayName,
    row.VolatilityModel AS volatilityModelName
MATCH (marketData:MarketData {source:sourceName, quoteName:quoteName, type:type})
OPTIONAL MATCH  (curveIndex:CurveIndex {name:curveIndexName}),
                (entity:Entity {name:entityName}),
                (maturity:Maturity {name:maturityName}),
                (depMaturity:Maturity {name:depMaturityName}),
                (seniority:Seniority {name:seniorityName}),
                (tray:Tray {name:trayName}),
                (volatilityModel:VolatilityModel {name:volatilityModelName})

FOREACH (f1 IN CASE WHEN curveIndex IS NULL THEN [] ELSE [curveIndex] END |
    MERGE (marketData)-[:CURVE_INDEX]->(curveIndex))
FOREACH (f1 IN CASE WHEN entity IS NULL THEN [] ELSE [entity] END |
    MERGE (marketData)-[:ENTITY]->(entity))
FOREACH (f1 IN CASE WHEN maturity IS NULL THEN [] ELSE [maturity] END |
    MERGE (marketData)-[:MATURITY]->(maturity))
FOREACH (f1 IN CASE WHEN depMaturity IS NULL THEN [] ELSE [depMaturity] END |
    MERGE (marketData)-[:DEP_MATURITY]->(depMaturity))
FOREACH (f1 IN CASE WHEN seniority IS NULL THEN [] ELSE [seniority] END |
    MERGE (marketData)-[:SENIORITY]->(seniority))
FOREACH (f1 IN CASE WHEN tray IS NULL THEN [] ELSE [tray] END |
    MERGE (marketData)-[:TRAY]->(tray))
FOREACH (f1 IN CASE WHEN volatilityModel IS NULL THEN [] ELSE [volatilityModel] END |
    MERGE (marketData)-[:VOLATILITY_MODEL]->(volatilityModel))
', {batchSize:1000, iterateList:true, parallel:true, concurrency:4});

它使用较少的内存,执行时间大约为50秒。

我不确定是否真的理解这两个命令之间的区别。有谁能解释一下吗?

EN

回答 2

Stack Overflow用户

发布于 2019-12-02 19:45:02

这两个查询做的不是同一件事,尽管对于您的特定数据,您可能会得到相同的结果(只要您在OPTIONAL MATCHes中匹配的所有内容总是返回一些内容)。

OPTIONAL MATCH基本上是在说‘如果我要OPTIONAL MATCH的模式不存在,就用nulls代替从OPTIONAL MATCH中的节点和关系派生出来的任何东西。

MATCHOPTIONAL MATCH后面用逗号分隔的块只是一个要找到的模式--我们不是隐式地为我们找到的每个逗号做另一个MATCH,而是找到符合整个模式的东西(并返回它),或者不符合这个模式(并对提到的任何东西返回空值)。

在您的案例中:

  • 第一个查询将查找与CSV行匹配的MarketData节点,然后可选地依次匹配其他节点类型,如果找到,则在该节点和MarketData节点之间创建关系。
    • 因为您一次对每个节点标签执行OPTIONAL MATCH操作,所以如果缺少任何标签,您只需获得该节点变量的null,并且由于FOREACH标签的原因,您将跳过创建关系的过程

  • 第二个查询将查找与第一个查询相同的CSV行匹配的MarketData节点,但随后它将满足返回这些值的整个模式(查找与该行匹配的CurveIndex、匹配的Maturity和匹配的Tray ),或者无法找到所有这些值并返回所有

的空值

如果您熟悉SQL,就好像您在使用逗号时将CSV行与内部联接数据的子选择相关联,而不是使用查询1按顺序对每个‘OUTER JOIN’进行查询。在您的第二个示例中,如果任何内容都不匹配,您的INNER JOIN将不返回任何行,因此您将只返回CSV行,而不会返回其他行。

我的感觉是,在第二个查询中创建的节点和关系可能会更少,因为如果从entityvolatilityModel的任何内容都不匹配,OPTIONAL MATCH将不会返回任何内容。

让我们用一些虚拟数据做一个简化的例子,只包含MarketData,CurveIndex和实体节点:

代码语言:javascript
复制
MERGE (m: MarketData { quoteName: 'MSFT' })
MERGE (curveIndex: CurveIndex { name: 'SomeCurveIndex' })
MERGE (entity: Entity { name: 'MSFT Entity' })

我们将在内存中伪造一个CSV,并暂时避免所有的批处理比特和bob。首先,当CSV中的所有内容都匹配时,让我们返回匹配的MarketData、CurveIndex和Entity节点,使用您的第一个查询来证明它是有效的:

代码语言:javascript
复制
WITH { Quote: 'MSFT', CurveIndex: 'SomeCurveIndex', Entity: 'MSFT Entity' } as row
WITH
    row.Quote AS quoteName,
    row.CurveIndex AS curveIndexName,
    row.Entity AS entityName
MATCH (marketData: MarketData { quoteName: quoteName })
OPTIONAL MATCH (curveIndex: CurveIndex { name: curveIndexName })
OPTIONAL MATCH (entity: Entity { name: entityName })
RETURN marketData, curveIndex, entity

因为所有数据都存在于CSV中,而参考数据已经存在于数据库中,所以我们将返回三个节点。现在,让我们尝试更改实体名称,看看会发生什么:

代码语言:javascript
复制
WITH { Quote: 'MSFT', CurveIndex: 'SomeCurveIndex', Entity: 'Some Other Entity' } as row
WITH
    row.Quote AS quoteName,
    row.CurveIndex AS curveIndexName,
    row.Entity AS entityName
MATCH (marketData: MarketData { quoteName: quoteName })
OPTIONAL MATCH (curveIndex: CurveIndex { name: curveIndexName })
OPTIONAL MATCH (entity: Entity { name: entityName })
RETURN marketData, curveIndex, entity

完美-我们得到我们可以匹配的比特,以及我们不能匹配的比特的空值。

现在,让我们尝试连接这两个OPTIONAL MATCH子句,看看效果:

代码语言:javascript
复制
WITH { Quote: 'MSFT', CurveIndex: 'SomeCurveIndex', Entity: 'Some Other Entity' } as row
WITH
    row.Quote AS quoteName,
    row.CurveIndex AS curveIndexName,
    row.Entity AS entityName
MATCH (marketData: MarketData { quoteName: quoteName })
OPTIONAL MATCH (curveIndex: CurveIndex { name: curveIndexName }), (entity: Entity { name: entityName })
RETURN marketData, curveIndex, entity

即使我们找到了一个匹配的CurveIndex,我们也没有返回它,因为我们无法同时找到一个匹配的Entity

票数 0
EN

Stack Overflow用户

发布于 2019-12-03 06:04:48

@Pablissimo对为什么这两个查询的行为不同是正确的。

  1. 速度慢的一个主要原因是所有的MATCH子句都在创建cartesian product。避免笛卡尔乘积的一种方法是最小化MATCH子句的数量,但正如您所看到的,将它们组合成单个子句在您的用例中不起作用。但是我有一个相当聪明的方法来避免使用entirely.
  2. Also,子句,您可能还没有创建适当的indexes.

为简单起见,我将仅讨论您的第一个查询中的这段代码(您可以将其扩展到其他可选变量):

代码语言:javascript
复制
OPTIONAL MATCH (curveIndex:CurveIndex {name:curveIndexName})
FOREACH (f1 IN CASE WHEN curveIndex IS NULL THEN [] ELSE [curveIndex] END |
  MERGE (marketData)-[:CURVE_INDEX]->(curveIndex))

  1. 上面的代码片段可以替换为以下代码,它使用pattern comprehensionvariable-length relationship避免使用多个OPTIONAL MATCH子句(以及它们生成的笛卡尔乘积),并且还创建所有CurveIndex节点的单个列表,以便可以通过单个FOREACH操作处理这些节点。顺便说一句,模式理解需要一个具有关系的模式,这就是为什么我们使用0长度关系而不仅仅是一个空节点的原因。

FOREACH (ci IN [(c:CurveIndex {name:curveIndexName})-*0..0-()|c] | MERGE (marketData)-:CURVE_INDEX->(ci))

  • You还应在以下位置创建索引:

:市场数据(sourceName,quoteName,类型)

:CurveIndex(name)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59100132

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档