33个稳定版本

1.4.9 2024年6月16日
1.4.8 2023年12月14日
1.4.3 2023年9月4日
1.4.0 2023年1月28日
0.0.1 2019年2月26日

#4数据库实现

Download history 212/week @ 2024-06-15 26/week @ 2024-06-22 6/week @ 2024-06-29 8/week @ 2024-07-06 3/week @ 2024-07-13 211/week @ 2024-07-27

每月211次下载

MPL-2.0 许可证

695KB
29K SLoC

Sonic

Test and Build Build and Release dependency status Buy Me A Coffee

Sonic是一款快速、轻量级且无模式的搜索后端。它能够快速处理搜索文本和标识符元组,并在微秒级时间内进行查询。

Sonic可以用作某些用例中替代Elasticsearch等重量级且功能齐全的搜索后端的简单选择。它能够规范化自然语言搜索查询,自动完成搜索查询,并提供与查询最相关的结果。Sonic是一个标识符索引,而不是文档索引;当被查询时,它返回ID,然后可以使用这些ID在外部数据库中引用匹配的文档。

在设计Sonic时,我们非常注重性能和代码整洁性。它旨在无故障运行、超快速且对服务器资源的影响最小(我们的测量数据显示,在负载下,Sonic对搜索查询的响应时间在微秒范围内,消耗约30MB RAM,并具有很小的CPU占用;查看我们的基准测试)。

在Rust版本:rustc 1.74.1 (a28077b28 2023-12-04)

🇫🇷 在法国南特制作。

📰 Sonic项目最初在 我的个人日记上的一篇文章中宣布

Sonic

「Sonic」是Sonic项目的吉祥物。我画得它看起来像一只迷幻的嘻哈刺猬。

谁在使用它?

清晰 Scrumpy

👋 您使用Sonic并希望被列入其中? 联系我

演示

Sonic集成在Crisp平台上的所有Crisp搜索产品中。它被用于在每月5美元的1-vCPU SSD云服务器上索引5亿个对象(截至2019年)。Crisp用户使用它来搜索他们的消息、对话、联系人、帮助台文章等。

您可以在以下位置实时测试Sonic: Crisp帮助台,并了解Sonic搜索结果的速度和相关性。您还可以从这里测试搜索建议:键入至少2个字符的单词,获取完整的单词建议(按Tab键展开建议)。 搜索和建议都由Sonic提供支持。

Demo on Crisp Helpdesk search

Sonic在帮助台文章中的模糊搜索表现最佳。查找任何单词或术语组,立即获得结果。

功能

  • 搜索术语存储在集合中,组织在桶中;您可以使用单个桶,或者如果您需要在单独的索引中进行搜索,则为您的平台上的每个用户使用一个桶。
  • 搜索结果返回对象标识符,如果需要丰富搜索结果,可以从外部数据库解析这些标识符。这使得Sonic成为一个简单的单词索引,指向标识符结果。Sonic在其索引中不存储任何直接文本数据,但它仍然保留一个单词图,用于自动完成和拼写纠正。
  • 如果搜索查询中的给定单词没有足够的精确匹配结果,Sonic会尝试纠正单词并尝试替换词。您在搜索时可以犯错误。
  • 在索引中插入和删除项目;索引更改操作很轻,可以在服务器运行时提交到服务器。后台任务处理程序负责合并索引,以便您推入或弹出的条目可以快速用于搜索。
  • 通过建议操作实时自动完成任何单词。这有助于在您的终端用户搜索界面中构建快速的单词建议功能。
  • 全Unicode兼容性,支持世界上80多种最常用的语言。Sonic在猜测文本语言后,从任何文本中删除无用的停用词(例如,英语中的“the”),确保任何搜索或摄入的文本在到达索引之前都是干净的; 查看语言
  • 简单的协议(Sonic通道),让您可以搜索索引、管理数据摄入(向索引中推入、从索引中弹出、刷新集合、刷新桶等)并执行管理操作。Sonic通道被设计为资源使用轻量级且易于集成; 阅读协议规范
  • 易于使用的库,让您可以从您的应用程序连接到Sonic; 查看库

如何使用它?

安装

Sonic是用Rust编写的。要安装它,可以从Sonic发布页面下载版本,使用cargo install或从master拉取源代码。

