# 从 Algolia 迁移到 Typesense
如果您当前正在使用 Algolia 并计划迁移到 Typesense,本指南旨在为您提供一些有用的提示,帮助您顺利完成过渡。 这些内容是基于我们观察到的 Algolia 用户在切换到 Typesense 时常见的情况整理而成。
# 时间线
我们从考虑切换到 Typesense 的 Algolia 用户那里最常被问到的问题是:迁移通常需要多长时间。
中位迁移时间线约为 2-3 周。
目前最快的记录是 3 小时就完成了从 Algolia 到 Typesense 的生产环境切换(当然这是极少数情况)。 另一方面,也有少数用户花费了 1-1.5 个月的时间,因为他们希望先通过功能标志将 Typesense 部署到一小部分流量,然后在数周内逐步将流量转移到 Typesense,同时密切监控指标并进行微调。
如果您使用的是 Algolia 的 InstantSearch (opens new window) UI 组件,那么迁移时间往往处于较短的一端, 因为我们提供了一个适配器库,安装到前端应用后可以自动将查询转换为 Typesense 格式。这样您就可以保持现有的 UI 组件不变,最快在 30 分钟到 1 小时内完成迁移。
因此,主要的工作是将您的 JSON 文档推送到 Typesense 而不是 Algolia,并考虑下面提到的差异点。 您还需要考虑同义词和查询规则的迁移,Algolia 和 Typesense 都提供了导出和导入这些数据的 API。
# 架构
Algolia 和 Typesense 在架构上非常相似——两者都是内存搜索引擎,针对闪电般快速的搜索进行了优化。
# API 兼容性
虽然 Typesense 是 Algolia 的开源替代方案,能够提供同样即时的输入即搜索体验,但它在一些关键方面对 Algolia 进行了改进。因此,尽管您可能会发现 Typesense 和 Algolia 有许多相似的概念,但我们基于第一性原则设计了 Typesense 的功能集,所以这些 API 在设计中并不相互兼容。
# 类型检查
Typesense 鼓励您为文档定义模式(schema),然后对索引的文档进行类型检查,以确保索引的数据保持一致,避免意外情况或细微错误。这与 C++、Go、Rust、Java、Kotlin、Swift、Typescript 等强类型编程语言中的类型检查优势非常相似。
在 Algolia 中,您可以发送任何 JSON 数据进行索引,数据类型会按原样保留,即使文档之间存在不一致。因此,您可能会有一个文档的 "timestamp" 字段是字符串类型,而另一个文档的 "timestamp" 字段是整数类型。这在使用不同类型的过滤器时可能会导致一些问题。
虽然 Typesense 不允许同一字段在不同文档中存在不同的数据类型,但您可以配置 Typesense 根据索引的文档自动检测模式(参见 自动模式检测)。您还可以在导入文档时使用 coerce_or_reject
参数,配置 Typesense 根据检测到的模式自动尝试转换数据类型。
# 同步写入 API
在 Algolia 中,所有写入 API 调用都会在内部排队并异步应用到索引中。您需要通过轮询写入状态来了解每个写入操作的状态。根据数据集的大小,您可能会在发起写入 API 调用和搜索时显示在索引之间存在延迟。
在 Typesense 中,所有写入 API 调用都是同步的。无需轮询即可了解写入状态。如果 API 调用成功,意味着数据已写入集群中的大多数节点并可用于搜索。这也意味着包含大批量数据的这些同步写入 API 调用将需要更长时间来完成数据摄入。
根据并发索引的数据量,如果超过配置的阈值,Typesense 可能会返回 HTTP 503 Lagging or Not Ready
消息,以确保在高容量写入期间搜索操作不受影响。此时,您需要在稍后的时间点暂停后重试写入 API 调用。
# 功能对等性
Typesense 目前与 Algolia 的功能对等性约为 85%(参见功能对比矩阵 (opens new window))。我们计划根据从 Algolia 切换到 Typesense 的用户反馈来缩小这一差距。
# Algolia 有而 Typesense 没有的关键功能
- 服务端 AB 测试(可以通过使用 AB 测试框架客户端实现,并根据用户的分桶标识使用不同的集合)
- 开箱即用的 AI/ML 功能
# Typesense 相比 Algolia 的独特功能
- 单一索引支持多重(严格)排序(在 Algolia 中,每个严格排序条件如价格升序、价格降序等都需要创建重复索引)
- 字段数据类型验证(类似强类型语言),在文档索引时防止不一致数据进入索引(如需 Algolia 类似行为可关闭此功能)
- 搜索时可指定字段数值权重,给予特定字段更高优先级
- 支持存储和查询同一记录中的多个地理坐标字段(纬度/经度),并在单次查询过滤时使用逻辑运算符组合它们
- 支持存储自有机器学习模型的向量,并进行最近邻搜索
- 支持使用嵌入模型(如 OpenAI、PaLM API 或内置模型 S-BERT、E-5 等),实现混合搜索(语义+关键词)并与大语言模型(LLMs)集成
- 支持以对话式响应返回结果(内置 RAG 功能),基于您的 JSON 数据生成自然语言回答
- 支持为集合创建别名(类似符号链接)
- 动态搜索参数配置:Algolia 中需要在索引级别配置的多数参数,在 Typesense 中可在搜索时动态配置,提供更高灵活性
- 无限制设计:记录大小、最大索引尺寸、同义词数量、规则数量或索引数量均无硬性限制
- 支持自托管部署
- 可运行于持续集成环境(得益于自托管特性)
- 完全开源
# 等效功能与概念对照
以下是 Algolia 和 Typesense 中常见功能及概念的术语对照表。
# 术语对照
Algolia | Typesense |
---|---|
每个被索引的 JSON 对象称为记录(record) | 每个被索引的 JSON 对象称为文档(Document) |
记录的集合称为索引(Index) | 记录/文档的集合称为集合(Collection) |
分布式搜索网络(Distributed Search Network) | 搜索交付网络(Search Delivery Network)(在 Typesense Cloud 中) |
神经搜索(NeuralSearch) | 混合搜索(Hybrid Search),本质上是语义搜索+带自动嵌入生成的关键词向量搜索 |
# 功能对比
Algolia | Typesense |
---|---|
认证通过 Application ID 和 API Key 实现 | 认证通过 x-typesense-api-key 实现 |
安全或虚拟 API 密钥 | 范围限定的 API 密钥 |
导入记录(无验证和模式) | 创建带有 自动模式检测 的集合,并使用 coerce_or_reject 导入文档 |
查询规则 | 覆盖规则(也称为策展功能,Typesense Cloud 还提供了拖拽管理界面用于覆盖规则) |
查询建议 (opens new window) | 在 Typesense 中也称为 查询建议,可通过 分析规则 创建 |
商品推广 | 通过覆盖规则 提升或排除结果,或在搜索时使用 pinned_hits 或 hidden_hits 搜索参数 |
动态过滤 | 通过覆盖规则实现动态过滤 |
用于排序的虚拟索引副本 | 在 Typesense 中,单个集合可以通过 sort_by 处理多种排序方式,因此不需要虚拟索引副本 |
多索引搜索(联合搜索或 multipleQueries ) | multi_search |
Algolia 中的排名和相关性 (opens new window) | Typesense 中的排名和相关性。 Typesense 的一个关键区别是我们简化了相关性调优体验,大多数用例开箱即用,并尽量减少了需要调整的参数数量。 |
记录过滤 (opens new window) | [filter_by 搜索参数可过滤文档 |
记录分面 (opens new window) | facet_by 搜索参数可对文档进行分面 |
记录分组 (opens new window) | group_by 搜索参数可对文档进行分组 |
地理搜索(使用 aroundRadius , aroundLatLng ) | Typesense 的地理搜索 |
地理搜索(使用 insidePolygon ) | 多边形内的地理搜索 |
地理搜索(使用 insideBoundingBox ) | 如果边界框的对角端点坐标为 [A,X] 和 [B,Y] ,您可以通过交换经纬度获取边界框的另外两个坐标:[A,Y] 和 [B,X] 。有了这 4 个坐标,就可以使用 Typesense 的 多边形地理搜索功能 在边界框内进行搜索。 |
使用 aroundPrecision 控制地理搜索精度 | geo_precision 和 exclude_radius |
# 配置对比
Algolia | Typesense |
---|---|
searchableAttributes | 所有需要建立索引的字段/属性在创建集合时配置,然后可以在搜索时通过query_by 参数动态选择使用字段子集。 |
attributesForFaceting 用于分面和过滤 | 通过在集合模式中为字段设置facet: true 来启用分面功能,搜索时可通过facet_by 调整在Typesense中,过滤字段不需要设置为分面字段。 |
unretrievableAttributes | 可通过创建范围API密钥并在其中嵌入exclude_fields 搜索参数来配置 |
attributesToRetrieve | 可通过创建范围API密钥并在其中嵌入include_fields 搜索参数来配置 |
attributeForDistinct 和 distinct | 可通过group_by 和group_limit 搜索参数配置 |
separatorsToIndex | 创建集合时的symbols_to_index 设置 |
removeWordsIfNoResults | drop_tokens_threshold 搜索参数 |
disablePrefixOnAttributes | prefix=false,false,true 搜索参数,对应query_by 中的字段 |
disableTypoToleranceOnAttributes | num_typos=false,false,true 搜索参数,对应query_by 中的字段 |
customRanking (opens new window) | 可在sort_by 参数中指定最多3个排序字段。例如: sort_by=_text_match(buckets: 10):desc,custom_field_1:desc,custom_field_2:desc 从v0.23.0开始,这会将结果集分为10个桶(从最相关到最不相关),强制每个桶内的结果并列,然后使用自定义排序字段在每个桶内进行排序。 |
# API 接口对比
Algolia | Typesense |
---|---|
使用 saveObjects 导入/索引文档 | 使用 /collections/<collection_name>/documents/import 端点配合 action=upsert 参数导入文档 |
使用 partialUpdateObjects 并设置 createIfNotExists: true | 使用 /collections/<collection_name>/documents/import 端点配合 action=emplace 参数导入文档 (从 v0.23.0 版本开始支持) |
使用 browseObjects (opens new window) 导出记录 | 使用 /collections/collection_name/documents/export 端点导出文档 |
searchForFacetValues (opens new window) | facet_query 搜索参数 |
# 迁移前端 UI 组件
Algolia 构建并开源了一套针对 Vanilla JS、React、Vue 和 Angular 的搜索 UI 库,名为 InstantSearch (opens new window)。
Typesense 通过 typesense-instantsearch-adapter (opens new window) 支持相同的 InstantSearch 组件。您只需通过 npm
或 yarn
将适配器安装到应用程序中并进行配置 (opens new window),现有的 UI 组件就能与您的 Typesense 集群配合工作,大多数情况下无需额外修改。
少数组件需要微小调整 (opens new window)才能与 Typesense 一起使用。
# 将数据从 Algolia 迁移至 Typesense
通常您会希望更新当前向 Algolia 发送 JSON 数据的应用后端,使其将相同数据发送至 Typesense。这样您就能直接从主数据存储向 Typesense 发送数据。
但如果您想快速一次性将 Algolia 中的数据导出至 Typesense 进行探索或数据回填,可按以下步骤操作:
# 步骤 1:从 Algolia 导出数据
安装 Algolia CLI (opens new window) 后运行:
algolia objects browse YOUR_INDEX_NAME > documents-raw.jsonl
此命令会将 Algolia 记录导出为 JSONL 文件。
# 步骤 2:转换数据
# ID 字段
Algolia 使用名为 objectId
的字段来唯一标识记录,而 Typesense 使用名为 id
的字段实现相同目的。
我们可以使用 jq
(opens new window) 工具将下载的 JSONL 文件中 objectId
字段的值复制到新字段 id
中:
jq -c '(to_entries[] | select(.key | ascii_downcase == "objectid")).key as $key | .["id"] = .[$key]' documents-raw.jsonl > documents-with-ids.jsonl
# 时间戳(可选)
如需按日期/时间戳排序,需要将 ISO8601 格式的日期/时间戳转换为 Unix 时间戳(纪元时间)。
以下是转换命令:
jq -c 'if .your_iso_timestamp_field then .your_iso_timestamp_field |= (sub("\\.[0-9]+"; "") | strptime("%Y-%m-%dT%H:%M:%SZ") | mktime) else . end' documents-with-ids.jsonl > documents.jsonl
# 步骤 3:创建集合
按照此处的说明在 Typesense 中创建集合。
对于 Algolia 中配置为可分面(facetable)的字段,需要在 Typesense 中设置 facet: true
。
这里 (opens new window)有一个实用工具,可以帮助您从数据集的 JSON 示例对象生成 Typesense 集合模式的初稿:
npx typesense-collection-schema-generator@latest <path_to_input_json_document_file> <path_to_output_typesense_collection_schema_json_file>
# 步骤 4:导入文档
现在你可以使用以下代码片段,将转换好的 JSONL 文件导入到你的Typesense 集合中:
export TYPESENSE_API_KEY=xyz
export TYPESENSE_HOST=xxx.a1.typesense.net
export TYPESENSE_PROTOCOL=https
export TYPESENSE_COLLECTION_NAME=YOUR_INDEX_NAME
# 我们使用 `parallel` 命令并行化导入(请确保已安装该命令):
parallel --block -5 -a documents.jsonl --tmpdir /tmp --pipepart --cat 'curl -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -X POST -T {} "${TYPESENSE_PROTOCOL}://${TYPESENSE_HOST}/collections/${TYPESENSE_COLLECTION_NAME}/documents/import?action=upsert"'
提示
- 增大命令中的
-5
数值可以减小每批次导入 Typesense 的数据块大小 - 如果遇到 "Bad Request" 或 "Connection Refused" 错误,可能需要根据你的 shell 环境调整命令中的转义符和引号
- 如果出现 404 错误,请确保在运行导入命令前已创建 Typesense 集合
# 步骤5:导入查询规则
如果您使用 Algolia 的 Query Rules(查询规则)功能来根据条件定制搜索结果,可以使用我们提供的这个工具来导入这些规则:
npx algolia-query-rules-to-typesense@latest <path/to/algolia_rules_export.json> <path/to/typesense_overrides_output.json>
要获取 Algolia 规则导出文件,请转到 Algolia 索引的 "Rules" 部分,您会找到一个下载图标将规则导出为 JSON 文件。
然后您可以使用 Typesense Overrides API 将这些转换后的 JSON 规则(typesense_overrides_output.json
)导入到 Typesense 中。
# 地理分布式集群
Algolia 将其类似 CDN 的地理分布式搜索服务称为 Distributed Search Network (opens new window),并且仅作为付费附加功能提供给按年付费的客户。
在 Typesense Cloud 中,类似 CDN 的地理分布式搜索服务称为 Search Delivery Network(搜索分发网络),所有用户在创建新集群时都可以选择此配置。
# 定价模型
Algolia 按照记录数量和搜索次数(如果实现了即时搜索则为按键次数)收费,您需要为这两个维度中较大的数值付费,如果超出计划限制还需支付超额费用。 因此,如果您有高流量但记录数量少,或者低流量但记录数量多,您都需要为两者中较大的数值付费。
Typesense 是免费开源的,可以免费自托管。
Typesense 还提供名为 Typesense Cloud (opens new window) 的托管搜索服务。 Typesense Cloud 的定价基于您索引数据所需的 RAM 和 CPU 资源量,以及支撑预期并发流量所需的计算资源。 根据您选择的配置,采用固定的小时费率计费,外加标准带宽费用,类似于 AWS、GCP 等云服务商。 与 Algolia 不同,我们不收取每条记录或每次搜索的费用。只要您的集群能够承载,您可以随意增加流量或数据量。 根据我们的观察,从 Algolia 迁移到 Typesense Cloud 的用户可以节省 50% 到 95% 的搜索成本。
# Algolia 迁移支持
如果您计划从 Algolia 迁移到 Typesense Cloud,我们提供免费的 迁移咨询支持 (opens new window),根据您在 Algolia 的使用情况提供不同级别的服务。