對應到業務裡,常用的查詢其實大多數都是這些很簡單的條件並列,A && B && C && D。所以翻譯起來也比較簡單。
單表的count放在ES裡做也非常的快,為什麼呢?因為ES本身會把單個欄位的一種值當作一個term,然後會記錄這個term出現的所有文件和出現次數。舉個例子,我們公司的業務,可能會去查詢某個業務線下的所有工單。那麼查詢條件就類似於where business_type is 6這樣。可能只需要一毫秒就返回了結果。很費解是不是?其實ES也只是去讀了一下這個business_type是6的term出現的文件數,邏輯上是很簡單的。
從傳統的sql思維翻譯到es的dsl過程也稍微有點痛苦。因為ES畢竟是從搜尋引擎的角度去做這些事情,所以如果當DB來用的話,其DSL設計就顯得很彆扭。雖然有了上面的轉換規則,但實際上業務轉換起來並沒有這麼方便,比如在通常的查詢裡還可能會有where a = 1 or b = 2。顯然想轉成DSL就沒有這麼方便了。
ElasticSearch最廣泛的使用場景,是提供垂直搜尋功能。什麼是垂直搜尋呢?
垂直搜尋引擎是針對某一個行業的專業搜尋引擎,是搜尋引擎的細分和延伸,是對網頁庫中的某類專門的資訊進行一次整合,定向分欄位抽取出需要的資料進行處理後再以某種形式返回給使用者。垂直搜尋是相對通用搜索引擎的資訊量大、查詢不準確、深度不夠等提出來的新的搜尋引擎服務模式,透過針對某一特定領域、某一特定人群或某一特定需求提供的有一定價值的資訊和相關服務。其特點就是“專、精、深”,且具有行業色彩,相比較通用搜索引擎的海量資訊無序化,垂直搜尋引擎則顯得更加專注、具體和深入。
其實說白了就一句話,垂直搜尋是在企業內部使用的搜尋引擎。這種搜尋引擎的特點是,內容可能是一些結構化的資料,而不像大搜索那樣都是雜亂的內容。
一般被拿來解決一些什麼樣的問題?
資料庫欄位太多,查詢太慢,索引沒有辦法再做最佳化;資料庫一個count就拖死全表;MySQL的limit翻到幾十幾百萬頁後實在是太慢;資料庫like實在太慢,每次like整個伺服器cpu記憶體飆高,拖慢整個線上服務;想要對外/內提供db裡的資料的全文檢索服務;提供日誌(程式執行)查詢功能;下面來針對上面幾方面的問題逐一進行說明。
資料庫方面MySQL對於一些較為固定,欄位較少的查詢方式,可以透過簡單的增加索引來完成最佳化。在大多數公司,即使對索引最佳化不熟悉,也有專門的dba來幫忙完成一些簡單的最佳化。甚至有些公司要求程式中不允許出現orm,必須用純sql來完成業務邏輯,這樣dba可以直接介入到程式碼中來。
不過到欄位太多的時候,這種方法就失靈了。欄位越多,查詢自然就越慢(比如單條記錄可能都超過了4k)。
MySQL表在普通查詢過程中,比如select * from xxx limit 100w, 100;這種,資料量小的時候隨便寫sql,可能不會體會到翻頁的痛。但在一個單表3000w的系統中寫了limit 100w, 10。那資料庫伺服器就哭了。因為實際上資料庫為了取出想要的那幾條資料,需要把所有的資料也就是10000010條都取到記憶體中,複雜一點的select再加上order by則可能會同時涉及到多次磁碟讀取和檔案排序,慢上加慢。
除此之外,現在最流行的innodb之類的儲存引擎在計算count的時候非常的慢。當然了,網路上會有人從亂七八糟的文章裡看到換myisam應該就會更快的結論,但這其實是錯的。如果在select語句的where條件中也有表示式時,這兩種儲存引擎本質上都是一樣的,都會很慢很慢。
還有MySQL的like,其實沒什麼玄幻的,每次做like本質還是查詢內容去和資料庫欄位做字串匹配。非常地慢。
現在一般的網際網路系統都是普遍的寫少讀多的系統,寫/讀搞不好會有1/5以上。但因為資料量龐大,為了讀取效率而去做拆表或者拆庫的話,有時候實在是有點得不償失。而且拆表拆庫對業務程式碼來說也並不透明,還可能會對本來支援的功能造成額外的影響。只是為了查詢而去拆分的話,不是很合適。
上面這些問題,ES都可以解決。企業裡對資料的查詢一般可以分為三種:列表查詢、詳情查詢和統計查詢。列表一般就是列表頁對應的查詢,詳情查詢一般就是具體id對應的詳情查詢,而統計查詢一般都是在看一些數值之類的報表,也就是一堆count值。
這三種查詢裡,MySQL做起來最困難的是1和3,即列表查詢和統計查詢。列表查詢這種場景也會對應各種各樣的查詢條件,例如欄位等於/小於/大於/不等判斷,或者像字串的嚴格匹配/前後綴模糊查詢,時間欄位的範圍查詢,in查詢等等。這些查詢都可以翻譯為ES中的bool查詢,舉一個簡單的例子:
例如上面這個es中的bool查詢,就是從這種sql翻譯過來的:
對應到業務裡,常用的查詢其實大多數都是這些很簡單的條件並列,A && B && C && D。所以翻譯起來也比較簡單。
單表的count放在ES裡做也非常的快,為什麼呢?因為ES本身會把單個欄位的一種值當作一個term,然後會記錄這個term出現的所有文件和出現次數。舉個例子,我們公司的業務,可能會去查詢某個業務線下的所有工單。那麼查詢條件就類似於where business_type is 6這樣。可能只需要一毫秒就返回了結果。很費解是不是?其實ES也只是去讀了一下這個business_type是6的term出現的文件數,邏輯上是很簡單的。
這是不是說明ES就是萬能的了?
並不是。
首先是翻頁的問題,ES裡有上億資料,翻到最後一頁的時候還是會比較慢,並且會影響到整個系統的load,然後系統響應變慢。因為其原理還是拿一堆資料來做merge。
從傳統的sql思維翻譯到es的dsl過程也稍微有點痛苦。因為ES畢竟是從搜尋引擎的角度去做這些事情,所以如果當DB來用的話,其DSL設計就顯得很彆扭。雖然有了上面的轉換規則,但實際上業務轉換起來並沒有這麼方便,比如在通常的查詢裡還可能會有where a = 1 or b = 2。顯然想轉成DSL就沒有這麼方便了。
ES不是資料庫,所以如果想要實現聯表查詢也會變得很麻煩。如果還想實現事務,那麼還是放棄吧。
在企業裡用ES提供查詢服務的話,一般都會做一層查詢封裝。直接提供sql介面。
但外掛支援的功能也是有限的,並不是所以的特性都能很好的支援,比如join。所以也有一些公司的人會用druid之類的東西做一個sql parser層,然後來支援這些需求。
不過即使是直接用這種外掛,也不能認為它就能一勞永逸,還是需要對ES內部的機制(例如mapping)和通常的查詢方式(term/query_string/wild_card等)很瞭解才行。
比如必須知道wildcard查詢必須對字串欄位設定為not_analyzed。還得知道term什麼時候代表的是分詞後的詞,什麼時候代表的是整個欄位的值。
在瞭解了這些之後才會瞭解到ES的高效能like,其實也還是有一些限制。例如輸入的字串會被分詞,這也就是說,想要高效能的時候只能用ES預設提供的基於詞的字串like,而且一旦分詞,就沒辦法實現類似sql裡的 x= "Hello world"這種準確匹配的邏輯。也就是說,在ES裡查詢hello world,hello world fuck也會出現在結果當中。不過這個對於大多數的業務來說實際上是無所謂的。
檢索服務方面搜尋是人類的自然需求。如果不是的話,那Google和百度就不會誕生了。
而檢索/搜尋的基本原理就是對語句進行分詞,然後再形成倒排索引,再根據詞項出現次數對文件進行打分,最終按分數倒序展示給使用者。
對於海量資料的公司來說,一個單機的方案很快就會遇到瓶頸,而去尋求或自行開發更好的解決方案。在ES之前solr更流行一些吧,不過solr的配置還是稍微麻煩,而es的叢集搭建只要改改yml就好了。
有了ES以後,叢集便可以非常方便地進行動態擴充套件。只要加硬碟加機器改配置就好,因為本身的副本分佈策略比較科學。所以只要別一半以上的節點都掛掉,資料就不會丟失。而且還會在某些結點掛掉的時候自動進行分片relocate。
由於ES本身帶的分詞不是很科學,這樣的話對doc打分可能會有一些影響。比如華人可能不正確地分成了中/華人之類的。現在很多人會選擇以外掛的形式把ik分詞器之類的外掛掛載到es上來改善分詞效果。這些外掛的本質其實還是一個非常龐大的中文詞庫。內部設計有連結可以直接檢視語句的分詞結果,可以方便地直接檢視效果。
所以要是有幾億的文件需要做些檢索,那五六臺配置不錯的ES機器就足夠了,甚至都不用ssd。
日誌方面企業裡的系統一般都是分散式系統,所以無論是接入,還是api,還是db,都不太可能在一臺機器上完成需求。
對於某一個服務模組來說,多臺機器最麻煩的就是去查問題。在沒有日誌系統的時代,程式設計師大概只能登陸到機器去一臺一臺尋找可能的錯誤日誌,然而因為負載均衡演算法(比如可能是一致性雜湊望/隨機/RR/WR)的問題,可能一個使用者在一次訪問會話(session)中的請求都不是一臺而是多臺機器完成的響應。
所以日誌系統的工作就是把日誌彙集到一起,並提供統一的查詢入口。
要收集日誌一般會自行搭建一個elk平臺,elasticsearch/logstash/kibana必不可少。
不過拿來的東西總會有那麼一些問題,比如kibana裡的按地圖出資料預設用的是googlemap,在牆內使會有些問題,這個問題github上也有人已經解決了。再比如logstash這個程式可能只考慮了簡單的收集 ,如果是大公司的業務講究一個嚴謹。例如想要對日誌收集端的資源使用做一些限制,不能隨便佔用系統資源而影響到業務系統。再比如還希望日誌不要因為網路閃斷之類的問題導致日誌丟失什麼的,所以還可能會在logstash後面再加一個kafka/redis。不管怎麼說,工作基礎還是elk。
日誌系統還存在一個問題,因為海量的資料和海量的訪問,日誌的資料量一般都非常地龐大。所以一般資料都會有一個過期時間,一般來說,日誌資料其實一般也就一週或者一個月。畢竟即使是一個邊緣部門,一週的日誌也都已經幾個億(100+GB)了。
查詢起來也不希望太慢,所以還是儘量把日誌索引的大小控制在一個範圍內。當然,也有按照日期來生成索引的。每一天在一個獨立的索引下,這樣查詢效能也會好一些。
同時又是因為這海量的資料,在寫入到ES的時候必須使用bulk埠,相信使用過ES的人都知道使用和不使用分別意味著什麼。