如何在Cypher中高效排序列表与元组列表?
如何在Cypher中排序列表的列表/元组列表?
首先咱们拆解下你的问题和现有查询的问题:你当前的查询是先把所有[docId, senId]收集到docs列表,再按docs[0]排序——但这里的排序是列表的自然数值比较,也就是直接对比docId的数值大小,这就是为什么结果里大数值的docId(比如848613)会排在小数值(90029)前面,和你想要的目标顺序不符。
而你要的目标排序,看起来是基于docId的字符串降序(因为字符串"90029"首字符'9'大于所有以"8"开头的docId),再对相同docId的条目按senId升序排列。
高效解决方案:先排序单个条目,再收集
在Cypher中,排序列表的列表(或元组列表)最高效的方式是先对单个条目按自定义规则排序,再收集成列表,比先收集再展开排序的方式少了UNWIND步骤,性能更优。
针对你的场景,优化后的查询如下:
MATCH (n) WHERE EXISTS(n.docId) WITH DISTINCT n.docId AS docId, n.senId AS senId // 按docId的字符串形式降序,再按senId升序排序单个条目 ORDER BY toString(docId) DESC, senId ASC // 收集排序后的条目为目标列表 WITH COLLECT([docId, senId]) AS docs RETURN docs
为什么这个查询能得到你要的结果?
- 提前去重更高效:在
WITH阶段就对docId和senId的组合去重,避免后续收集重复条目,比先收集再去重的性能更好。 - 自定义排序精准匹配需求:
toString(docId) DESC:把docId转为字符串后降序排序,让字符串"90029"因为首字符优势排在最前面,后续以"8"开头的docId也会按字符串的字典序从大到小排列,完全符合你目标结果的顺序。senId ASC:对相同docId的条目,按senId升序排列,所以[848613, 1]会排在[848613, 2]前面。
- 直接收集无额外开销:排序完成后直接收集成列表,不需要额外的展开-重收集步骤,执行效率更高。
针对你的两个问题的通用说明:
- 排序列表的列表:核心是拆解列表中的元素,分别指定排序规则(比如按列表第1个元素降序、第2个元素升序),优先排序单个列表元素再收集;如果已经有现成的列表的列表,也可以通过
UNWIND展开后排序,再重新COLLECT,但效率不如前者。 - 排序元组列表:Cypher中的元组(比如
(docId, senId))排序逻辑和列表类似,同样可以拆解元组的元素指定排序规则,先排序单个元组再收集成元组列表。
比如排序元组列表的查询可以写成:
MATCH (n) WHERE EXISTS(n.docId) WITH DISTINCT (n.docId, n.senId) AS docSenTuple ORDER BY toString(docSenTuple.1) DESC, docSenTuple.2 ASC WITH COLLECT(docSenTuple) AS docs RETURN docs
内容的提问来源于stack exchange,提问作者sus
相关产品推荐
相关产品推荐

