📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入
Easysearch 布尔查询子句重排序(二)|ConjunctionDISI 按 cost 排序源码解析

Lucene 如何让最稀疏的迭代器领跑,最大化跳过无效文档

INFINI Easysearch 是一款专注于企业级场景的分布式近实时搜索与分析引擎。它以 Apache Lucene 为内核进行了增强,在保持与行业主流搜索协议及开发生态完全兼容的同时,重点强化了安全性、稳定性、压缩率及信创兼容性。


一、回顾与引入 #

第一篇中,我们走完了布尔查询从用户 JSON 到 Lucene 执行的构建层旅程:Easysearch 的 BoolQueryBuilder 会保留同类子句的书写顺序,Lucene 的 BooleanQuery.rewrite() 则通过等价改写简化查询结构。

其中,和本文关系最直接的是 SHOULD + FILTER → MUST:一个原本只是“可选加分”的 SHOULD 子句,如果同时出现在 FILTER 中,就会被改写成 MUST。它的执行路径也随之改变——从可选评分路径,进入更直接的合取路径

所谓合取路径,就是按 AND 语义执行查询:所有必选条件都要同时满足,任意一个不满足就可以跳过该文档。对于 MUST / FILTER 这类合取子句,真正影响性能的不是用户在 JSON 里先写谁、后写谁,而是 Lucene 在执行层如何安排它们的检查顺序。

这就是本文要讲的“布尔查询子句重排序”:进入 Scorer 构造阶段后,每个 MUST / FILTER 子句会变成对应的文档迭代器,Lucene 再按 cost() 对这些迭代器重新排序,让匹配文档最少的迭代器先领跑。

一个直觉可以帮助我们理解:在 AND 查询中,谁的结果最少,谁最有"话语权"。因为 AND 语义要求所有条件都满足,所以结果最少的那个条件能最快地排除不满足的文档,剩下的条件只需要确认即可。

本文就专注于这条合取路径的核心机制:ConjunctionDISI 如何按 cost 排序,让最稀疏的迭代器领跑整场迭代


二、前置:什么情况下走 ConjunctionScorer? #

上面已经说明,rewrite 可能会把子句带入合取路径;但并不是所有 bool 查询都会走这条路径。本节先界定范围:哪些查询会进入合取路径,哪些不会。Lucene 在 Boolean2ScorerSupplier.getInternal() 中会根据子句组合做这个判断。

查询形态是否进入合取路径简单理解
多个 MUST / FILTER是:ConjunctionScorerConjunctionDISI标准 AND 查询:所有条件都必须满足
只有一个 MUST / FILTER不需要只有一个迭代器,没必要做求交和排序
MUST / FILTER + SHOULD,且 minShouldMatch = 0必选部分进入先用 MUST / FILTER 圈定候选集,SHOULD 只负责加分
MUST / FILTER + SHOULD,且 minShouldMatch > 0整体进入除了必选条件,还要求 SHOULD 至少命中 N 个
只有 SHOULD这是 OR 查询,走 WANDScorer 或 DisjunctionSumScorer,不是本文的合取路径

对本文来说,记住一个判断就够了:只要查询里出现多个“必须同时满足”的条件,Lucene 就需要做交集计算,ConjunctionDISI 的 cost 排序就有发挥空间。

那么 ConjunctionDISI 内部到底做了什么?让我们深入源码。


三、核心揭秘:ConjunctionDISI 按 cost 排序 #

这是合取查询最核心的优化。

3.1 生活类比 #

可以把合取查询理解成多条件筛选:先用结果最少的条件缩小候选集,再让其他条件确认,通常最省事。

比如在快递系统里找“已签收、发往北京、备注里有易碎品”的包裹。“已签收”和“发往北京”的包裹可能很多,但“备注里有易碎品”的包裹很少。先从“易碎品”开始查,再确认它是否发往北京、是否已签收,比先遍历所有已签收包裹更快。

3.2 源码解析 #

先解释一下“迭代器”,比如下文的 DocIdSetIterator。迭代器可以理解为某个查询条件对应的匹配文档列表游标。它负责在自己的列表里向前移动,告诉 Lucene:下一个匹配这个条件的 docID 是谁。

比如 author:sam 的迭代器里可能是 [42, 78, 203]category:ai 的迭代器里可能是 [12, 42, 100, 203]。执行 AND 查询时,Lucene 要做的就是不断推进这些游标,找到它们共同出现的 docID,比如这里的 42203

