返回博客

Palantir 的搜索与发现:在百万对象中找到你要的那个

我们每天都在使用 Google、百度搜索互联网内容,体验流畅自然。但当你在企业内部搜索数据时,体验往往是灾难性的。

Coomia发布于 2025年6月16日23 分钟阅读
分享本文Twitter / X

系列:S1 Palantir 解密 · 第 15 篇 | 难度:入门 | 阅读时间:15 分钟

Palantir 的搜索与发现:在百万对象中找到你要的那个

#TL;DR

  • Foundry 的搜索不是传统的"关键词搜表" -- 它搜索的是 Ontology 对象,理解对象类型、属性、关系和权限,让用户像使用 Google 一样在企业数据中搜索,但结果是结构化的业务对象。
  • 权限感知搜索是 Foundry 的核心差异化能力 -- 你永远只能搜索到你有权限看到的对象,搜索结果自动过滤,不会泄露任何你不应该看到的数据,这对政府和金融客户至关重要。
  • coomia-dip 实现了 6 种搜索模式(BEST_MATCH/PREFIX/FUZZY/EXACT/WILDCARD/REGEX)+ 3 种分面搜索(TERMS/RANGE/DATE_RANGE)+ 基于 Redis 的热词/近期搜索自动建议,在开源生态中构建 Ontology 感知的搜索体验。

#1. 为什么企业搜索如此困难?

#1.1 消费者搜索 vs 企业搜索

我们每天都在使用 Google、百度搜索互联网内容,体验流畅自然。但当你在企业内部搜索数据时,体验往往是灾难性的。

Code
消费者搜索 vs 企业搜索
================================================

Google 搜索:
  输入: "北京天气"
  结果: 即时显示天气卡片, 温度、湿度、预报
  体验: ★★★★★

企业传统搜索:
  输入: "客户张三的订单"
  结果: ???

  场景 1 (没有搜索):
    "请联系 IT 部门提工单,工单处理时间 3-5 个工作日"

  场景 2 (有基本搜索):
    返回 47 个结果:
    - CRM 中的客户记录 (3 条)
    - ERP 中的订单数据 (12 条)
    - 邮件中提到"张三"的邮件 (28 条)
    - 某个 Excel 文件 (4 个)

    问题: 哪些是同一个"张三"?
    问题: 我有权限看这些数据吗?
    问题: 哪些信息是最新的?

  Foundry 搜索:
    返回结构化结果:
    ┌─────────────────────────────────────┐
    │ Customer: 张三                       │
    │ ID: CUST-2024-78901                 │
    │ 状态: 活跃                           │
    │ 关联订单: 12 个                      │
    │ 最新订单: ORD-2024-56789 (进行中)    │
    │ 客户经理: 李四                       │
    │ [查看详情] [查看关联] [查看历史]      │
    └─────────────────────────────────────┘
    体验: ★★★★☆

#1.2 企业搜索的三大难题

Code
企业搜索三大难题
================================================

难题 1: 数据分散
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ CRM  │ │ ERP  │ │ HRM  │ │ 邮件 │ │ 文件 │
└──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘
   │        │        │        │        │
   ▼        ▼        ▼        ▼        ▼
 同一个"客户"在 5 个系统中有 5 种不同的表示
 ID 不同, 字段不同, 更新时间不同

难题 2: 权限复杂
┌──────────────────────────────────────────┐
│  用户 A (销售): 能看客户联系方式          │
│  用户 B (财务): 能看客户账务信息          │
│  用户 C (合规): 能看客户风险评分          │
│  用户 D (实习): 只能看客户名称            │
│                                          │
│  同一个搜索请求, 4 个人看到不同的结果     │
└──────────────────────────────────────────┘

难题 3: 语义理解
┌──────────────────────────────────────────┐
│  搜索 "大客户":                           │
│  - 指的是订单金额大的客户?               │
│  - 指的是公司规模大的客户?               │
│  - 指的是"大客户部"名下的客户?           │
│  - 指的是客户等级为"大客户"的?           │
│                                          │
│  没有 Ontology = 无法消除歧义             │
│  有 Ontology = 精确理解语义               │
└──────────────────────────────────────────┘

#2. Foundry 的 Ontology 感知搜索

#2.1 搜索的是对象,不是表

这是 Foundry 搜索与传统数据库搜索的根本区别:

Code
传统搜索 vs Ontology 搜索
================================================

