String.equals 或 STARTS WITH 在 neo4j 中的效率
Efficiency of String.equals or STARTS WITH in neo4j
假设我的应用场景如下:
JOJO家族的每个成员都以其祖先的名字命名。第一代叫Jonathan,所以Jonathan的直系后代叫JonathanJoseph和JonathanGiorno。依此类推,我们得到 JonathanJosephJotaro、JonathanJosephJosuke、JonathanJosephJotaroJolyne。
(Jonathan)-[:AncestorOf]->(JonathanJoseph)
(Jonathan)-[:AncestorOf]->(JonathanGiorno)
(JonathanJoseph)-[:AncestorOf]->(JonathanJosephJotaro)
(JonathanJoseph)-[:AncestorOf]->(JonathanJosephJosuke)
(JonathanJosephJotaro)-[:AncestorOf]->(JonathanJosephJotaroJolyne)
JOJO家族代代传承黄金精神,所以每个人都有一种特殊的能力,叫做'stand power'。但是,我们只关心叶节点上的JOJO的'stand power'(没有后代)。
(JonathanGiorno)-[:Owns]->(Gold Experience)
(JonathanJosephJosuke)-[:Owns]->(Crazy Diamond)
(JonathanJosephJotaroJolyne)-[:Owns]->(Stone Free)
问题是:
- 我想编写查询以获取某个家庭拥有的 'stand power' 的所有名称。我想到两个解决方案
- 存储所有祖先节点,使用String.equals获取匹配的祖先节点,然后跳转到叶子节点
MATCH (:JOJO{name:"Jonathan"})-[:AncestorOf*]-(:JOJO)-[:Owns]->(sp:StandPower)
return sp
- 不存储任何祖先节点,使用START WITH获取匹配的叶节点
MATCH (j:JOJO)-[:Owns]->(sp:StandPower)
WHERE j.name STARTS WITH "Jonathan"
return sp
哪种解决方案更好?
- 在Java中,String.equals和String.startsWith的时间复杂度O(n)几乎相同。那么在neo4j中还是这样吗?
根据这个 link 索引偏好:
https://neo4j.com/docs/cypher-manual/current/query-tuning/indexes/#_index_preference
引用:
- 对于 CONTAINS 和 ENDS,TEXT 索引优于 BTREE 索引
与.
- 在所有其他情况下,BTREE 索引优于 TEXT 索引。
取消引用:
因此,在你的例子中,我会选择
MATCH (:JOJO{name:"Jonathan"})-[:AncestorOf*]-(:JOJO)-[:Owns]->(sp:StandPower)
return sp
一般来说,进行字符串匹配将优于执行 STARTS WITH,因为前者已经在使用索引。如果您执行查询计划以查看有关如何使用索引的详细信息,那就更好了。
假设我的应用场景如下:
JOJO家族的每个成员都以其祖先的名字命名。第一代叫Jonathan,所以Jonathan的直系后代叫JonathanJoseph和JonathanGiorno。依此类推,我们得到 JonathanJosephJotaro、JonathanJosephJosuke、JonathanJosephJotaroJolyne。
(Jonathan)-[:AncestorOf]->(JonathanJoseph)
(Jonathan)-[:AncestorOf]->(JonathanGiorno)
(JonathanJoseph)-[:AncestorOf]->(JonathanJosephJotaro)
(JonathanJoseph)-[:AncestorOf]->(JonathanJosephJosuke)
(JonathanJosephJotaro)-[:AncestorOf]->(JonathanJosephJotaroJolyne)
JOJO家族代代传承黄金精神,所以每个人都有一种特殊的能力,叫做'stand power'。但是,我们只关心叶节点上的JOJO的'stand power'(没有后代)。
(JonathanGiorno)-[:Owns]->(Gold Experience)
(JonathanJosephJosuke)-[:Owns]->(Crazy Diamond)
(JonathanJosephJotaroJolyne)-[:Owns]->(Stone Free)
问题是:
- 我想编写查询以获取某个家庭拥有的 'stand power' 的所有名称。我想到两个解决方案
- 存储所有祖先节点,使用String.equals获取匹配的祖先节点,然后跳转到叶子节点
MATCH (:JOJO{name:"Jonathan"})-[:AncestorOf*]-(:JOJO)-[:Owns]->(sp:StandPower) return sp
- 不存储任何祖先节点,使用START WITH获取匹配的叶节点
MATCH (j:JOJO)-[:Owns]->(sp:StandPower) WHERE j.name STARTS WITH "Jonathan" return sp
- 存储所有祖先节点,使用String.equals获取匹配的祖先节点,然后跳转到叶子节点
- 在Java中,String.equals和String.startsWith的时间复杂度O(n)几乎相同。那么在neo4j中还是这样吗?
根据这个 link 索引偏好:
https://neo4j.com/docs/cypher-manual/current/query-tuning/indexes/#_index_preference
引用:
- 对于 CONTAINS 和 ENDS,TEXT 索引优于 BTREE 索引 与.
- 在所有其他情况下,BTREE 索引优于 TEXT 索引。
取消引用:
因此,在你的例子中,我会选择
MATCH (:JOJO{name:"Jonathan"})-[:AncestorOf*]-(:JOJO)-[:Owns]->(sp:StandPower)
return sp
一般来说,进行字符串匹配将优于执行 STARTS WITH,因为前者已经在使用索引。如果您执行查询计划以查看有关如何使用索引的详细信息,那就更好了。