sonic——可替代Elasticsearch的簡單搜索引擎

簡介

近期,筆者在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

複製代碼

在這份配置文件中,你可能只須要注意兩個點:

  • inet,sonic的監聽端口,這裏默認爲"0.0.0.0:1491"
  • auth_password,sonic的密碼,這裏默認爲"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的操做可分爲三個模式:

  • Search mode(搜索模式),sonic的模式區分非常硬核,在搜索模式下,你只能進行搜索相關的操做,不能進行數據插入和備份的相關操做。核心的有QUERYSUGGEST兩個操做,分別用來對進行搜索和對進行補全。
  • Ingest mode(插入模式),請記住sonic只有在插入模式下才能進行數據的插入。sonic的數據插入核心的有三個操做,分別是PUSHPOPFLUSH。push會向存儲區中添加一個元素,pop則是從存儲區中彈出這個元素,flush則會將存儲區中的元素所有清除。
  • Control mode(控制模式),sonic能夠在控制模式下,對數據進行鞏固,備份和恢復等一系列的操做。核心的操做有TRIGGERINFO,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,它真的足夠小巧,足夠簡單,將搜索作到了精細極致。

在下篇文章中,筆者會使用pythonmongodb作一個簡單的搜索應用,盡情期待吧,諸君。

過分封裝帶來的簡單性,並不會帶來真正的簡單,只會帶來更加的複雜。——來自sonic和Elasticsearch的對比思考

相關文章
相關標籤/搜索