所以,本文说的“重排序”不是改写用户 JSON 里的子句顺序,而是在执行阶段对这些子句对应的迭代器排序:谁的 cost() 更小,谁就更靠前执行。

核心逻辑在 Lucene 的 ConjunctionDISI.javaConjunctionDISI.java:154-163):

private ConjunctionDISI(List<? extends DocIdSetIterator> iterators) {
    assert iterators.size() >= 2;

    // Sort the array the first time to allow the least frequent DocsEnum to
    // lead the matching.
    CollectionUtil.timSort(iterators,
        (o1, o2) -> Long.compare(o1.cost(), o2.cost()));
    lead1 = iterators.get(0);  // 代价最小 → 领头
    lead2 = iterators.get(1);
    others = iterators.subList(2, iterators.size()).toArray(new DocIdSetIterator[0]);
}

三行代码,逻辑清晰:

  1. cost() 升序排序cost() 返回迭代器预估的匹配文档数,越少越"便宜"(注:cost 是预估值,实际匹配数可能有偏差,但排序逻辑依然成立)
  2. lead1:代价最小的迭代器,负责领头跳转——它最稀疏,每次跳转跳过的文档最多
  3. lead2:代价第二小的迭代器,负责二次确认
  4. others:其余迭代器,仅在 lead1 和 lead2 都停下时才被调用

3.3 执行过程 #

核心迭代方法 doNext()ConjunctionDISI.java:165-199):

private int doNext(int doc) throws IOException {
    advanceHead:
    for (; ; ) {
        // doc 是当前 lead1 停住的位置;lead1 是最稀疏的迭代器,负责给出候选 docID
        assert doc == lead1.docID();

        // 先让 lead2 追上 lead1:advance(doc) 会跳到 >= doc 的第一个文档
        final int next2 = lead2.advance(doc);
        if (next2 != doc) {
            // lead2 跳过了当前 doc,说明当前候选不匹配;lead1 跳到 lead2 的位置作为新起点
            doc = lead1.advance(next2);
            if (next2 != doc) {
                // 仍没对齐,说明 lead1 又跳到了更后面,重新开始对齐
                continue;
            }
        }

        // lead1 和 lead2 对齐后,再检查其他迭代器
        for (DocIdSetIterator other : others) {
            // other 可能在上一轮已经被推进过;只有落后时才需要追赶
            if (other.docID() < doc) {
                final int next = other.advance(doc);
                if (next > doc) {
                    // other 跳过了当前 doc,当前候选失败;lead1 追到新的最大 docID
                    doc = lead1.advance(next);
                    continue advanceHead;
                }
            }
        }

        // 所有迭代器都停在同一个 doc 上 → 这个文档满足所有条件
        return doc;
    }
}

这段代码的核心就是“不断对齐”:谁跳到了更大的 docID,其他迭代器就追上去;直到所有迭代器停在同一个 docID,才算匹配成功。

例如 lead1 停在 78,而 lead2.advance(78) 返回 100,就说明 78 不可能匹配。Lucene 会直接把 lead1 推进到 100 附近,而不是继续检查 79、80、81……这些中间文档。

3.4 直观示例 #

为突出 cost 的量级差异,下面用夸张的数量级示意(§六会给出真实测试索引的实测数据,数量级更小,但结论一致):

查询:must: [status:published(100万), category:ai(1万), author:sam(500)]

迭代器按 cost 排序后:
  lead1: author:sam     cost=500     ← 最稀疏,领头跳转
  lead2: category:ai    cost=10,000
  other: status:published cost=1,000,000

执行过程:
  lead1 → doc=42 → lead2确认✓ → other确认✓ → 匹配!
  lead1 → doc=78 → lead2确认✗ → 跳过(不用查 other)
  lead1 → doc=203 → lead2确认✓ → other确认✓ → 匹配!

  如果没有 cost 排序,让高频词先给出候选,后续条件就要确认大量无效文档。

cost排序的效果:Lucene 实际执行时,lead1 一定是 cost 最小的迭代器(即最低频)。低频迭代器先领头,可以显著减少候选文档数量。

3.5 子合取展平 #

还有一个值得注意的细节:当嵌套的 ConjunctionDISI 作为子句出现时,会被"拆包"展平( ConjunctionDISI.java:54-77):

} else if (disi.getClass() == ConjunctionDISI.class) {
    // 发现子句本身也是一个 ConjunctionDISI,也就是嵌套的 AND 查询
    ConjunctionDISI conjunction = (ConjunctionDISI) disi;

    // 不把整个子 ConjunctionDISI 当成一个黑盒,
    // 而是把它内部已经拆好的 lead1、lead2、others 全部取出来
    allIterators.add(conjunction.lead1);
    allIterators.add(conjunction.lead2);
    Collections.addAll(allIterators, conjunction.others);
}

