土法炼钢兴趣小组的算法知识备份

【图数据库内核】标签、类型与属性索引:起点过滤器,不是遍历引擎

文章导航

分类入口
databasegraph
标签入口
#graph-database#neo4j#index#range-index#lookup-index#constraint#uniqueness#cypher#label

目录

01 篇把「索引」钉成坐标系之一:决定从哪里开始走,很少替代深度 expand。 本篇把该句落到 Neo4j 5 的具体对象——token lookup、RANGE/TEXT/POINT、关系属性索引,以及唯一/存在/类型/KEY 约束——并接到第 06 篇的写放大。全文与向量索引只留接口,展开在第 08 篇。

本文是「图数据库内核」系列第 7 篇(共 16 篇)。→ 系列目录

篇目 核心内容
第 6 篇 · 写入路径 建边、dense、ID 复用
第 7 篇 · 索引与约束 LOOKUP / RANGE / TEXT / POINT;约束
第 8 篇 · 全文与向量边界 Lucene / vector;不重写 ANN 全书
第 9–10 篇 · Expand / 计划 索引起点之后发生什么

版本锚定:Cypher Manual 5(与站内 Neo4j 5.x / current 产品线对齐)Indexes → Search-performance indexesConstraints。运维侧:Operations Manual Memory configuration(native 索引进 page cache;Lucene / 向量不在其中——第 05、08 篇)。不粘贴未执行的 PROFILE 行数;算子名以手册示例为准。


一、先立边界:索引解决什么、不解决什么

解决 不解决
按标签/类型找到候选实体集合 \(k\) 跳拓扑扩张变成「一次索引查找」
按属性谓词缩小起点(或边集合) 超节点某一类型上百万边的输出基数
唯一性等完整性(约束) 基数估计在幂律图上天然可信(第 10 篇)

一次典型模式匹配的代价仍接近:

[ {}() + {}^{k} + _{} ]

索引只硬砍第一项,并间接影响计划是否敢选某条路径。若 \(\mathrm{Cost}_{\mathrm{entry}}\) 产出的 \(|S|\) 仍然巨大,后面的 expand 照样爆炸——这是「计划每个算子都合理、乘积不合理」的常见入口。


二、Token lookup:数据库自带的标签/类型索引

Cypher Manual:创建库时默认存在两个 token lookup index——节点标签 lookup 与关系类型 lookup。它们只解决标签 / 关系类型谓词,不解决任何属性谓词。

有 lookup 无 lookup(若被删)
计划可用 NodeByLabelScan 等,只碰该标签节点 手册示例:退化为 AllNodesScan,先读全库节点再过滤

手册原话级警告:删除 token lookup 会导致严重性能退化;它们也帮助其它索引的填充。非平凡库上「只靠 lookup」不够——因为业务过滤几乎总在属性上——但没有 lookup 则连「按标签起步」都贵

与第 03 篇对照:标签在节点记录里另有字段/动态记录;lookup 是为扫描准备的二级结构,不是「读节点时顺便得到的免费列表」。关系类型同理:store 里每条 Rel 带 type token,lookup 加速「找出所有 [:R]」类入口,不替代邻接 expand。


三、搜索性能索引四型

手册把加速精确检索的索引称为 search-performance indexes,四类:

类型 创建要点 主要解决
RANGE CREATE INDEX 默认即 range;可建在节点或关系上;支持复合属性 大多数谓词:等值、范围、STARTS WITH、排序借用等
TEXT CREATE TEXT INDEX;默认 provider text-2.0(trigram,5.1+) STRING 上的 CONTAINS / ENDS WITH;与 range 并存时这两类算子优先 text
POINT CREATE POINT INDEX 距离、bounding box 等空间谓词
LOOKUP 见上;一般勿删;可用 CREATE LOOKUP INDEX 重建 仅标签/类型

3.1 RANGE:默认主力

3.2 TEXT 与 RANGE 分工

同一 STRING 属性上可同时存在 range 与 text。手册规则:

text-2.0 用 trigram 切分(手册举例 "developer"dev/eve/vel/…)——解释为何 CONTAINS 能走索引而不必全表扫字符串。

3.3 POINT

专用于 POINT 属性的距离与 bbox 类谓词。规划器需能推断属性为 point 类型才会用它;仅有松散谓词时可能退回 label scan(手册有「text/point 需能排除非兼容类型」的讨论)。存在 property type constraint(EE,5.9+)时可帮规划器确立类型。

3.4 自动选用与提示

多索引可用时,规划器选自认最便宜者;也可用 USING 提示强制(手册 Index hints)。强制错索引会把「起点过滤器」变成「起点误伤」——第 10 篇再谈。


四、约束:完整性,兼带索引副作用

Cypher Manual 5 约束一览:

