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