这些迭代器取出来后,会和外层迭代器一起进入统一排序流程。也就是说,Lucene 不会把内层 AND 当成一个整体参与外层排序,而是先展平,再让所有迭代器按 cost 统一排序。

这确保了基于 cost 估算的全局最优迭代顺序——如果内层有一个极稀疏的迭代器,它也有机会“越级”成为全局 lead1,而不是被锁在内层。

注意这里使用了精确类检查 disi.getClass() == ConjunctionDISI.class,而不是 instanceof。这是为了确保只拆包原始的 ConjunctionDISI,不误拆子类(如 BitSetConjunctionDISI,它有自己的优化路径)。


四、延伸:候选文档确定后,验证也要按成本排序 #

前面讲的是 cost() 排序:在多个迭代器之间,先让匹配文档最少的迭代器领头,尽量少产生候选文档。它背后的思想是:把执行成本低、过滤能力强的步骤放在前面,尽早排除不匹配的文档

matchCost() 排序是这个思想在“验证阶段”的延伸:cost() 决定“谁先领头找候选”,matchCost() 决定“先做哪个精确验证”。

为什么候选文档还要验证?因为有些迭代器是"近似的"——先用低成本方式定位可能匹配的文档,再用精确方式二次确认。典型场景是短语查询:先对短语中的每个词做倒排合取,得到“包含全部词”的候选文档,再检查这些词是否出现在符合要求的相对位置上。前者用 posting list 快速缩小范围,后者才是真正的精确匹配。

Lucene 用 TwoPhaseIterator 表示这种两阶段验证,而 ConjunctionTwoPhaseIterator 会按 matchCost() 从低到高排序,让便宜的验证先执行;一旦失败,就不用再执行后面更贵的验证( ConjunctionDISI.java:317-357):

CollectionUtil.timSort(twoPhaseIterators,
    (o1, o2) -> Float.compare(o1.matchCost(), o2.matchCost()));

类比:先查身份证(快,matchCost 低),再查指纹(慢,matchCost 高),而不是反过来。如果身份证就不对,指纹根本不用查。

cost() 不同,matchCost() 没有统一公式:它是每个 TwoPhaseIterator 子类按自身验证逻辑估算的“简单操作数”(如 DocValues 查 bitset 约记为 3 次操作)。这个值比较粗略,实际排序时用到的只是相对大小——让便宜的验证先跑。

在实际代码中,ConjunctionDISI.createConjunction() 会把执行过程拆成两个阶段来看:

  • 找候选 docID:用 allIterators 完成。普通迭代器会直接放进来;如果某个查询是两阶段查询,就把它的“近似迭代器”放进来,先参与 cost() 排序和合取对齐。
  • 验证候选是否真的匹配:用 twoPhaseIterators 完成。这里保存的不是另一批文档列表,而是候选 docID 命中后要执行的 matches() 验证逻辑,并按 matchCost() 排序。

所以可以理解为:allIterators 负责“先找可能匹配的文档”,twoPhaseIterators 负责“再确认这些文档是否真的匹配”。前者按 cost() 排序,目标是少产生候选;后者按 matchCost() 排序,目标是少做昂贵验证。


五、进阶补充:cost 排序还会影响子查询策略 #

前面讲的是 cost 排序对“当前这一层”的影响:选出最稀疏的迭代器作为 lead1,减少候选文档。但 cost 排序选出的 lead1 还会带来一个连锁效应:它把代价信息继续传给子查询,让子查询也能根据外层的调用频率选择更合适的执行方式。

这个连锁效应的起点是:在合取查询里,外层最终会由最稀疏的迭代器领头,所以其他子查询被推进的次数通常不会超过这个领头迭代器的规模。这个规模就是向外传播给子查询的代价上限。Lucene 在 Boolean2ScorerSupplier.getInternal() 中用 Math.min(leadCost, cost()) 给这个估计加了一个上限( Boolean2ScorerSupplier.java:126):如果上层传来的 leadCost 过大,就用当前查询自己的 cost() 压住,避免子查询误判使用模式。对于纯合取查询来说,这个值通常接近 lead1.cost()

