加载 CSV 并提交:有条件的 (FOREACH/CASE) 执行行为异常
LOAD CSV and Commits: Conditional (FOREACH/CASE) Execution Behaving Oddly
我正在使用 Neo4j 3.1 版,运行我认为导入非常简单,但 运行 遇到了非常严重的问题。我正在导入有关酒吧的数据(对于 non-UK 用户,public 房屋 - 您拥有 pint 和放松的地方!)。 (pl:PubListing)
已被 (u:BiteUser)
评论,创建 (bc:BiteComment)
。我有两个 CSV 文件,并且已经导入了 (pl:PubListing)
节点,所以我正在尝试导入链接到每个发布(在 pl.source_pub_id
上)和每个用户(在 u.username
上)的评论).重要的是,我想将它们添加为一个简单的关系,以及——为了更好的词——我称之为链。
通过这种方式,用户发表的最后两条评论(bc1
是最近的,bc2
是最近的一条)因此链接到用户:
第一条评论:
(u:BiteUser)-[:USER_PREVIOUS_COMMENT]->(bc1), (u)-[:USER_MADE_COMMENT]->(bc1)
第二个:
(u)-[:USER_MADE_COMMENT]->(bc2), (bc1)-[:USER_PREVIOUS_COMMENT]->(bc2)
到目前为止,一切正常(网络应用程序中的面包和黄油,评论可能类似于登录事件、密码更改、post 等)。然而,这并不是全部发生在一次整洁的交易中,而是在通过 CSV 加载时发生的。我的查询如下。
N.B。 - pre-processing 脚本对数据进行排序,以便所有评论按时间顺序排列:最早的评论排在第一位,因此没有逻辑将评论定位在链中的正确位置。
N.B。 II - 我在这里的几个地方使用 MERGE
over create 因为期望查询可能 运行 不止一次,因为新数据可用或跟进这个项目(这是一个谈话) 技术困难后尝试re-import数据。无论如何,它都不是生产脚本,查询优化也不是我的首要任务。
LOAD CSV WITH HEADERS FROM 'file:///output-comments-0031.csv' AS line
// find the pub it refers to
MATCH (pl:PubListing) WHERE pl.source_pub_id = toInteger(line.source_pub_id)
MERGE (u:BiteUser {username: line.username })
// ensure the comment node is created
MERGE (bc:BiteComment { source_comment_id: toInteger(line.source_comment_id) })
SET
// be flexible on scraped input
bc += line,
// indices should be integers, though
bc.source_pub_id = toInteger(line.source_pub_id),
bc.source_comment_id = toInteger(line.source_comment_id),
bc.created_timestamp = toInteger(line.created_timestamp)
// link the comment to the user and pub directly
MERGE (u)-[:USER_MADE_COMMENT]->(bc)
MERGE (bc)-[:COMMENT_ABOUT_PUT]->(pl)
// and in a chain
// - this section will be repeated to link the comment to the
// pub, in a chain. I've only included the user example
// to isolate the problem for SO
WITH u, pl, bc
OPTIONAL MATCH (u)-[r:USER_PREVIOUS_COMMENT]->(lc:BiteComment)
WHERE lc <> bc
WITH u, bc, pl, r, CASE WHEN r IS NULL THEN [] ELSE [1] END AS upc, lc
FOREACH (i IN upc |
DELETE r
CREATE (bc)-[:USER_PREVIOUS_COMMENT]->(lc)
)
// pre-processing means we know this is the most recent comment
// that the graph has seen yet
MERGE (u)-[:USER_PREVIOUS_COMMENT]->(bc)
问题是目前它为每条评论创建了这两种关系。但是,我更改查询的开头并在 LOAD CSV
行之后添加以下行,因此每个事务加载一个评论,它按预期工作。
WITH line SKIP 0 LIMIT 1
然后,
WITH line SKIP 1 LIMIT 1
然后...
WITH line SKIP 2 LIMIT 1
...你明白了。
我的问题是这样的。 为什么在 CSV 导入期间会发生这种情况,如果不 运行 将导入作为单独的事务处理,我如何才能停止它?
请务必记住,Cypher 查询不会对每行进行迭代处理。相反,它们同时处理所有行,并且迭代是针对所有行的每个操作。
因此,您首先匹配所有行,然后对所有行进行 MERGE(加载 CSV 之后的第二个操作),等等。
您的 CSV 导入似乎脱离了迭代处理行的(不正确的)假设,因此您对以前处理过的行有某种依赖性,这将不起作用。
我建议您修复 CSV 以消除对先前行处理的依赖。
要么您需要执行 COLLECT() 评论,然后获取最后两个条目(类似于 WITH collectedComments[-2..] as lastTwo
,然后为每个节点添加别名并创建相关关系),或者您需要添加时间戳或其他一些排序方式,然后执行 post-导入查询以获取两个最新评论并对其进行排序。
我正在使用 Neo4j 3.1 版,运行我认为导入非常简单,但 运行 遇到了非常严重的问题。我正在导入有关酒吧的数据(对于 non-UK 用户,public 房屋 - 您拥有 pint 和放松的地方!)。 (pl:PubListing)
已被 (u:BiteUser)
评论,创建 (bc:BiteComment)
。我有两个 CSV 文件,并且已经导入了 (pl:PubListing)
节点,所以我正在尝试导入链接到每个发布(在 pl.source_pub_id
上)和每个用户(在 u.username
上)的评论).重要的是,我想将它们添加为一个简单的关系,以及——为了更好的词——我称之为链。
通过这种方式,用户发表的最后两条评论(bc1
是最近的,bc2
是最近的一条)因此链接到用户:
第一条评论:
(u:BiteUser)-[:USER_PREVIOUS_COMMENT]->(bc1), (u)-[:USER_MADE_COMMENT]->(bc1)
第二个:
(u)-[:USER_MADE_COMMENT]->(bc2), (bc1)-[:USER_PREVIOUS_COMMENT]->(bc2)
到目前为止,一切正常(网络应用程序中的面包和黄油,评论可能类似于登录事件、密码更改、post 等)。然而,这并不是全部发生在一次整洁的交易中,而是在通过 CSV 加载时发生的。我的查询如下。
N.B。 - pre-processing 脚本对数据进行排序,以便所有评论按时间顺序排列:最早的评论排在第一位,因此没有逻辑将评论定位在链中的正确位置。
N.B。 II - 我在这里的几个地方使用 MERGE
over create 因为期望查询可能 运行 不止一次,因为新数据可用或跟进这个项目(这是一个谈话) 技术困难后尝试re-import数据。无论如何,它都不是生产脚本,查询优化也不是我的首要任务。
LOAD CSV WITH HEADERS FROM 'file:///output-comments-0031.csv' AS line
// find the pub it refers to
MATCH (pl:PubListing) WHERE pl.source_pub_id = toInteger(line.source_pub_id)
MERGE (u:BiteUser {username: line.username })
// ensure the comment node is created
MERGE (bc:BiteComment { source_comment_id: toInteger(line.source_comment_id) })
SET
// be flexible on scraped input
bc += line,
// indices should be integers, though
bc.source_pub_id = toInteger(line.source_pub_id),
bc.source_comment_id = toInteger(line.source_comment_id),
bc.created_timestamp = toInteger(line.created_timestamp)
// link the comment to the user and pub directly
MERGE (u)-[:USER_MADE_COMMENT]->(bc)
MERGE (bc)-[:COMMENT_ABOUT_PUT]->(pl)
// and in a chain
// - this section will be repeated to link the comment to the
// pub, in a chain. I've only included the user example
// to isolate the problem for SO
WITH u, pl, bc
OPTIONAL MATCH (u)-[r:USER_PREVIOUS_COMMENT]->(lc:BiteComment)
WHERE lc <> bc
WITH u, bc, pl, r, CASE WHEN r IS NULL THEN [] ELSE [1] END AS upc, lc
FOREACH (i IN upc |
DELETE r
CREATE (bc)-[:USER_PREVIOUS_COMMENT]->(lc)
)
// pre-processing means we know this is the most recent comment
// that the graph has seen yet
MERGE (u)-[:USER_PREVIOUS_COMMENT]->(bc)
问题是目前它为每条评论创建了这两种关系。但是,我更改查询的开头并在 LOAD CSV
行之后添加以下行,因此每个事务加载一个评论,它按预期工作。
WITH line SKIP 0 LIMIT 1
然后,
WITH line SKIP 1 LIMIT 1
然后...
WITH line SKIP 2 LIMIT 1
...你明白了。
我的问题是这样的。 为什么在 CSV 导入期间会发生这种情况,如果不 运行 将导入作为单独的事务处理,我如何才能停止它?
请务必记住,Cypher 查询不会对每行进行迭代处理。相反,它们同时处理所有行,并且迭代是针对所有行的每个操作。
因此,您首先匹配所有行,然后对所有行进行 MERGE(加载 CSV 之后的第二个操作),等等。
您的 CSV 导入似乎脱离了迭代处理行的(不正确的)假设,因此您对以前处理过的行有某种依赖性,这将不起作用。
我建议您修复 CSV 以消除对先前行处理的依赖。
要么您需要执行 COLLECT() 评论,然后获取最后两个条目(类似于 WITH collectedComments[-2..] as lastTwo
,然后为每个节点添加别名并创建相关关系),或者您需要添加时间戳或其他一些排序方式,然后执行 post-导入查询以获取两个最新评论并对其进行排序。