传统数据库搜索:
  SELECT * FROM customers WHERE name LIKE '%张三%'
  UNION
  SELECT * FROM orders WHERE customer_name LIKE '%张三%'
  UNION
  SELECT * FROM tickets WHERE description LIKE '%张三%'

  问题: 跨表搜索需要知道表结构
  问题: 结果是"行",不是"对象"
  问题: 无法理解对象之间的关系

Foundry Ontology 搜索:
  Search("张三", types=[Customer, Order, Ticket])

  引擎理解:
  - Customer 是一个对象类型, 有 name, email, phone 等属性
  - Order 与 Customer 有 "placed_by" 关系
  - Ticket 与 Customer 有 "reported_by" 关系

  返回:
  ┌─ Customer 对象 ────────────────────────┐
  │ 张三 (CUST-78901)                      │
  │ ├─ placed_by → [12 个订单]              │
  │ ├─ reported_by → [3 个工单]             │
  │ └─ managed_by → 李四 (员工)             │
  └────────────────────────────────────────┘

#2.2 搜索架构

Code
Foundry 搜索系统架构
================================================

用户搜索请求
     │
     ▼
┌─────────────────────────────────────────────┐
│  Search Gateway                              │
│                                              │
│  1. 解析查询 (NLP / 结构化解析)               │
│  2. 权限校验 (ACL 过滤)                       │
│  3. 查询路由                                  │
└────────┬──────────────────────┬──────────────┘
         │                      │
    ┌────▼──────┐         ┌────▼──────┐
    │ Full-Text │         │ Structured│
    │ Search    │         │ Search    │
    │ Engine    │         │ Engine    │
    │           │         │           │
    │(Elasticsearch)      │(Ontology  │
    │           │         │ Index)    │
    └────┬──────┘         └────┬──────┘
         │                      │
         └──────────┬───────────┘
                    │
              ┌─────▼──────┐
              │  Result     │
              │  Merger &   │
              │  Ranker     │
              │             │
              │ 合并结果     │
              │ 相关性排序   │
              │ 权限过滤     │
              │ 分面聚合     │
              └─────┬──────┘
                    │
                    ▼
              搜索结果 (对象列表)

#2.3 多维度搜索

Code
Foundry 搜索维度
================================================

维度 1: 全文搜索
  搜索 "supply chain disruption"
  → 匹配所有包含相关文本的对象
  → 支持同义词、词干提取、模糊匹配

维度 2: 属性搜索
  搜索 Customer WHERE revenue > 1000000
  → 精确的属性值过滤
  → 支持数值范围、日期范围、枚举值

维度 3: 关系搜索
  搜索 Order WHERE Customer.industry = "制造业"
  → 通过关系链搜索关联对象
  → 支持多跳关系遍历

维度 4: 地理搜索
  搜索 Facility WHERE location WITHIN 50km OF (39.9, 116.4)
  → 地理位置相关搜索
  → 支持多边形、圆形、多边形区域

维度 5: 时间搜索
  搜索 Event WHERE timestamp BETWEEN "2024-01" AND "2024-03"
  → 时间序列相关搜索
  → 支持相对时间 ("last 7 days")

组合搜索:
  搜索 Order
    WHERE Customer.industry = "制造业"
    AND amount > 100000
    AND created_at > "2024-01-01"
    AND location WITHIN 100km OF Shanghai
    AND status IN ["pending", "processing"]
    TEXT_MATCH "urgent delivery"

#3.1 什么是分面搜索

Code
分面搜索示意
================================================

搜索: "laptop" 在电商网站

左侧分面面板:                    右侧搜索结果:
┌─────────────────────┐          ┌──────────────────┐
│ 品牌                │          │ MacBook Pro 14"  │
│  ☐ Apple    (234)   │          │ ¥14,999          │
│  ☑ Dell     (189)   │          ├──────────────────┤
│  ☐ Lenovo   (156)   │          │ Dell XPS 15      │
│  ☐ HP       (98)    │          │ ¥9,999           │
│                     │          ├──────────────────┤
│ 价格区间            │          │ Dell Latitude    │
│  ☐ < ¥5,000 (120)   │          │ ¥7,599           │
│  ☑ ¥5-10K   (234)   │          ├──────────────────┤
│  ☐ > ¥10K   (189)   │          │ ...              │
│                     │          └──────────────────┘
│ 内存                │
│  ☐ 8GB      (156)   │          显示 189 条结果
│  ☐ 16GB     (234)   │          (已过滤: Dell, ¥5-10K)
│  ☐ 32GB     (89)    │
└─────────────────────┘