这个向外传播的代价上限,就是 leadCost。它可以理解为上层给子查询的一个提示:“接下来你大概要被推进这么多次”。它不是 ConjunctionDISI 内部的概念,而是 ScorerSupplier.get(long leadCost) 的参数。

这里的“推进”指的是:上层会不断要求子查询的迭代器向后移动,要么调用 nextDoc() 走到下一个匹配文档,要么调用 advance(target) 直接跳到 >= target 的文档。

为什么这个提示有用?因为不同实现适合不同使用方式:如果会被频繁推进,就适合用支持高效跳转的结构;如果只会被少量推进,就可以选择初始化成本更低的结构。一个典型例子是 IndexOrDocValuesQuery。它内部同时持有索引结构(点数据 / term 查询)和 DocValues 两种策略,会根据 leadCost 动态选择( IndexOrDocValuesQuery.java:176-186):

public Scorer get(long leadCost) throws IOException {
    final long threshold = cost() >>> 3;  // cost / 8
    if (threshold <= leadCost) {
        return indexScorerSupplier.get(leadCost);   // 推进频繁:用索引结构
    } else {
        return dvScorerSupplier.get(leadCost);      // 推进较少:用 DocValues
    }
}

简单说:外层通过 cost 排序估算推进频率,再把这个信息传给子查询;子查询只需要判断“我会被频繁推进,还是只会偶尔确认”,就能做出局部最优选择。


六、一个 MUST 查询是如何被重新排序的 #

用一个简单的 MUST 查询,把第一篇的 rewrite 和本文的 cost 排序串起来。下面这个例子中,status:published 写在前面,category:ai 写在后面:

GET /bool_cost_profile_test/_search
{
  "profile": true,
  "query": {
    "bool": {
      "must": [
        { "term": { "status": "published" }},
        { "term": { "category": "ai" }}
      ]
    }
  }
}

完整过程可以拆成四步:

① Easysearch 层:按用户写法构建 BooleanQuery
   profile description 仍显示:+status:published +category:ai

② Lucene rewrite:2 个 MUST,无重复、无矛盾
   查询形态保持为两个 MUST 子句

③ Scorer 构造:
   Boolean2ScorerSupplier.req() → new ConjunctionScorer(...)
   ConjunctionScorer 内部创建 ConjunctionDISI
   ConjunctionDISI 再按 cost 对迭代器排序

④ 执行:
   低 cost 的 category:ai 负责产生候选 docID
   status:published 通过 advance(candidate) 追赶确认

在本地 Easysearch 2.2.0 / Lucene 9.12.2 的测试索引中,status:published 约 900 条,category:ai 约 100 条。实际 profile 结果是:

子句                 next_doc_count   advance_count   说明
──────────────────────────────────────────────────────────────
category:ai          91               1               低 cost,产生候选
status:published     0                91              跟随候选,用 advance 确认

把 JSON 里的两个 MUST 顺序反过来再查,profile 仍然显示 category:ai 通过 nextDoc() 产生候选,status:published 通过 advance() 确认。也就是说,description 会保留查询展示顺序,但真正执行时的迭代器顺序由 cost 排序决定。

这就是本文的关键点:用户在 JSON 中先写谁,不等于执行时谁先跑。对于合取查询,Lucene 会在 Scorer 构造阶段按 cost 重新安排迭代器顺序,让更稀疏的条件领头。唯一的例外是多词查询混入 must/filter 且版本较老的场景,见 §八末尾的边界说明。

双条件场景验证了"重排序确实发生",接下来看三条件场景如何用 Profile 观察。


七、如何用 Profile API 观察 cost 排序效果 #

现在扩展到三条件,重点看一个更极端的对比:author:sam 只有 5 条,status:published 有 900 条。Profile 不会直接告诉你 lead1 是谁,但可以通过 next_doc_countadvance_count 的分布间接推断。

在同一个测试索引上,查三个 MUST:

"must": [
  { "term": { "status": "published" }},
  { "term": { "category": "ai" }},
  { "term": { "author": "sam" }}
]

BooleanQuery 的子节点大致如下:

子句                 next_doc_count   advance_count   说明
──────────────────────────────────────────────────────────────
author:sam           5                1               最稀疏,负责产生候选 docID
category:ai          0                6               跟随候选,用 advance 对齐
status:published     0                5               跟随候选,用 advance 对齐

注意跟随迭代器的 advance_count 未必完全相等,这和实际匹配过程中发生的追赶次数有关,不影响"谁是领头"的判断。

如何看这份 Profile #

