近期,笔者在github上发现了一个十分好玩的开源项目——sonic
。sonic项目的介绍十分简单。python
🦔 Fast, lightweight & schema-less search backend. An alternative to Elasticsearch that runs on a few MBs of RAM.git
在这段话中,咱们能够很迅速的了解sonic的特性。github
首先,它很快,比Elasticsearch还要快不少,在官方给出的benchmark中,它的搜索都在毫秒级别的。redis
第二,它轻量,Elasticsearch在漫长的发展过程当中,已经变得愈来愈沉了,不只支持搜索,存储,分析,可视化,Elasticsearch还拥抱上了大数据,使Elasticsearch的学习曲线很高,并且使用成本也很高,普通的机器已经彻底不够用了,而sonic十分的轻,上手快,API少,专一于搜索这一块。sql
第三,无范式(schema-less)。请原谅我这样翻译,Elasticsearch在使用中你须要先定义mappings来让数据格式化。不少时候,定义固定结构去存储数据本应该是数据库该干的事,可是Elasticsearch支持了数据存储,所以你必须先完成这一步才能使用Elasticsearch。而sonic是无范式的,sonic不作数据的存储,它只作搜索,所以你不须要作mappings。mongodb
第四,省钱。在任何实际项目的开发和运维中,成本大多时候被放在了第一位,sonic对于运行机的要求很低,且内存占用少,能够为你省下一大笔的开支。docker
说了这么多,你是否也想尝试一下sonic
?接下来咱们一块儿来实操一下,看看可否窥一斑而知全豹
。数据库
首先一点,sonic不支持windows,所以最好的使用方式即是docker
,因此请先确保你会简单的使用docker,仅仅须要知道一些概念便可。windows
请在终端键入以下命令:bash
docker pull valeriansaliou/sonic:v1.2.0
复制代码
等待一下子,docker会帮咱们搞定一切,拉取完成以后,咱们须要一份简单的sonic配置文件——config.cfg
。配置文件内容以下:
# Sonic
# Fast, lightweight and schema-less search backend
# Configuration file
# Example: https://github.com/valeriansaliou/sonic/blob/master/config.cfg
[server]
log_level = "debug"
[channel]
inet = "0.0.0.0:1491"
tcp_timeout = 300
auth_password = "SecretPassword"
[channel.search]
query_limit_default = 10
query_limit_maximum = 100
query_alternates_try = 4
suggest_limit_default = 5
suggest_limit_maximum = 20
[store]
[store.kv]
path = "/var/lib/sonic/store/kv/"
retain_word_objects = 1000
[store.kv.pool]
inactive_after = 1800
[store.kv.database]
flush_after = 900
compress = true
parallelism = 2
max_files = 100
max_compactions = 1
max_flushes = 1
write_buffer = 16384
write_ahead_log = true
[store.fst]
path = "/var/lib/sonic/store/fst/"
[store.fst.pool]
inactive_after = 300
[store.fst.graph]
consolidate_after = 180
复制代码
在这份配置文件中,你可能只须要注意两个点:
"0.0.0.0:1491"
。"SecretPassword"
。sonic在通讯协议上选择了更加高效的tcp协议,而且衍生了本身的一套脚本语言,放心仅仅只是几句简单的查询操做语句。
请将配置文件存放在一个合适的位置存储,如笔者的存储位置在/Users/pedro/Desktop/sonic-test/config.cfg
。
在终端输入以下命令,咱们开启一个sonic服务:
docker run -p 1491:1491 -v ~/Desktop/sonic-test/config.cfg:/etc/sonic.cfg valeriansaliou/sonic:v1.2.0
复制代码
等待一下子,若是终端出现以下信息,则表明运行成功:
(INFO) - starting up
(INFO) - started
(DEBUG) - spawn managed thread: tasker
(DEBUG) - spawn managed thread: channel
(INFO) - tasker is now active
(INFO) - listening on tcp://0.0.0.0:1491
复制代码
在具体的数据操做以前,咱们十分有必要的去了解一下sonic的工做机制。请记住,这很重要,了解它你才会有足够清晰的大局观,才有可能作到窥一斑而知全豹
。
sonic的操做可分为三个模式:
QUERY
和SUGGEST
两个操做,分别用来对词
进行搜索和对字
进行补全。sonic只有在插入模式下才能进行数据的插入
。sonic的数据插入核心的有三个操做,分别是PUSH
、POP
和FLUSH
。push会向存储区中添加一个元素,pop则是从存储区中弹出这个元素,flush则会将存储区中的元素所有清除。TRIGGER
和INFO
,trigger主要对数据进行巩固,备份和恢复,而info用于查看sonic的运行状态。在刚才咱们谈到过了sonic的协议,咱们把它称做Sonic Channel protocol
。这份协议构建在tcp的协议之上,若是你熟悉redis的话,你可能会发现,两者非常类似。
sonic在此协议上衍生了这三大模式以及相关的操做,不难发现,sonic的核心概念和使用真的十分简单,固然了笔者不可能在此处全盘拖出,在sonic的文档中详细的给出了Sonic Channel protocol
的具体细节和实用方法,若是感兴趣,请务必了解一下。
sonic的服务运行起来之后,咱们经过telnet
这个实用的工具来操做一下它。
在终端输入:
telnet localhost 1491
复制代码
出现以下信息表示你链接成功。
Trying ::1...
Connected to localhost.
Escape character is '^]'.
CONNECTED <sonic-server v1.2.0>
复制代码
在真正的插入以前,咱们还须要对sonic的存储
作一下简单的概述。在文章的开头,笔者说到sonic只关注于搜索,而将数据的存储交给了其它的数据库去实现。那么sonic真的不须要存储吗?
答案显而易见,须要!难道这是欺骗吗?固然不是,sonic不作数据的存储,但它须要对搜索的部分数据作索引和存储。你可能会以为有些绕,不要紧,咱们举个例子。
一篇文章,可能有标题,综述,正文,做者...等一系列的数据。那么在搜索这篇文章的时候,咱们不可能搜索这全部的字段数据,咱们每每会采起一种折中的方式,搜索某几个字段的数据。例如:咱们搜索综述和标题,而放弃搜索庞大的正文数据,这既提升了搜索效率,也下降了搜索成本。
这个时候,你再来理解,sonic它确实不作存储,它不会存储这篇文章的全部字段,即不会存储标题,综述,正文,做者等等,可是它须要存储它用来作搜索的部分数据,即综述和标题。相比存储全部字段的庞大数据,综述和标题仅仅占了很小的一部分。
好,重点来了!sonic如何存储这些有效的搜索数据的呢?sonic有两个存储点,一个是kv
存储,一个是fst
存储。kv
存储很好理解,即key-value
存储,咱们须要把综述和标题合并成一个value
,并为它取上惟一的key
,这个key
通常对应数据库的主键,sonic会把这两个值存储到kv
区。
对于把综述和标题合并成一个value
,我想不少人会有些许不理解,把它们合并了还怎么搜索了?不用怕,sonic会自动帮咱们作分词,并将其经过倒排索引
的方式存储起来,当你在经过词搜索的时候,通常状况下只会取几个词作搜索,而不会取所有,因此即便合并起来,影响也不大,固然你也能够仅选择一个字段作value
,这样就不会有合并的问题。
好,上段之中,咱们抛出了倒排索引
这个概念,在此处笔者对其不作详细解释,若是你想了解,查询一些资料便可。你能够简单理解为倒排
就是经过词
来找句子
,索引会存储词
和句子
之间的关联,而后经过搜索传来的词来反向寻找句子。此处你可能已经意识到了,这些索引是否是要存储到fst
区啊。是的,这些倒排索引会存储到fst
区,与kv
区良好的分开。
好了,谈了这么多,咱们终于能够进入到实操环节了。经过telnet
链接sonic以后,咱们尝试插入一条数据。
telnet localhost 1491
Trying ::1...
Connected to localhost.
Escape character is '^]'.
CONNECTED <sonic-server v1.2.0>
# 此处以 START 开始 ingest模式 SecretPassword 是密码,务必输入密码
START ingest SecretPassword
# sonic的返回信息
STARTED ingest protocol(1) buffer(20000)
# 经过PUSH 插入数据
# movie 为 collection名
# douban 为 bucket 名
# 1 为 object 名 即 key 值
# "the knight" 为 value 值
PUSH movie douban 1 "the knight"
# 插入成功后的返回值 ok
OK
# 退出
QUIT
ENDED quit
复制代码
笔者已经在注释中,详细的解释了每一行命令的做用,但这可能仍是不够友好。sonic每次链接均可以被理解成一次会话(session),这个会话从START
命令开始,固然若是经过telnet链接后一段时间未执行start,sonic会自动关闭掉这个链接。
START
命令后,会开始一个会话。具体的命令格式为START <mode> <password>
,如START ingest SecretPassword
会开启插入模式(ingest model),密码为SecretPassword
。sonic鉴权成功后,返回会话创建成功的信息STARTED ingest protocol(1) buffer(20000)
。
随后,再经过PUSH
命令插入一条数据,命令格式为PUSH <collection> <bucket> <object> "<text>"
。这里注意:sonic与大多数数据库同样都有层级
的概念,如在mongodb
中有 数据库 -> 集合 -> 项 -> 字段的层级概念,sonic也有 collection -> bucket -> [object:text]的层次。
固然有人会问,这有啥用啊?就但这条语句PUSH movie douban 1 "the knight"
而言,它就能够看到层级的做用,它能够将搜索数据分类,更为重要的是,the knight归到了movie
集合下的douban
桶,而当有其它的集合时,如song
,咱们能够有效的在某个集合的某个桶下进行有效的搜索。
插入成功后,返回一个OK
。
插入数据后,咱们尝试再次链接,并用搜索模式进入一个会话。
# 开始一个搜索会话
START search SecretPassword
STARTED search protocol(1) buffer(20000)
# 搜索 movie -> douban 下的数据,搜索关键字为 the
QUERY movie douban "the"
PENDING Q5Z3lY25
# 获得搜索结果,返回object,即key值 1
EVENT QUERY Q5Z3lY25 1
复制代码
搜索做为sonic的最最最重要的部分,使用起来极其简单,但却十分强大。其命令格式为QUERY <collection> <bucket> "<terms>" [LIMIT(<count>)]? [OFFSET(<count>)]?
,熟悉sql
的立马就能理解如何使用了,collection和bucket表示详细的层级关系,terms表示搜索的关键词,limit 限制返回结果的数量,offset表示结果的偏移量。
PENDING Q5Z3lY25
EVENT QUERY Q5Z3lY25 1
复制代码
这两行均是搜索以后,sonic的返回信息,表示发生了一个事件,事件id为Q5Z3lY25,获得的结果是1
。
sonic还支持单词的自动补全,如输入th
,它会返回the
这个单词,帮助你的搜索进行自动补全,提升用户体验。具体的格式是:SUGGEST <collection> <bucket> "<word>" [LIMIT(<count>)]?
。
START search SecretPassword
STARTED search protocol(1) buffer(20000)
# 输入 th 这两次字母
SUGGEST movie douban "th"
PENDING SukqsbYk
# 返回 the 这个已经补全的单词
EVENT SUGGEST SukqsbYk the
复制代码
这里要注意一下,SUGGEST
仅仅支持limit这一个项,在书写命令的时候请必定保持大写即LIMIT
。
sonic在控制模式下,能够对数据进行consolidate
加固,backup
备份,restore
恢复,以及INFO
查看sonic服务的数据等操做。
这些操做对于数据维护以及服务运维来讲很重要,但显然不是这篇文章的重点。以上的所有操做,都可以在sonic的文档中找到,若是你感兴趣,请务必阅读一下,它真的不多,很方便上手。
在文章开头到结尾,笔者介绍了sonic的特性和它的一些概念,以及部分的工做原理。若是你单纯的想要去使用sonic,那么请记住,熟悉本文提到的概念,保证对sonic的大局观的理解,详细阅读一下它的文档,那么你就能够去尝试使用sonic。
到此,咱们几乎介绍到了sonic的所有,相较于Elasticsearch,它真的足够小巧,足够简单,将搜索作到了精细极致。
在下篇文章中,笔者会使用python
,mongodb
作一个简单的搜索应用,尽情期待吧,诸君。
过分封装带来的简单性,并不会带来真正的简单,只会带来更加的复杂。——来自sonic和Elasticsearch的对比思考