#3.2 Foundry 中的分面搜索

在 Foundry 中,分面搜索理解 Ontology 的类型系统:

Code
Foundry Ontology 分面搜索
================================================

搜索: 所有 Order 对象

分面面板:                        搜索结果:
┌────────────────────────┐       ┌──────────────────────┐
│ 对象类型                │       │ ORD-2024-001         │
│  ☑ Order       (15234) │       │ 客户: 某某公司        │
│  ☐ LineItem    (45692) │       │ 金额: $45,000        │
│  ☐ Shipment    (8923)  │       │ 状态: 进行中          │
│                        │       ├──────────────────────┤
│ 状态 (Ontology 枚举)    │       │ ORD-2024-002         │
│  ☐ pending     (3421)  │       │ 客户: 另一公司        │
│  ☑ processing  (5612)  │       │ 金额: $12,300        │
│  ☐ shipped     (4201)  │       │ 状态: 进行中          │
│  ☐ delivered   (2000)  │       ├──────────────────────┤
│                        │       │ ...                  │
│ 金额范围               │       └──────────────────────┘
│  ☐ < $1K       (2345)  │
│  ☑ $1K-$50K    (8901)  │       显示 5612 条结果
│  ☐ $50K-$1M    (3456)  │       (过滤: processing,
│  ☐ > $1M       (532)   │        $1K-$50K)
│                        │
│ 客户行业 (关联对象属性)  │       分面来自 Ontology 定义:
│  ☐ 制造业      (4521)  │       - 属性类型自动生成分面
│  ☐ 金融        (3212)  │       - 枚举值 = TERMS 分面
│  ☐ 零售        (2345)  │       - 数值 = RANGE 分面
│  ☐ 科技        (5156)  │       - 日期 = DATE_RANGE 分面
│                        │
│ 创建日期               │
│  ☐ 最近 7 天   (1234)  │
│  ☑ 最近 30 天  (5678)  │
│  ☐ 最近 90 天  (12345) │
└────────────────────────┘

#4. 权限感知搜索

#4.1 你只能找到你能看到的

这是 Foundry 搜索最重要的安全特性:

Code
权限感知搜索
================================================

数据库中实际存在的对象:
  Customer: [张三, 李四, 王五, 赵六, 刘七]
  Order: [ORD-001, ORD-002, ORD-003, ..., ORD-100]

用户 A (华东区销售经理):
  权限: 华东区客户 + 自己的订单
  搜索 "客户" → 结果: [张三, 李四]  (2/5 客户)
  搜索 "订单" → 结果: [ORD-001, ORD-023, ORD-045]

用户 B (全国销售总监):
  权限: 所有区域客户 + 所有订单
  搜索 "客户" → 结果: [张三, 李四, 王五, 赵六, 刘七]
  搜索 "订单" → 结果: [ORD-001, ..., ORD-100]

用户 C (合规审计):
  权限: 所有客户 (只看合规字段) + 高风险订单
  搜索 "客户" → 结果: [张三, 李四, 王五, 赵六, 刘七]
    但每个客户只显示: 名称, 风险等级, 合规状态
    不显示: 联系方式, 交易记录

关键点:
  - 搜索结果的数量不同 (行级权限)
  - 搜索结果的字段不同 (列级权限)
  - 分面统计数字也会相应调整
  - 永远不会泄露"你无权看到的数据"

#4.2 实现机制

Code
权限感知搜索实现
================================================

搜索请求处理流程:

1. 接收搜索查询
   query = "高价值客户"
   user = User(id="user-A", roles=["east_region_sales"])

2. 获取用户权限
   permissions = ACL.get_permissions(user)
   → {
       Customer: {
         row_filter: "region = 'east'",
         visible_fields: ["name", "email", "phone", "revenue"]
       },
       Order: {
         row_filter: "salesperson_id = 'user-A'",
         visible_fields: ["*"]
       }
     }

3. 构建受限搜索查询
   search_query = {
     text: "高价值客户",
     type_filters: {
       Customer: {
         must: [{ term: { region: "east" }}],
         source_includes: ["name", "email", "phone", "revenue"]
       }
     }
   }

4. 执行搜索 (Elasticsearch)
   results = es.search(search_query)

5. 二次权限校验 (防止竞态条件)
   filtered_results = [
     r for r in results
     if ACL.check_access(user, r.object_id)
   ]

6. 返回安全的结果
   return filtered_results

#5. 搜索建议与自动补全

#5.1 智能搜索建议

Code
搜索建议系统
================================================

用户输入: "sup"

搜索建议 (实时, <100ms):
┌──────────────────────────────────────────┐
│  🔍 sup                                  │
│  ──────────────────────────────────────── │
│  📦 Supply Chain (对象类型, 12,345 个)     │
│  🏢 Superior Industries (公司, 客户)      │
│  👤 Super Admin (角色)                    │
│  📋 Supply Order #SO-2024-789 (最近访问)   │
│  🔍 "supply chain disruption" (热门搜索)  │
│  ──────────────────────────────────────── │
│  最近搜索:                                │
│  🕐 "supply chain risk assessment"        │
│  🕐 "supplier evaluation"                 │
└──────────────────────────────────────────┘

建议来源:
  1. 对象类型名称匹配 (Ontology Schema)
  2. 具体对象名称匹配 (实时索引)
  3. 用户最近访问的对象 (个性化)
  4. 热门搜索词 (全局统计)
  5. 保存的搜索 (用户自定义)

#5.2 搜索建议的架构

Code
搜索建议架构 (coomia-dip 实现)
================================================

┌──────────────┐
│  用户输入     │ "sup" (每次按键触发)
└──────┬───────┘
       │
       ▼
┌──────────────────────────────────────────┐
│  Suggest Service                          │
│                                          │
│  ┌─────────────────────────────────────┐  │
│  │  1. Schema Suggest (Ontology 类型)  │  │
│  │     Redis SET: "type_names"          │  │
│  │     匹配: PREFIX("sup") → ["Supply  │  │
│  │     Chain", "Supplier", "Superior"]  │  │
│  └─────────────────────────────────────┘  │
│                                          │
│  ┌─────────────────────────────────────┐  │
│  │  2. Object Suggest (具体对象)        │  │
│  │     Elasticsearch: prefix query      │  │
│  │     + 权限过滤                       │  │
│  └─────────────────────────────────────┘  │
│                                          │
│  ┌─────────────────────────────────────┐  │
│  │  3. Recent Suggest (最近搜索)        │  │
│  │     Redis ZSET: "recent:{user_id}"  │  │
│  │     Score = timestamp                │  │
│  └─────────────────────────────────────┘  │
│                                          │
│  ┌─────────────────────────────────────┐  │
│  │  4. Hot Suggest (热门搜索)           │  │
│  │     Redis ZSET: "hot_searches"      │  │
│  │     Score = search_count (24h 滚动)  │  │
│  └─────────────────────────────────────┘  │
│                                          │
│  合并 & 排序 & 去重 → Top 10 建议        │
└──────────────────────────────────────────┘

#6. 模糊搜索与容错

#6.1 搜索模式对比

Code
6 种搜索模式
================================================

1. EXACT(精确匹配)
   查询: "ORD-2024-56789"
   匹配: ORD-2024-56789 ✅
   不匹配: ORD-2024-56788 ❌

2. PREFIX(前缀匹配)
   查询: "ORD-2024"
   匹配: ORD-2024-56789 ✅, ORD-2024-00001 ✅
   不匹配: ORD-2023-99999 ❌

3. FUZZY(模糊匹配, 容忍拼写错误)
   查询: "Shnaghai" (拼写错误)
   匹配: "Shanghai" ✅ (编辑距离 = 2)

   算法: Levenshtein 距离
   允许: 插入、删除、替换、调换

4. BEST_MATCH(最佳匹配, 综合评分)
   查询: "supply chain risk"
   结果按相关性排序:
   1. "Supply Chain Risk Assessment" (所有词匹配) 评分: 9.8
   2. "Supply Chain Management" (部分匹配)        评分: 7.2
   3. "Risk Management Framework" (部分匹配)       评分: 5.1

5. WILDCARD(通配符匹配)
   查询: "ORD-*-VIP"
   匹配: ORD-2024-VIP ✅, ORD-2023-VIP ✅
   不匹配: ORD-2024-NORMAL ❌

6. REGEX(正则表达式匹配)
   查询: "ORD-202[34]-\d{5}"
   匹配: ORD-2023-12345 ✅, ORD-2024-67890 ✅
   不匹配: ORD-2022-12345 ❌

#6.2 相关性评分

Code
搜索相关性评分模型
================================================

最终得分 = w1 * 文本相关性
         + w2 * 属性匹配度
         + w3 * 时效性
         + w4 * 热度
         + w5 * 个人相关性

文本相关性 (TF-IDF / BM25):
  - 搜索词在对象中出现的频率
  - 搜索词在所有对象中的稀有度
  - 字段权重 (名称 > 描述 > 备注)

属性匹配度:
  - 精确匹配属性值 → 高分
  - 部分匹配 → 中分
  - 仅文本匹配 → 低分

时效性:
  - 最近更新的对象 → 加分
  - 超过 90 天未更新 → 减分

热度:
  - 近期被频繁访问 → 加分
  - 被多人收藏 → 加分

个人相关性:
  - 用户最近访问过 → 加分
  - 属于用户负责的项目 → 加分
  - 与用户角色相关 → 加分

#7. 与主流搜索工具对比

维度Foundry SearchElasticsearchAlgoliaApache Solr
搜索对象Ontology 对象文档文档/记录文档
Ontology 感知原生
权限集成深度集成需要自建有限需要自建
分面搜索Ontology 驱动手动配置自动手动配置
搜索建议内置 + 个性化需要自建内置需要自建
模糊搜索支持支持支持支持
关系搜索原生 (图遍历)不支持不支持不支持
地理搜索支持支持支持支持
实时索引近实时实时近实时
托管方式SaaS/私有自建/云SaaS自建
开源
学习曲线中 (平台内)

#核心差异

Code
搜索工具定位差异
================================================

Elasticsearch:
  定位: 通用分布式搜索引擎
  强项: 灵活, 可扩展, 大规模
  弱项: 不理解业务语义, 需要大量开发
  适用: 需要高度定制化搜索的场景

Algolia:
  定位: 即时搜索 SaaS
  强项: 极快的响应时间 (<50ms), 简单集成
  弱项: 不支持复杂查询, 成本高
  适用: 电商、内容网站搜索

Foundry Search:
  定位: Ontology 感知的企业搜索
  强项: 理解业务对象、关系、权限
  弱项: 锁定在 Foundry 平台内
  适用: 需要跨源、权限感知的企业搜索

coomia-dip Search:
  定位: 开源 Ontology 感知搜索
  强项: 基于 ES, 集成 Ontology 语义
  弱项: 成熟度较低
  适用: 需要开源方案的企业

#8. coomia-dip 的搜索实现

#8.1 SearchService 架构

Code
coomia-dip SearchService
================================================

┌────────────────────────────────────────────────┐
│  SearchService (gRPC)                          │
│                                                │
│  核心搜索 RPC:                                  │
│  ┌──────────────────────────────────────────┐   │
│  │  1. Search(SearchRequest)                │   │
│  │     → 支持 6 种搜索模式                   │   │
│  │     → 支持分面搜索                        │   │
│  │     → 支持分页和排序                      │   │
│  │                                          │   │
│  │  2. Suggest(SuggestRequest)              │   │
│  │     → 自动补全建议                        │   │
│  │     → 热门搜索                            │   │
│  │     → 最近搜索                            │   │
│  │                                          │   │
│  │  3. FacetSearch(FacetRequest)            │   │
│  │     → TERMS 分面                          │   │
│  │     → RANGE 分面                          │   │
│  │     → DATE_RANGE 分面                     │   │
│  └──────────────────────────────────────────┘   │
│                                                │
│  底层引擎:                                      │
│  ┌────────────┐  ┌──────────┐  ┌────────────┐  │
│  │Elasticsearch│  │  Redis   │  │ Ontology   │  │
│  │(全文索引)   │  │(建议缓存)│  │(类型感知)   │  │
│  └────────────┘  └──────────┘  └────────────┘  │
└────────────────────────────────────────────────┘

#8.2 搜索请求模型

PROTOBUF
// coomia-dip Search Protobuf (简化版)

syntax = "proto3";
package onto.search.v1;

message SearchRequest {
    string query = 1;                    // 搜索词
    SearchMode mode = 2;                 // 搜索模式
    repeated string object_types = 3;    // 限定对象类型
    repeated FacetSpec facets = 4;       // 分面定义
    Pagination pagination = 5;          // 分页
    repeated SortSpec sort = 6;         // 排序
    map<string, string> filters = 7;    // 过滤条件
}

enum SearchMode {
    BEST_MATCH = 0;    // 综合最佳匹配
    PREFIX = 1;        // 前缀匹配
    FUZZY = 2;         // 模糊匹配
    EXACT = 3;         // 精确匹配
    WILDCARD = 4;      // 通配符
    REGEX = 5;         // 正则表达式
}

message FacetSpec {
    string field = 1;          // 分面字段
    FacetType type = 2;        // 分面类型
    int32 size = 3;            // 返回数量
    RangeSpec range = 4;       // RANGE 类型的配置
}

enum FacetType {
    TERMS = 0;          // 词项分面 (枚举值计数)
    RANGE = 1;          // 数值范围分面
    DATE_RANGE = 2;     // 日期范围分面
}

message SearchResponse {
    repeated SearchHit hits = 1;
    int64 total_count = 2;
    repeated FacetResult facets = 3;
    float max_score = 4;
    int32 took_ms = 5;
}

message SearchHit {
    string object_id = 1;
    string object_type = 2;
    float score = 3;
    map<string, string> highlight = 4;  // 高亮片段
    map<string, google.protobuf.Value> fields = 5;
}

message SuggestRequest {
    string prefix = 1;          // 用户输入前缀
    string user_id = 2;         // 用户 ID (个性化)
    int32 max_results = 3;      // 最大建议数
}

message SuggestResponse {
    repeated Suggestion suggestions = 1;
}

message Suggestion {
    string text = 1;
    SuggestionType type = 2;
    string description = 3;
    float score = 4;
}

enum SuggestionType {
    OBJECT_TYPE = 0;    // 对象类型建议
    OBJECT = 1;         // 具体对象建议
    RECENT = 2;         // 最近搜索
    HOT = 3;            // 热门搜索
    SAVED = 4;          // 保存的搜索
}

#8.3 Redis 搜索建议实现

Python
# coomia-dip 搜索建议实现

import redis.asyncio as redis
import time
from typing import List

class SearchSuggestService:
    """基于 Redis 的搜索建议服务"""

    def __init__(self, redis_client: redis.Redis):
        self.redis = redis_client
        self.HOT_KEY = "search:hot"
        self.RECENT_PREFIX = "search:recent:"
        self.HOT_WINDOW = 86400  # 24 小时滚动窗口

    async def record_search(self, user_id: str, query: str):
        """记录搜索行为,更新热门和最近搜索"""
        now = time.time()

        # 更新用户最近搜索 (ZSET, score=timestamp)
        recent_key = f"{self.RECENT_PREFIX}{user_id}"
        await self.redis.zadd(recent_key, {query: now})
        await self.redis.zremrangebyrank(recent_key, 0, -51)  # 保留最近 50 条

        # 更新全局热门搜索 (ZSET, score=count)
        await self.redis.zincrby(self.HOT_KEY, 1, query)

        # 清理过期热门搜索 (每小时清理一次旧数据)
        cutoff = now - self.HOT_WINDOW
        await self.redis.zremrangebyscore(
            self.HOT_KEY, "-inf", cutoff
        )

    async def get_suggestions(
        self,
        prefix: str,
        user_id: str,
        max_results: int = 10
    ) -> List[dict]:
        """获取搜索建议"""
        suggestions = []

        # 1. 最近搜索 (个性化)
        recent_key = f"{self.RECENT_PREFIX}{user_id}"
        recent = await self.redis.zrevrange(
            recent_key, 0, 4, withscores=True
        )
        for query, score in recent:
            query_str = query.decode() if isinstance(query, bytes) else query
            if query_str.lower().startswith(prefix.lower()):
                suggestions.append({
                    "text": query_str,
                    "type": "RECENT",
                    "score": 0.8
                })

        # 2. 热门搜索 (全局)
        hot = await self.redis.zrevrange(
            self.HOT_KEY, 0, 19, withscores=True
        )
        for query, count in hot:
            query_str = query.decode() if isinstance(query, bytes) else query
            if query_str.lower().startswith(prefix.lower()):
                suggestions.append({
                    "text": query_str,
                    "type": "HOT",
                    "score": min(float(count) / 100, 1.0)
                })

        # 3. 去重和排序
        seen = set()
        unique = []
        for s in sorted(suggestions, key=lambda x: -x["score"]):
            if s["text"] not in seen:
                seen.add(s["text"])
                unique.append(s)

        return unique[:max_results]

#9. 搜索性能优化

#9.1 索引策略

Code
搜索索引优化策略
================================================

策略 1: 多级索引
┌────────────────────────────────────────────┐
│  Level 1: 内存缓存 (Redis)                 │
│  - 热门搜索结果缓存                         │
│  - TTL: 5 分钟                              │
│  - 命中率: ~60%                             │
│  - 响应时间: <5ms                           │
├────────────────────────────────────────────┤
│  Level 2: Elasticsearch                    │
│  - 全文索引 + 结构化索引                     │
│  - 近实时更新 (refresh_interval: 1s)        │
│  - 响应时间: 10-100ms                       │
├────────────────────────────────────────────┤
│  Level 3: 数据库 (PostgreSQL)              │
│  - 精确查询回退                             │
│  - 复杂关联查询                             │
│  - 响应时间: 50-500ms                       │
└────────────────────────────────────────────┘

策略 2: 索引设计
┌────────────────────────────────────────────┐
│  每个 Ontology 类型一个 ES 索引:            │
│                                            │
│  onto_customer:                            │
│    mappings:                               │
│      name: text (analyzed) + keyword (raw) │
│      email: keyword                        │
│      revenue: long                         │
│      region: keyword                       │
│      created_at: date                      │
│      _all_text: text (所有文本字段合并)      │
│                                            │
│  onto_order:                               │
│    mappings:                               │
│      order_id: keyword                     │
│      amount: double                        │
│      status: keyword                       │
│      description: text                     │
│      customer_id: keyword (关联查询用)      │
└────────────────────────────────────────────┘

策略 3: 查询优化
┌────────────────────────────────────────────┐
│  - 使用 filter context (可缓存) 处理精确过滤 │
│  - 使用 query context 处理相关性评分         │
│  - 权限过滤放在 filter 中 (不影响评分)       │
│  - 分面聚合使用 global 聚合避免重复计算       │
│  - 大结果集使用 search_after 代替 from+size  │
└────────────────────────────────────────────┘

#10. 保存的搜索与搜索订阅

#10.1 保存搜索

Code
保存的搜索 (Saved Searches)
================================================

用户经常执行相同的复杂搜索, 可以保存下来:

保存的搜索: "我的高优先级待处理订单"
┌────────────────────────────────────────────┐
│  定义:                                      │
│  {                                         │
│    "query": "",                             │
│    "object_type": "Order",                 │
│    "filters": {                            │
│      "status": "pending",                  │
│      "priority": "high",                   │
│      "assigned_to": "${current_user}"      │
│    },                                      │
│    "sort": [{"field": "due_date",          │
│              "order": "asc"}]              │
│  }                                         │
│                                            │
│  特性:                                      │
│  - 动态变量 (${current_user})               │
│  - 可以分享给团队                            │
│  - 可以固定到仪表盘                          │
│  - 可以设置通知 (结果变化时提醒)              │
└────────────────────────────────────────────┘

#Key Takeaways

  1. Foundry 的搜索革命性地将"搜表"变成了"搜对象" -- 通过 Ontology 感知,搜索引擎理解业务对象的类型、属性和关系,返回的不是数据库行,而是有结构、有上下文的业务对象,配合权限过滤确保数据安全。

  2. 权限感知搜索不是"事后过滤"而是"内建安全" -- 从搜索查询构建阶段就注入权限约束,确保用户永远只能发现自己有权访问的数据,这对政府和金融行业的合规要求至关重要。

  3. coomia-dip 通过 6 种搜索模式 + 3 种分面类型 + Redis 热词/近期搜索构建了完整的 Ontology 感知搜索体验 -- 底层基于 Elasticsearch 保证搜索性能,上层通过 Ontology 类型系统提供语义理解,Redis 提供实时的个性化搜索建议。

#下一篇预告

第 16 篇:Palantir 的定价与商业模式 -- 为什么客户愿意付 1 亿美金/年

Palantir 单客户年费可达上亿美元,净留存率超过 118%。我们将深入分析其定价策略、商业模式、以及为什么一旦用上 Palantir 就很难停下来。

Tags: palantir search discovery ontology elasticsearch faceted-search fuzzy-search coomia-dip redis permissions