目标是把你现在的全局唯一特征值链 + 指针引用共享这套体系,写成可执行的约束与接口约定,避免后续“值被改坏 / 索引失效 / 融合逻辑飘了”的事故。
0. 总定位
- 特征值节点:全局唯一、可共享的“值对象”(被多个特征引用)。
- 特征节点:语义上的“某存在的某种特征”,它引用一个或多个特征值节点,并维护“当前值/历史值/区间摘要”等。特征节点里已经有
当前值 / 值列表 / 区间摘要 / 区间语义这些结构,适合承接融合与摘要职责。 - 原则:特征值负责去重与比较,融合主要发生在特征节点层(否则会破坏“全局唯一共享”语义)。
1. 数据结构规范
1.1 载体与主信息(必须保持一致)
你现在的“最终载体”是:
特征值载体 = variant<monostate, int64, uint64, VecI64, VecIU64, string>特征值主信息类字段:类型 / 比较模式 / 值 / 命中次数 / 可信度
规范要求:类型 与 variant 实际分支必须匹配。你已经有 debug 工具
校验载体与类型一致(),任何“入库/反序列化/融合写入”入口都必须 assert 它。
1.2 类型语义约定(关键点)
VecIU64除了“向量”,还被你明确用于存体素占据金字塔块数据。Bits64语义是“用 U64 存 + 海明距离”,也就是说Bits64 不需要单独成为载体分支,而是约定为类型=U64,比较模式=海明距离的一种用法。- 工厂函数是“规范入口”:
创建字符串/创建VecI64/创建VecIU64/创建Bits64等应该被视为唯一推荐的构造方式(它们把类型+比较模式一次性定死)。
2. 不变量(决定你索引能不能一直快)
2.1 值三元组不可变
对任何已入库的特征值节点:
- 不可变字段:
类型 / 比较模式 / 值 - 可变字段:
命中次数 / 可信度
原因:一旦你把节点放进“按值索引”的 map/hash 里,如果再改值,索引就会变成幽灵船。
规范强制:如果你要“把值从 10 改成 11”,必须走删旧引用 + 取新节点(新建或复用),而不是修改旧节点的
值。
2.2 元数据修改要可并发且不破坏索引
你已经在链表模板里加了修改节点信息_已加锁(...)这类入口。规范建议:
- 只用它改
命中次数 / 可信度 - 改完不需要触碰索引(因为 key 不变)
3. 索引体系规范(“每类型一棵树”怎么落地)
你要的“各自一棵树 + 快速索引查询”,推荐拆成两层:
3.1 精确去重索引(必须有)
- Key:
(类型, 比较模式, 值) - 结构:
unordered_map<KeyHash, Node*>或unordered_map<Key, Node*, Hash, Eq> - 目标:O(1) 找“完全相同的值对象”,实现全局唯一。
其中Eq使用:
类型相等比较模式相等variant分支相等且内容相等
KeyHash:对 variant 内容做稳定 hash(Vec 逐元素 hash combine,string 用 std::hash)。
3.2 有序树索引(用于范围/最近邻候选)
- 结构:
std::map<Key, Node*, Compare>或std::set<Node*, CompareByKey> - Compare 使用你现成的“严格排序比较”思想(对 variant 做强序),保证容器稳定。
用途:
- 标量:范围检索(区间内候选)
- 向量:取一批候选后再用距离函数精排
- 海明:按块/按前缀分桶后精排(树用于分桶 key)
注意:“相似度最近邻”不建议直接靠 std::map 全局做,更靠谱的是:先用树/桶缩小候选集,再按比较模式算距离精排(L1/L2/海明/颜色距离等)。你的比较模式枚举里已经明确了这些距离语义。
4. API 规范(推荐的最小闭环)
下面是建议你在“特征值仓库/特征值类”暴露的核心接口(统一入口,不再分标量/矢量/文本三套 CRUD):
// 约定:key 的 (类型/比较模式/值) 已设置好,且通过 校验载体与类型一致特征值节点类*查找_精确(const特征值主信息类&key)const;特征值节点类*获取或创建_精确(const特征值主信息类&key);// 命中:找到则返回已有节点,并递增命中次数;没找到则入库并建索引bool增加命中(const特征值节点类*n,std::uint32_tdelta=1);bool更新可信度(const特征值节点类*n,floatnewC);// 可选:相似查询(返回候选集,最终由上层做融合决策)std::vector<特征值节点类*>查找_相似(const特征值主信息类&query,std::size_t topK,doublemaxDistOrMinSim)const;4.1 “增删改还要不要区分标量/矢量/文本?”
- 仓库层(特征值链)不需要再分三套 CRUD:统一吃
特征值主信息类就行。 - 比较/相似度计算仍然要按类型和比较模式分流:这是不可消除的本质差异(标量能做区间,字符串多为等值,向量多为距离)。
一句话:API 不分,算法分。
5. 融合规范(重点:在哪一层融合)
5.1 特征值层只做两件事
- 去重共享(全局唯一)
- 记录统计(命中次数/可信度)
5.2 融合发生在特征节点层(你已经具备结构)
特征节点主信息里已经有:
当前值值列表区间摘要(可选)+区间语义
规范建议的“融合写入”:
覆盖:
当前值 = 新值,并按需 append 到值列表融合:
- 先
获取或创建_精确(新值key)得到全局值节点 - 再更新
值列表、更新区间摘要(标量/可比较的维度) 当前值选代表值(例如最近一次、或命中最高、或更可信)
- 先
这样你不会出现“改一个值,所有引用它的地方都被强行改掉”的灾难。
6. 序列化规范(存档不丢共享语义)
你现在的特征值读写,是把类型/比较模式/命中次数/可信度和 variant 内容写入/读出。
规范要求加载时必须做两步:
先读出一批“值对象”(临时列表)
逐个走
获取或创建_精确入库:- 这样可自动去重恢复“全局唯一共享”
- 如果同 key 出现多次:合并
命中次数/可信度(例如命中次数求和,可信度取 max 或加权)
7. “由简入繁,再由繁入简”的最终落点(给你一句总纲)
- 由简入繁:为了表达力与算法多样性,把“值”扩展到
variant + 比较模式(支持标量、向量、占据块、字符串、海明等)。 - 由繁入简:为了工程可控性,把增删改查统一成一个 key 类型(特征值主信息类),把复杂性收敛到“比较模式 + 上层融合策略”。
现在这版特征值主信息类 + 特征值载体 variant就是那个“简化后的核”,同时仍保留海明/向量/字符串的表达能力。