Profile 不会直接打印 lead1,但指标和源码是对应的:ConjunctionDISI.nextDoc() 会调用 lead1.nextDoc() 产生下一个候选;进入 doNext() 后,再通过 lead2.advance(doc)other.advance(doc) 让其他迭代器追赶。next_doc_countadvance_count 统计的正是这些底层调用。

可以总结成一条简单观察规律:

  • 领头迭代器next_doc_count 通常更高,它要不断产生候选
  • 跟随迭代器advance_count 通常更高,它只在候选 docID 上确认

需要注意:Profile 只提供观察线索,不同 Lucene 版本、查询类型(DocValues、PointRange 等)和数据分布,都可能让 next_doc / advance 的表现有所不同。特别是当查询走了 BitSet 优化路径或 BlockMaxConjunctionScorer 时,指标分布会不一样。解读时要结合 descriptiontype 和各子节点的 breakdown 一起判断。


八、小结与预告 #

回到本系列的主题:布尔查询子句重排序。本文讲的是其中最典型的一种——MUST / FILTER 这类合取子句进入执行层后,会从“用户书写顺序”转换为“按 cost 排序的迭代器执行顺序”。

本文着重介绍的核心机制包括:

  • ConjunctionDISI 按 cost 排序:最稀疏的迭代器领头,其他迭代器仅做确认,最大化跳过无效文档
  • 两阶段验证按 matchCost 排序:最便宜的验证先执行,失败即可短路
  • leadCost 传播:代价信息从外向内传播,子查询据此做局部最优策略选择(如 IndexOrDocValuesQuery 的自适应切换)
  • 子合取展平:嵌套的 ConjunctionDISI 被拆包到同一层级,确保全局最优的迭代顺序

这些机制的共同特点是:代价感知 + 动态决策——排序在 Scorer 构造时完成,与用户书写顺序无关。

一条边界:老版本里混入多词查询,顺序仍然敏感 #

“与书写顺序无关"有个前提:每个子句在调度阶段都能被轻量地试探。TermQuery 满足——预建的 TermStates 让它能 O(1) 判断某段有无匹配,没有就返回 null,短路掉还没轮到的子句。但 prefix / wildcard / regexp / range-on-keyword / fuzzy 这类多词查询在 Lucene 9.5 之前不满足:它们一旦被调度就同步干重活——枚举全部 term、读倒排、建 bitset——而调度又是按书写顺序进行的。

在一个 2900 万文档、23 个主分段的索引上实测,must 里放一个极稀疏的 term(命中 12 篇,只落在 6 个段)和一个极稠密的 prefix(展开约 11.7 万个 term):

must 写法prefix.build_scorer_count稳态耗时
[prefix, term]36≈ 92 ms
[term, prefix]6≈ 35 ms

两条查询逻辑等价却差了近 3 倍:prefix 写前面时,其余 17 个段的 term 返回 null 触发整段短路,但 prefix 的 bitset 已经白白建好又扔掉;term 写前面时,这些段根本轮不到 prefix 出场。

💡 结论:稀疏廉价的子句写在前面,让它先行短路,昂贵的多词查询就不会被无效触发。