约束 作用 Edition
Property uniqueness 指定标签(或关系类型)上,属性(组合)唯一 节点与关系(关系唯一 5.7+
Property existence 属性必须存在(IS NOT NULL Enterprise
Property type 属性必须为给定类型 Enterprise5.9+
KEY(NODE KEY / RELATIONSHIP KEY) 存在 ∧ 唯一(组合) Enterprise;关系 KEY 5.7+

4.1 唯一性细节

4.2 索引后备(写路径含义)

创建唯一性 / KEY 类约束会带上后备索引(同 schema 上通常不能再单独建同型重复索引——历史手册与创建冲突规则一致;以当前版本文档的冲突提示为准)。后果直接对接第 06 篇:

存在性约束像唯一约束那样以同样方式「顺带当查找索引」——手册写明 existence 目前不按同一方式 leverage 索引使用;其价值在写入期拒绝坏数据。

4.3 Community / Enterprise 边界

存在、类型、KEY 在手册标为 EE。含这些约束的库不能用 Community 打开(4.x 手册已有同类警告;迁移时按 edition 规划)。本系列正文区分能力边界,不做版本营销。


五、和存储 / 缓存的接口

结构 落点(运维口径)
Token lookup、RANGE 等 native 索引 计入 data and native indexes;规划进 page cache(第 05 篇)
Full-text(Lucene) 不进 Neo4j page cache;与剩余 OS/堆外内存谈判
Vector index 手册:加载在 OS 内存侧,不在 page cache(第 08 篇)

因此「给图查询加索引」会:

  1. 增加 store 侧体积(手册 over-indexing:索引是主数据的二级拷贝,空间上近似再占一份被索引数据);
  2. 推高 server.memory.pagecache.size 的合理下界;
  3. 拖慢写路径(每写更新索引)。

SHOW INDEXES5.8+ 相关列)可用 lastRead / readCount / trackedSince 抓闲置索引,再 DROP INDEX——手册推荐的反过索引手段。


六、经典事故:索引起点 × 深度遍历

6.1 高召回入口

索引求出 |S| = 50万起点
→ 每点 expand 平均 f = 20
→ 一层就百万级中间行

索引「很成功」(避免了 AllNodesScan),查询仍可能跑爆。杠杆在:收紧谓词、限制变长路径、换建模,而不是再加一个更宽的索引。

6.2 低基数属性上的索引

手册 heuristics 偏向高基数属性。低基数(布尔、状态枚举)上的 range 可能选出巨大起点,计划看起来用了 NodeIndexSeek,实质接近标签扫描。此时索引的存储与写成本几乎白付。

6.3 复合索引属性顺序

创建 (a,b,c) 与查询只提供 c 时,复合索引可能根本用不上(须覆盖全部属性的规则)。错误顺序会导致「建了却不见 seek」。用 EXPLAIN/PROFILE 核对算子(有环境再贴;第 10 篇)。

6.4 与邻接布局的分工

组件 职责
LOOKUP / 属性索引 选出 \(S\)
Record 链 / block 主块与 dense 树 \(S\) 走出邻居
计划器 猜测 \(|S|\) 与扇出——幂律下易错

索引再强,也要把第 03–05 篇的 hop 成本算进总账。


七、Heuristics(手册口径 + 本系列补一句)

手册 Heuristics: deciding what to index 要点:

  1. 频繁用于过滤/匹配的属性;
  2. 已确认的慢查询瓶颈属性;
  3. 高基数属性;
  4. 复杂多跳且多层过滤时,给过滤属性加索引;
  5. 用实验对比有无索引——不要凭感觉堆。

手册 Over-indexing:空间接近翻倍被索引数据;写变慢。本系列补一条图特有的:

  1. 先问入口选择性,再问跳数——选择性差的索引对多跳查询是负资产。

八、学术与工程谱系(短)

  1. 二级索引加速选择:与关系库 B-Tree/LSM 二级索引同构;图引擎的增量在于入口之后是拓扑算子而非更多 JOIN 节点(第 02、09 篇)。
  2. Token 与属性分离:标签/类型走 lookup、属性走 range/text/point——承认「图式过滤」与「键值过滤」不是同一访问路径。
  3. 争论:应用层「先建齐所有属性索引」vs「按 readCount 裁剪」。写多读少的摄取管道与读多写少的查询服务答案相反;用第 06 篇写放大与本节 over-indexing 对齐,而不是品牌默认。
  4. 开放问题:幂律下入口基数估计(第 10 篇);约束与 graph type(Cypher 25 方向)如何改变「开放属性图」的工程默认——本篇不展开 25 全书。

九、来源与实验台账(本篇)

结论 等级 来源
四类 search-performance 索引职责;默认 LOOKUP;删 LOOKUP 的后果 A Cypher Manual 5 Search-performance indexes / using indexes
RANGE/TEXT 分工;trigram text-2.0;复合索引全属性与顺序 A 同上 Create indexes / using indexes
约束类型与 EE 边界;唯一性对缺属性实体的豁免 A Cypher Manual 5 Constraints / Create constraints
过索引空间与写代价;lastRead/readCount(5.8+) A using indexes → Over-indexing
Native vs Lucene/向量内存分工 A Operations Manual Memory configuration(经第 05 篇)
本机 PROFILE 对比有无索引 未跑 不贴伪造 DB hits

十、小结

  1. LOOKUP 保标签/类型入口;RANGE/TEXT/POINT 保属性入口;都不是遍历引擎。
  2. 唯一/KEY 约束带索引后备,把完整性与写放大绑在同一条绳上;存在/类型约束偏 EE 的形状治理。
  3. 过索引有价:空间、写入、错误的低基数入口。
  4. 下一篇:全文(Lucene)与向量索引如何接在属性旁边,以及为何不应塞进 page cache 叙事。

系列目录 · 上一篇:写入路径 · 下一篇:全文与向量边界

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .