Palantir 的搜索与发现:在百万对象中找到你要的那个
我们每天都在使用 Google、百度搜索互联网内容,体验流畅自然。但当你在企业内部搜索数据时,体验往往是灾难性的。
“系列: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、百度搜索互联网内容,体验流畅自然。但当你在企业内部搜索数据时,体验往往是灾难性的。
消费者搜索 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 企业搜索的三大难题
企业搜索三大难题
================================================
难题 1: 数据分散
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ CRM │ │ ERP │ │ HRM │ │ 邮件 │ │ 文件 │
└──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
同一个"客户"在 5 个系统中有 5 种不同的表示
ID 不同, 字段不同, 更新时间不同
难题 2: 权限复杂
┌──────────────────────────────────────────┐
│ 用户 A (销售): 能看客户联系方式 │
│ 用户 B (财务): 能看客户账务信息 │
│ 用户 C (合规): 能看客户风险评分 │
│ 用户 D (实习): 只能看客户名称 │
│ │
│ 同一个搜索请求, 4 个人看到不同的结果 │
└──────────────────────────────────────────┘
难题 3: 语义理解
┌──────────────────────────────────────────┐
│ 搜索 "大客户": │
│ - 指的是订单金额大的客户? │
│ - 指的是公司规模大的客户? │
│ - 指的是"大客户部"名下的客户? │
│ - 指的是客户等级为"大客户"的? │
│ │
│ 没有 Ontology = 无法消除歧义 │
│ 有 Ontology = 精确理解语义 │
└──────────────────────────────────────────┘
#2. Foundry 的 Ontology 感知搜索
#2.1 搜索的是对象,不是表
这是 Foundry 搜索与传统数据库搜索的根本区别:
传统搜索 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 搜索架构
Foundry 搜索系统架构
================================================
用户搜索请求
│
▼
┌─────────────────────────────────────────────┐
│ Search Gateway │
│ │
│ 1. 解析查询 (NLP / 结构化解析) │
│ 2. 权限校验 (ACL 过滤) │
│ 3. 查询路由 │
└────────┬──────────────────────┬──────────────┘
│ │
┌────▼──────┐ ┌────▼──────┐
│ Full-Text │ │ Structured│
│ Search │ │ Search │
│ Engine │ │ Engine │
│ │ │ │
│(Elasticsearch) │(Ontology │
│ │ │ Index) │
└────┬──────┘ └────┬──────┘
│ │
└──────────┬───────────┘
│
┌─────▼──────┐
│ Result │
│ Merger & │
│ Ranker │
│ │
│ 合并结果 │
│ 相关性排序 │
│ 权限过滤 │
│ 分面聚合 │
└─────┬──────┘
│
▼
搜索结果 (对象列表)
#2.3 多维度搜索
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. 分面搜索(Faceted Search)
#3.1 什么是分面搜索
分面搜索示意
================================================
搜索: "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 的类型系统:
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 搜索最重要的安全特性:
权限感知搜索
================================================
数据库中实际存在的对象:
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 实现机制
权限感知搜索实现
================================================
搜索请求处理流程:
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 智能搜索建议
搜索建议系统
================================================
用户输入: "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 搜索建议的架构
搜索建议架构 (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 搜索模式对比
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 相关性评分
搜索相关性评分模型
================================================
最终得分 = w1 * 文本相关性
+ w2 * 属性匹配度
+ w3 * 时效性
+ w4 * 热度
+ w5 * 个人相关性
文本相关性 (TF-IDF / BM25):
- 搜索词在对象中出现的频率
- 搜索词在所有对象中的稀有度
- 字段权重 (名称 > 描述 > 备注)
属性匹配度:
- 精确匹配属性值 → 高分
- 部分匹配 → 中分
- 仅文本匹配 → 低分
时效性:
- 最近更新的对象 → 加分
- 超过 90 天未更新 → 减分
热度:
- 近期被频繁访问 → 加分
- 被多人收藏 → 加分
个人相关性:
- 用户最近访问过 → 加分
- 属于用户负责的项目 → 加分
- 与用户角色相关 → 加分
#7. 与主流搜索工具对比
| 维度 | Foundry Search | Elasticsearch | Algolia | Apache Solr |
|---|---|---|---|---|
| 搜索对象 | Ontology 对象 | 文档 | 文档/记录 | 文档 |
| Ontology 感知 | 原生 | 无 | 无 | 无 |
| 权限集成 | 深度集成 | 需要自建 | 有限 | 需要自建 |
| 分面搜索 | Ontology 驱动 | 手动配置 | 自动 | 手动配置 |
| 搜索建议 | 内置 + 个性化 | 需要自建 | 内置 | 需要自建 |
| 模糊搜索 | 支持 | 支持 | 支持 | 支持 |
| 关系搜索 | 原生 (图遍历) | 不支持 | 不支持 | 不支持 |
| 地理搜索 | 支持 | 支持 | 支持 | 支持 |
| 实时索引 | 是 | 近实时 | 实时 | 近实时 |
| 托管方式 | SaaS/私有 | 自建/云 | SaaS | 自建 |
| 开源 | 否 | 是 | 否 | 是 |
| 学习曲线 | 中 (平台内) | 高 | 低 | 高 |
#核心差异
搜索工具定位差异
================================================
Elasticsearch:
定位: 通用分布式搜索引擎
强项: 灵活, 可扩展, 大规模
弱项: 不理解业务语义, 需要大量开发
适用: 需要高度定制化搜索的场景
Algolia:
定位: 即时搜索 SaaS
强项: 极快的响应时间 (<50ms), 简单集成
弱项: 不支持复杂查询, 成本高
适用: 电商、内容网站搜索
Foundry Search:
定位: Ontology 感知的企业搜索
强项: 理解业务对象、关系、权限
弱项: 锁定在 Foundry 平台内
适用: 需要跨源、权限感知的企业搜索
coomia-dip Search:
定位: 开源 Ontology 感知搜索
强项: 基于 ES, 集成 Ontology 语义
弱项: 成熟度较低
适用: 需要开源方案的企业
#8. coomia-dip 的搜索实现
#8.1 SearchService 架构
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 搜索请求模型
// 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 搜索建议实现
# 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 索引策略
搜索索引优化策略
================================================
策略 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 保存搜索
保存的搜索 (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
-
Foundry 的搜索革命性地将"搜表"变成了"搜对象" -- 通过 Ontology 感知,搜索引擎理解业务对象的类型、属性和关系,返回的不是数据库行,而是有结构、有上下文的业务对象,配合权限过滤确保数据安全。
-
权限感知搜索不是"事后过滤"而是"内建安全" -- 从搜索查询构建阶段就注入权限约束,确保用户永远只能发现自己有权访问的数据,这对政府和金融行业的合规要求至关重要。
-
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