👉 每个发布二进制文件都附带一个.asc签名文件,可以使用@valeriansaliou GPG公钥进行验证: 🔑valeriansaliou.gpg.pub.asc

👉 从软件包安装

Soundic为基于Debian的系统(Debian、Ubuntu等)提供了预构建软件包

重要:目前Soundic只提供针对Debian 12的64位软件包(代号:bookworm)。您可能仍然能够在其他Debian版本以及Ubuntu上使用它们(尽管它们依赖于特定版本的glibc,该版本可能在较老或较新的系统上不可用)。

首先,添加Soundic APT仓库(例如,针对Debian bookworm

echo "deb [signed-by=/usr/share/keyrings/valeriansaliou_sonic.gpg] https://packagecloud.io/valeriansaliou/sonic/debian/ bookworm main" > /etc/apt/sources.list.d/valeriansaliou_sonic.list
curl -fsSL https://packagecloud.io/valeriansaliou/sonic/gpgkey | gpg --dearmor -o /usr/share/keyrings/valeriansaliou_sonic.gpg
apt-get update

然后,安装Soundic软件包

apt-get install sonic

然后,编辑预填充的Soundic配置文件

nano /etc/sonic.cfg

最后,重启Soundic

service sonic restart

👉 从源代码安装

如果您从Git拉取了源代码,可以使用cargo构建它

cargo build --release

构建的二进制文件可以在./target/release目录中找到。

安装build-essentialclanglibclang-devlibc6-devg++llvm-dev,以便能够编译所需的RocksDB依赖项。

请注意,以下可选功能可以在构建Soundic时启用:allocator-jemalloctokenizer-chinesetokenizer-japanese(其中一些可能默认已启用)。

👉 使用Cargo安装

您可以直接使用cargo install安装Soundic

cargo install sonic-server

确保您的$PATH已正确配置以使用Crates的二进制文件,然后使用sonic命令运行Soundic。

安装build-essentialclanglibclang-devlibc6-devg++llvm-dev,以便能够编译所需的RocksDB依赖项。

👉 使用Docker Hub安装

您可能发现通过Docker运行Soundic很方便。您可以在Docker Hub上找到预构建的Soundic镜像,地址为valeriansaliou/sonic

首先,拉取valeriansaliou/sonic镜像

docker pull valeriansaliou/sonic:v1.4.9

然后,创建一个配置文件并运行它(将/path/to/your/sonic/config.cfg替换为您配置文件的路径)

docker run -p 1491:1491 -v /path/to/your/sonic/config.cfg:/etc/sonic.cfg -v /path/to/your/sonic/store/:/var/lib/sonic/store/ valeriansaliou/sonic:v1.4.9

在配置文件中,请确保

  • channel.inet设置为0.0.0.0:1491(这允许Soundic从容器外部访问)
  • store.kv.path设置为/var/lib/sonic/store/kv/(这允许Soundic访问外部KV存储目录)
  • store.fst.path设置为/var/lib/sonic/store/fst/(这允许Soundic访问外部FST存储目录)

Soundic将从tcp://localhost:1491访问。

👉 从其他来源(非官方)安装

其他安装来源可用

  • Homebrew(macOS)brew install sonic查看公式

请注意,这些来源是非官方的,这意味着它们不属于也不由Soundic项目所有者拥有和维护。这些来源上可用的最新Soundic版本可能与通过Soundic项目可用的最新版本不同步。

配置

使用示例配置文件config.cfg,并根据您的环境进行调整。

如果您想微调配置,您可以阅读我们的详细配置文档

运行 Sonic

Sonic 可以这样运行

./sonic -c/path/to/config.cfg

执行搜索和管理对象

搜索和对象管理(即数据摄入)仅通过 Sonic Channel 协议处理。由于我们希望 Sonic 的事情简单(类似于 Redis 的做法),Sonic 不提供 HTTP 端点或类似功能;当您需要与 Sonic 搜索数据库交互时,通过 Sonic Channel 连接是唯一的方式。

Sonic 分发官方库,让您轻松将 Sonic 集成到应用程序中。点击下面的库以查看库集成文档和代码。

如果您想了解原始 Sonic Channel TCP 协议的详细信息,您可以阅读我们的详细协议文档。如果您想编写自己的 Sonic Channel 库,这可能很有用。

📦 Sonic Channel Libraries

1️⃣ 官方库

Sonic 为您的编程语言分发官方 Sonic 集成库(官方意味着这些库已经过核心维护者的审查和验证)

2️⃣ 社区库

以下列出了社区提供的 Sonic 集成(非常感谢他们!)

ℹ️ 找不到您编程语言的库?自己构建并在此引用!(联系我

支持哪些文本语言?

Sonic在其词法分析系统中支持多种语言。如果语言不在列表中,您仍然可以将此语言推送到搜索索引,但停用词将无法排除,这可能导致搜索结果质量较低。

词法分析系统支持的语言有:

  • 🇿🇦 阿拉伯语
  • 🇸🇦 阿拉伯语
  • 🇦🇲 亚美尼亚语
  • 🇦🇿 阿塞拜疆语
  • 🇧🇩 孟加拉语
  • 🇧🇬 保加利亚语
  • 🇲🇲 缅甸语
  • 🏳 加泰罗尼亚语
  • 🇨🇳 中文(简体)
  • 🇹🇼 中文(繁体)
  • 🇭🇷 克罗地亚语
  • 🇨🇿 捷克语
  • 🇩🇰 丹麦语
  • 🇳🇱 荷兰语
  • 🇬🇧 英语
  • 🏳 世界语
  • 🇪🇪 爱沙尼亚语
  • 🇫🇮 芬兰语
  • 🇫🇷 法语
  • 🇬🇪 格鲁吉亚语
  • 🇩🇪 德语
  • 🇬🇷 希腊语
  • 🇮🇳 古吉拉特语
  • 🇮🇱 希伯来语
  • 🇮🇳 印地语
  • 🇭🇺 匈牙利语
  • 🇮🇩 印度尼西亚语
  • 🇮🇹 意大利语
  • 🇯🇵 日语
  • 🇮🇳 卡纳达语
  • 🇰🇭 老挝语
  • 🇰🇷 韩语
  • 🏳 拉丁语
  • 🇱🇻 拉脱维亚语
  • 🇱🇹 立陶宛语
  • 🇮🇳 马拉地语
  • 🇳🇵 尼泊尔语
  • 🇮🇷 波斯语
  • 🇵🇱 波兰语
  • 🇵🇹 葡萄牙语
  • 🇮🇳 旁遮普语
  • 🇷🇺 俄语
  • 🇸🇰 斯洛伐克语
  • 🇸🇮 斯洛文尼亚语
  • 🇪🇸 西班牙语
  • 🇸🇪 瑞典语
  • 🇵🇭 他加禄语
  • 🇮🇳 泰米尔语
  • 🇹🇭 泰语
  • 🇹🇷 土耳其语
  • 🇺🇦 乌克兰语
  • 🇵🇰 乌尔都语
  • 🇻🇳 越南语
  • 🇮🇱 犹太语
  • 🇿🇦 祖鲁语

它有多快、多轻量?

Sonic最初是为Crisp构建的。随着Crisp的成长和将越来越多的搜索数据索引到全文搜索SQL数据库中,我们决定是时候切换到适当的搜索后端系统。在审查Elasticsearch(ELS)和其他系统时,我们发现它们是功能齐全但重量级的系统,并不能很好地适应Crisp基于免费增值的成本结构。

最终,我们决定构建自己的搜索后端,设计上资源简单、轻量。

您可以使用以下命令运行函数级别的基准测试:cargo bench --features benchmark

👩‍🔬 基准测试 #1

➡️ 场景

我们从用于Crisp自身客户支持的所有消息中提取了所有消息。

我们希望将所有这些消息导入一个干净的Sonic实例,然后在构建的索引上执行搜索。我们将测量Sonic执行每个操作(即每个Sonic通道上的PUSHQUERY命令)所花费的时间,并将结果按每1,000个操作分组(这输出了每1,000个操作的平均时间)。

➡️ 上下文

我们的基准测试在以下计算机上运行

  • 设备:MacBook Pro(视网膜,15英寸,2014年中期)
  • 操作系统:MacOS 10.14.3
  • 磁盘:512GB SSD(在AFS文件系统下格式化)
  • 处理器:2.5 GHz Intel Core i7
  • 内存:16 GB 1600 MHz DDR3

Sonic的编译方式如下

  • Sonic版本: 1.0.1
  • Rustc版本rustc 1.35.0-nightly (719b0d984 2019-03-13)
  • 编译器标志release配置文件(带有-03lto

我们的数据集如下

  • 对象数量:约1,000,000条消息
  • 总大小:约100MB的原始消息文本(此数据不包括标识符和其他元数据)

➡️ 脚本

我们用于进行基准测试的脚本有

  1. PUSH脚本sonic-benchmark_batch-push.js
  2. QUERY脚本sonic-benchmark_batch-query.js

⏬ 结果

我们的发现

  • 我们导入约1,000,000条动态长度的消息(有些非常长,例如电子邮件);
  • 导入后,搜索索引在磁盘上的大小为20MB(KV)+ 1.4MB(FST);
  • 导入过程中的CPU使用率平均为单个CPU核心的75%;
  • 在基准测试期间,Sonic进程的RAM使用峰值达到28MB;
  • 我们使用了单个Sonic通道TCP连接,这限制了导入为单个线程(我们本可以将负载均衡到与CPU数量相同的Sonic通道连接上);
  • 我们获得的导入RPS接近每秒4,000次操作(每线程);
  • 我们获得的搜索查询RPS接近每秒1,000次操作(每线程);
  • 在超线程的4核CPU上,我们可以将操作并行化到8个虚拟核心,从而理论上将导入RPS增加到每秒32,000次操作,而搜索查询RPS将增加到每秒8,000次操作(但我们可能在某些时候受到SSD的限制);

每操作的比较结果(单个对象)

我们从批量操作中抽取了8个结果样本,这些操作产生了总共1,000个结果(1,000,000个物品,每次测量报告中有1,000个物品批量处理)。

这并不十分科学,但它应该能让你清楚地了解Sonic的性能。

每操作耗时

操作 平均 最佳 最差
PUSH 275μs 190μs 363μs
QUERY 880μs 852μs 1ms

从我们的终端看到的批量PUSH结果(从初始索引:0个对象)

Batch PUSH benchmark

从我们的终端看到的批量QUERY结果(在索引:1,000,000个对象)

Batch QUERY benchmark

限制

  • 索引数据限制:Sonic旨在设计用于大型搜索索引,每个集合分割成数千个搜索桶。IID(即内部ID)作为32位数字存储在索引中,理论上允许每个桶中索引约42亿个对象(即OID)。我们观察到存储节省了30%到40%,这在大型数据库中是合理的权衡(与Sonic使用64位IID相比)。此外,Sonic只保留最近推入的N个结果,以滑动窗口方式存储给定单词(滑动窗口宽度可配置)。
  • 搜索查询限制:Sonic自然语言处理系统(NLP)不按句子级别工作,出于存储紧凑性的原因(我们保持FST图浅以减少时间和空间复杂度)。它按单词级别工作,因此能够按单词搜索并基于用户输入预测单词,尽管它无法预测句子中的下一个单词。
  • 实时限制:每次从桶图中推入或弹出单词时,FST都需要重建。由于这相当复杂,Sonic将批量重建周期。如果你刚刚向索引中推入了一个新单词,但还没有在SUGGEST命令中看到它,请等待下一个重建周期开始,或者通过在control通道中使用TRIGGER consolidate强制执行。
  • 互操作性限制:Sonic通道协议是读取和写入Sonic搜索索引中搜索条目的唯一方式。Sonic不公开任何HTTP API。Sonic通道在设计时考虑了性能和最小的网络占用。如果您需要从不受支持的编程语言访问Sonic,您可以提出一个问题,或者查看参考node-sonic-channel实现,并在您的目标编程语言中构建它。
  • 硬件限制:Sonic直接在文件系统上执行搜索;即,它不会将索引放入RAM。搜索查询会导致对磁盘的大量随机访问,这意味着它在老式的HDD上会很慢,而在新的SSD上会非常快。请只将Sonic数据库存储在基于SSD的文件系统中。

🔥 报告一个漏洞

如果您发现Sonic中存在漏洞,您非常欢迎直接通过发送加密邮件至@valeriansaliou[email protected])来报告。请不要在公共GitHub问题中报告漏洞,因为这些漏洞可能被恶意人员利用以针对运行未修补Sonic实例的生产服务器。

⚠️ 您必须使用@valeriansaliou GPG公钥加密您的邮件:[🔑valeriansaliou.gpg.pub.asc](https://valeriansaliou.name/files/keys/valeriansaliou.gpg.pub.asc)。

依赖项

~41MB
~766K SLoC