sonic——可替代Elasticsearch的簡單搜尋引擎
近期,筆者在github上發現了一個十分好玩的開源專案——sonic
。sonic專案的介紹十分簡單。
? Fast, lightweight & schema-less search backend. An alternative to Elasticsearch that runs on a few MBs of RAM.
在這段話中,我們可以很迅速的瞭解sonic 的特性。
首先,它很快,比Elasticsearch還要快很多,在官方給出的benchmark中,它的搜尋都在毫秒級別的。
第二,它輕量,Elasticsearch在漫長的發展過程中,已經變得越來越沉了,不僅支援搜尋,儲存,分析,視覺化,Elasticsearch還擁抱上了大資料,使Elasticsearch的學習曲線很高,而且使用成本也很高,普通的機器已經完全不夠用了,而sonic十分的輕,上手快,API少,專注於搜尋這一塊。
第三,無正規化(schema-less)。請原諒我這樣翻譯,Elasticsearch在使用中你需要先定義mappings來讓資料格式化。很多時候,定義固定結構去儲存資料本應該是資料庫該乾的事,但是Elasticsearch支援了資料儲存,因此你必須先完成這一步才能使用Elasticsearch。而sonic是無正規化的,sonic不做資料的儲存,它只做搜尋,因此你不需要做mappings。
第四,省錢。在任何實際專案的開發和運維中,成本大多時候被放在了第一位,sonic對於執行機的要求很低,且記憶體佔用少,可以為你省下一大筆的開支。
說了這麼多,你是否也想嘗試一下sonic
?接下來我們一起來實操一下,看看能否窺一斑而知全豹
。
使用
安裝
首先一點,sonic不支援windows,因此最好的使用方式便是docker
,所以請先確保你會簡單的使用docker,僅僅需要知道一些概念即可。
請在終端鍵入如下命令:
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.cfgvaleriansaliou/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的操作可分為三個模式:
-
Search mode(搜尋模式),sonic的模式區分很是硬核,在搜尋模式下,你只能進行搜尋相關的操作,不能進行資料插入和備份的相關操作。核心的有
QUERY
和SUGGEST
兩個操作,分別用來對詞
進行搜尋和對字
進行補全。 -
Ingest mode(插入模式),請記住
sonic只有在插入模式下才能進行資料的插入
。sonic的資料插入核心的有三個操作,分別是PUSH
、POP
和FLUSH
。push會向儲存區中新增一個元素,pop則是從儲存區中彈出這個元素,flush則會將儲存區中的元素全部清除。 -
Control mode(控制模式),sonic可以在控制模式下,對資料進行鞏固,備份和恢復等一系列的操作。核心的操作有
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的對比思考