近期,筆者在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的對比思考