分界线是 Lucene 9.5( PR #12055):多词查询的 wrapper 自此实现了轻量的 ScorerSupplier,调度阶段只估成本不干活,重活推迟到真正取迭代器时才做,顺序自此真正无关。对应到版本:Easysearch 1.x 基于 Lucene 8.11,存在此问题Easysearch 2.x 基于 Lucene 9.12,已包含修复——本文的全部结论在其上均成立。

但合取查询的优化目标很明确:所有子句都要匹配,找"最少"的那个领头即可。析取(SHOULD)场景完全不同:不需要全部匹配,而是找 Top-K 高分文档。优化目标从"最少匹配"变为"最高分数贡献”,WAND 算法登场——第三篇详解。

标签
Easysearch x
布尔查询 x
BoolQuery x
排序 x
自主可控 x
超聚变 x
FusionOS x
信创 x
CocoAI x
Elasticsearch x
中国银行 x
搜索引擎 x
DTCC x
中国数据库技术大会 x
爱加密 x
安全 x
极限网关 x
PICC x
Gateway x
Coco AI x
信创产品评估证书 x
达梦数据库 x
CDC x
AI搜索 x
DBX x
客户端 x
可视化 x
数据库 x
达梦 x
兼容认证 x
产品更新 x
巡检 x
CCR x
语义搜索 x
向量检索 x
RAG x
knn x
2026 x
信通院 x
TDBC x
可信数据库大会 x
中国数据库产业图谱 x
ZSTD x
Bboss x
开源 x
国产化 x
Java 客户端 x
Console x
搜索平台 x
鲲鹏 x
统信UOS x
DBackup x
鼎甲数据 x
备份与恢复 x
Coco x
迁移 x
快照 x
snapshot x
向量 x
IK x
分词 x
performance x
插件 x
开发 x
自定义 x
扩展 x
AI x
幻觉 x
大模型 x
Agent x
Mem0 x
MCP x
AI Agent x
kNN x
规则引擎 x
银行 x
保险 x
风控 x
Rules x
Percolator x
国产 x
搜索 x
Lucene x
GraalVM x
JDK x
赞助 x
开源生态 x
社区 x
二等奖 x
兴智杯 x
人工智能 x
赛事 x
低空经济 x
商业化 x
数据分析 x
金猿奖 x
技术卓越奖 x
创新产品奖 x
IT168 x
APM x
Skywalking x
Easy-Es x
GitLab x
代码审核 x
石油石化 x
Gitee x
投票 x
Meilisearch x
Rust x
轻量级 x
搜索百科 x
Docker x
Docker Compose x
Easyserach x
DevOps x
国产替代 x
backup x
esdump x
source_reuse x
ignore_above x
OpenSearch x
AWS x
Solr x
Easyearch x
发明专利 x
数据分区 x
国际专利 x
一等奖 x
人工智能应用创新大赛 x
bulk x
embedding x
OpenAI x
2025 x
搜索型数据库 x
上海开源创新菁英荟 x
开源创新新星企业 x
Workshop x
AI 搜索 x
智能助手 x
Automation x
Logstash x
MongoDB x
开源中国 x
直播 x
merge x
Elasticsearch 9 x
GitCode x
Cloud x
rollup x
Kubernetes x
Operator x
Arm64 x
Snapshot x
S3 x
Grafana x
Opensearch x
Nginx x
直播活动 x
搜索客社区 x
Meetup x
ES x
企业搜索 x
DeepSeek x
certificate x
windows x
Rollup x
TopN x
Filebeat x
Ubuntu x
请求限速 x
INFINI Console x
指标 x
Kibana x
多集群 x
client x
Spring Boot x
ECE x
ES Bulk x
vector database x
Postgres x
可搜索快照 x
SDK x
官网 x
Web 开发 x
Next.js x
React x
Three.js x
Metrics x
Helm x
filter x
querycache x
practice x
localStorage x
响应式 x
时间组件 x
时区组件 x
极限科技 x
三周年 x
周年庆 x
国家高新技术企业 x
校园招聘 x
湖北工业大学 x
Tauri x
Web 开发人员 x
桌面应用开发 x
桌面端 x
Electron x
Pizza x
认证培训 x
报名 x
Scrapy x
爬虫 x
Rust开发者大会 x
docsearch x
文档搜索 x
Easyseach x
有奖征文 x
黑神话悟空 x
EKS x
征文系列 x
跨集群搜索 x
科技中小企业 x
白皮书 x
Python SDK x
数据库产业图谱 x
超大规模 x
分布式集群 x
写入限流 x
2024可信数据库发展大会 x
创新型中小企业 x
搜索数据库 x
正排索引 x
免费许可证 x
K8S x
DTC2024 x
实时搜索 x
ES国产化 x
Redis x
OOM x
测试 x
内存 x
趋势 x
AI绘画 x
Stable Diffusion x
Diffusion x
Model x
GAN x
知识图 x
向量数据库 x
中国信通院 x
星河(Galaxy) x
标杆案例 x
鲲鹏技术认证 x
日志平台 x
LDAP x
Loadgen x
中国一汽 x
国内数据库 x
墨天轮 x
监控系统 x
集成测试 x
Helm Charts x
国产适配 x
兆芯 x
Linux x
LoongArch x
信创适配 x
二维拆分算法 x
中国移动云 x
Vault x
加密 x
安全工具 x
图片搜索 x
Alerting x
SQL x
Embedding x
可信数据库 x
统信 x
海光 x
龙芯 x
restore x
Arm x
大数据企业证书 x
移动云大会 x
信通院产品评测 x
国内首家 x
数据可视化 x
北京软协 x
第十届理事会会员单位 x
Apache Arrow x
宣传片 x
大会分享 x
多集群管理 x
无缝数据迁移 x
Loadrun x
INFINI Gateway x
log4j x