垂直搜索(站內搜索)java
互聯網的搜索:電商網站,招聘網站,各類appnode
IT系統的搜索:OA軟件,辦公自動化軟件,會議管理,員工管理,後臺管理系算法
數據庫在作某些搜索(模糊搜索)時,效率會不好,是不太靠譜的。數據庫
數據庫搜索的弊端:數據庫裏有100萬條數據,模糊匹配要掃描100萬次,每次掃描都要匹配文本全部字符,還沒法拆解開來檢索。json
全文檢索:會將100萬條數據拆分開來,創建倒排索引,搜索的時也許第一次就能夠搜素到對應的數據,多是100次,1000次,上述過程就叫全文檢索。api
Lucene:服務器
lucene的弊端:數據量大,一臺機器難以放下,須要多臺機器,可用性,可維護性差。restful
自動維護數據的分佈到多個節點的索引的創建,還有搜索請求分不到多個節點執行數據結構
自動維護數據的冗餘副本,保證說一些機器宕機了,不會丟失任何的數據app
分裝了更多的高級功能,以給咱們提供更多高級的支持,讓咱們快速地開發應用,開發更復雜的應用,複雜的搜素功能,聚合分析的功能。
分佈式搜索引擎和數據分析引擎
搜索:百度,網站站內搜索,It系統檢索
數據分析: 電商網站,最近7天牙膏銷量排行較前有哪些;新聞網站,最近一個月訪問量排行前十的有哪些
全文檢索:結構化檢索,數據分析
結構化檢索:我想搜索的商品分類爲日化用品的有哪些: select* from prod where cate_id = '日化用品'
全文檢索:想搜索商品名稱包含牙膏的商品: select * from prod where prod_name like "%牙膏%"
數據分析: 分析一下每個商品分類有多少商品,select cate_id,count(*) from prod group by cate_id
對海量數據近實時處理
分佈式: ES能夠自動將海量數據分散到多臺服務器上存儲和檢索
海量數據的處理:分佈式之後,就能夠採用大量服務器去檢索和存儲數據。
近實時:在秒級別對數據進行搜索和分析。
與海量數據/分佈式相反:lucene,單機應用,只能在單臺服務器上用,最多隻能處理單臺服務器的數據
維基百科,全文檢索,高亮,搜索推薦
電商網站,檢索商品
新聞網站,用戶行爲日誌(點贊,評論),數據分析
論壇網站,全文檢索,搜索問題和答案
Github,搜索代碼和項目
日誌數據分析,logstash採集日誌,ES進行復雜的數據分析(ELK技術,elasticsearch+logstash+kibana)
商品價格監控網站,用戶設定某商品的價格閾值,低於閾值時,發送通知給用戶。
BI系統,商業智能,ES執行數據分析和挖掘
站內搜索(電商,招聘,門戶),IT搜索(OA,CRM,ERP)等
能夠做爲大型分佈式集羣的技術,處理PB級的數據,服務大公司,也能夠運行在單機上
ES不是什麼新技術,主要是將全文檢索,數據分析以及分佈式技術合併在了一塊兒
對用戶而言,開箱即用,較爲簡單
數據庫的功能面對不少領域是不夠用的,好比全文檢索,同義詞處理,相關度排名,複雜數據分析,海量數據近實時處理。ES能夠做爲傳統數據庫的不錯,提供數據庫不足的功能。
lucene,最早進,最強大的搜索庫,基於lucene開發,很是複雜,api複雜,須要深刻原理。
ES基於lucene,隱藏其複雜性,提供簡單易用的restful接口,java api接口。
分佈式的文檔存儲引擎
分佈式的搜索引擎和分析引擎
分佈式,支持PB級數據
1.Near Realtime(NRT): 近實時,從寫入數據到ES到能夠被搜索到大概有1秒延遲,基於ES執行搜索和分析能夠達到秒級
2.Cluster: 集羣,包含多個節點,每一個節點屬於哪一個集羣是經過一個配置(集羣名稱,默認是elasticsearch)來決定的,對於中小型應用來講,剛開始一個集羣就一個節點很正常。
3.Node: 節點,集羣中的一個節點,節點也有一個名稱(默認是隨機),節點名稱很重要(在執行運維管理操做的時候),默認節點會去加入一個名稱爲"elasticsearch"的集羣,若是直接啓動一堆節點,那麼他們會自動組成一個elasticsearch集羣,固然一個節點也能夠組成一個es集羣
4.Document: 文檔。es中的最小單元,一個document能夠是客戶的一條數據,一條商品數據,訂單數據,一般用JSON數據結構表示,每一個index下的type中,均可以存儲多個doucument,一個document裏面有多個field,每一個field就是一個數據字段
Index: 索引,包含一堆有類似結構的文檔數據,好比一個商品索引,訂單索引,索引有一個名稱。一個index包含多個document,好比創建了一個商品索引,product index,裏面可能就存放了全部商品的數據。
Type:類型,每一個索引裏面均可以有一個或多個type,type是index的一個邏輯數據分類,一個type下的document,都有相同的field(有例外),好比博客系統,有一個索引,能夠定義用戶數據的type,博客數據的type
shard: 單臺機器沒法存儲大量數據,es能夠將一個索引中的數據切分爲多個shard,分佈在多臺服務器上存儲。有了shard就能夠橫向擴展,存儲更多數據,讓數據搜索和分析等操做分佈到多臺服務器上執行,提升吞吐量和性能。
PS:index會被拆分爲多個shard,每一個shard會存放這個index的部分數據,這些shard分佈在多臺服務器上分佈執行,提高吞吐量與性能。
replica: 任何一個服務器隨時可能故障或宕機,此時shard可能就會丟失,所以能夠爲每一個shard建立多個replica,replica能夠在shard故障時隨時提供服務,保證數據不丟失,多個replica還能夠提升吞吐量和性能。primary shard(建索引是一次設置,不能修改,默認5個),replica shard(隨時修改,默認1個),默認每一個索引10個shard,5個primary shard,5個replica shard,最小高可用配置,是兩臺服務器。
PS: shard其實叫primary shard,replica叫replica shard,其實都shard
replica的好處:
1).提高了高可用性,一個shard宕機,數據不丟,服務繼續提供
2).提高了搜索這類請求的吞吐量和性能
安裝JDK,至少Java1.8以上
下載解壓ES安裝包
啓動ES(使用終端命令行工具啓動,bin目錄下的elasticsearch)
檢查ES是否啓動成功(默認是localhost 9200端口)
修改集羣名稱:elasticsearch.yml
下載和解壓縮Kibana安裝包,使用裏面的開發界面,操做es,是學習es的主要界面入口
啓動kibana(默認localhost:5601)
應用系統的數據結構都是面向對象的,複雜的
對象數據存儲到數據庫中,只能拆解開來,變爲扁平的多張表,每次查詢返回原對象的格式,至關麻煩
ES是面向文檔的,文檔中存儲的數據結構,與面向對象的數據結構是同樣的,基於這種文檔數據結構,es能夠提供複雜的索引,全文檢索,分析聚合等功能
ES的document用json數據格式來表達
有一個電商網站,須要爲其基於ES構建一個後臺系統,提供如下功能:
對商品信息進行CRUD(增刪改查)操做
執行簡單的結構化查詢
能夠執行簡單的全文檢索,以及複雜的phrase(短語)檢索
對於全文檢索的結果,能夠進行高亮顯示
對數據進行簡單的聚合分析
一、快速檢查集羣的健康情況
es提供了一套api,叫作cat api,能夠查看es中各類各樣的數據
GET /_cat/health?v
如何快速瞭解集羣的健康情況?green、yellow、red?
green:每一個索引的primary shard和replica shard都是active狀態的 yellow:每一個索引的primary shard都是active狀態的,可是部分replica shard不是active狀態,處於不可用的狀態 red:不是全部索引的primary shard都是active狀態的,部分索引有數據丟失了
爲何如今會處於一個yellow狀態?
咱們如今就一個筆記本電腦,就啓動了一個es進程,至關於就只有一個node。如今es中有一個index,就是kibana本身內置創建的index。因爲默認的配置是給每一個index分配5個primary shard和5個replica shard,並且primary shard和replica shard不能在同一臺機器上(爲了容錯)。如今kibana本身創建的index是1個primary shard和1個replica shard。當前就一個node,因此只有1個primary shard被分配了和啓動了,可是一個replica shard沒有第二臺機器去啓動。
作一個小實驗:此時只要啓動第二個es進程,就會在es集羣中有2個node,而後那1個replica shard就會自動分配過去,而後cluster status就會變成green狀態。
二、快速查看集羣中有哪些索引
GET /_cat/indices?v
三、簡單的索引操做
建立索引:PUT /test_index?pretty
刪除索引:DELETE /test_index?pretty
1.新增商品:新增文檔,創建索引
語法: PUT /index/type/id { "json數據" }
示例:
PUT /ecommerce/product/1 { "name" : "gaolujie yagao", "desc" : "gaoxiao meibai", "price" : 30, "producer" : "gaolujie producer", "tags": [ "meibai", "fangzhu" ] }
Return:
{ "_index": "ecommerce", "_type": "product", "_id": "1", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": true }
PS:ES會自動創建index和type,不須要提早建立,並且es默認會對document每一個field都創建倒排索引,讓其能夠被搜索
2.查詢商品:檢索文檔
語法: GET /index/type/id
GET /ecommerce/product/1
3.修改商品:替換文檔
PUT /ecommerce/product/1 { "name" : "jiaqiangban gaolujie yagao", "desc" : "gaoxiao meibai", "price" : 30, "producer" : "gaolujie producer", "tags": [ "meibai", "fangzhu" ] }
PS:替換方式有一個很差,即便必須帶上全部的field,才能去進行信息的修改
4.修改商品:更新文檔
POST /ecommerce/product/1/_update { "doc": { "name": "jiaqiangban gaolujie yagao" } }
5.刪除商品:刪除文檔
DELETE /ecommerce/product/1
*搜索所有商品: GET /ecommerce/product/search
took: 耗費了幾毫秒 timed_out: 是否超時,這裏是沒有 shards: 數據拆成了5個分片,因此對於搜索請求,會打到全部的primary shard(或者是它的某個replica shard也能夠) hits.total: 查詢結果的數量,3個document hits.max_score: score的含義,就是document對於一個search的相關度的匹配分數,越相關,就越匹配,分數也高 hits.hits: 包含了匹配搜索的document的詳細數據
query string search的由來,由於search參數都是以http請求的query string來附帶的
搜索商品名稱中包含yagao的商品,並且按照售價降序排序:GET /ecommerce/product/_search?q=name:yagao&sort=price:desc
PS: 適用於臨時的在命令行使用一些工具,好比curl,快速的發出請求,來檢索想要的信息;可是若是查詢請求很複雜,是很難去構建的,在生產環境中,幾乎不多使用query string search
DSL: Domain Specified Language,特定領域的語言 http request body: 請求體,能夠用json的格式來構建查詢語法,比較方便,能夠構建各類複雜的語法,比query string search確定強大多了
查詢全部的商品
GET /ecommerce/product/_search { "query": { "match_all": {} } }
查詢名稱包含yagao的商品,同時按照價格降序排序
GET /ecommerce/product/_search { "query" : { "match" : { "name" : "yagao" } }, "sort": [ { "price": "desc" } ] }
分頁查詢商品,總共3條商品,假設每頁就顯示1條商品,如今顯示第2頁,因此就查出來第2個商品
GET /ecommerce/product/_search { "query": { "match_all": {} }, "from": 1, "size": 1 }
指定要查詢出來商品的名稱和價格就能夠
GET /ecommerce/product/search { "query": { "match_all": {} }, "source": ["name", "price"] }
PS: 更加適合生產環境的使用,能夠構建複雜的查詢
搜索商品名稱包含yagao,並且售價大於25元的商品
GET /ecommerce/product/_search { "query" : { "bool" : { "must" : { "match" : { "name" : "yagao" } }, "filter" : { "range" : { "price" : { "gt" : 25 } } } } } }
全文檢索會將輸入的搜索串拆解開來,去倒排索引裏面去一一匹配,只要能匹配上任意一個拆解後的單詞,就能夠做爲結果返回。
GET /ecommerce/product/_search { "query" : { "match" : { "producer" : "yagao producer" } } }
Result:
{ "took": 4, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 4, "max_score": 0.70293105, //最高分,匹配度最高的那個 "hits": [ { "_index": "ecommerce", "_type": "product", "_id": "4", "_score": 0.70293105, "_source": { "name": "special yagao", "desc": "special meibai", "price": 50, "producer": "special yagao producer", "tags": [ "meibai" ] } }, { "_index": "ecommerce", "_type": "product", "_id": "1", "_score": 0.25811607, "_source": { "name": "gaolujie yagao", "desc": "gaoxiao meibai", "price": 30, "producer": "gaolujie producer", "tags": [ "meibai", "fangzhu" ] } }, { "_index": "ecommerce", "_type": "product", "_id": "3", "_score": 0.25811607, "_source": { "name": "zhonghua yagao", "desc": "caoben zhiwu", "price": 40, "producer": "zhonghua producer", "tags": [ "qingxin" ] } }, { "_index": "ecommerce", "_type": "product", "_id": "2", "_score": 0.1805489, "_source": { "name": "jiajieshi yagao", "desc": "youxiao fangzhu", "price": 25, "producer": "jiajieshi producer", "tags": [ "fangzhu" ] } } ] } }
跟全文檢索相對應,相反,phrase search,要求輸入的搜索串,必須在指定的字段文本中,徹底包含如出一轍的,才能夠算匹配,才能做爲結果返回。
GET /ecommerce/product/_search { "query" : { "match_phrase" : { "producer" : "yagao producer" } } }
Return:
{ "took": 11, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 1, "max_score": 0.70293105, "hits": [ { "_index": "ecommerce", "_type": "product", "_id": "4", "_score": 0.70293105, "_source": { "name": "special yagao", "desc": "special meibai", "price": 50, "producer": "special yagao producer", "tags": [ "meibai" ] } } ] } }
GET /ecommerce/product/_search { "query" : { "match" : { "producer" : "producer" } }, "highlight": { "fields" : { "producer" : {} } } }
1.計算每一個tag下的商品數量:
GET /ecommerce/product/_search { "aggs": { "group_by_tags": { "terms": { "field": "tags" } } } }
將文本field的fielddata屬性設置爲true:
PUT /ecommerce/_mapping/product { "properties": { "tags": { "type": "text", "fielddata": true } } } GET /ecommerce/product/_search { "size": 0, "aggs": { "all_tags": { "terms": { "field": "tags" } } } } { "took": 20, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 4, "max_score": 0, "hits": [] }, "aggregations": { "group_by_tags": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "fangzhu", "doc_count": 2 }, { "key": "meibai", "doc_count": 2 }, { "key": "qingxin", "doc_count": 1 } ] } } }
2.對名稱中包含yagao的商品,計算每一個tag下的商品數量
GET /ecommerce/product/_search { "size": 0, "query": { "match": { "name": "yagao" } }, "aggs": { "all_tags": { "terms": { "field": "tags" } } } }
3.計算每一個tag下的商品的平均價格,而且按照平均價格降序排序
GET /ecommerce/product/_search { "size": 0, "aggs" : { "group_by_tags" : { "terms" : { "field" : "tags" }, "aggs" : { "avg_price" : { "avg" : { "field" : "price" } } } } } }
Result:
{ "took": 8, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 4, "max_score": 0, "hits": [] }, "aggregations": { "group_by_tags": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "fangzhu", "doc_count": 2, "avg_price": { "value": 27.5 } }, { "key": "meibai", "doc_count": 2, "avg_price": { "value": 40 } }, { "key": "qingxin", "doc_count": 1, "avg_price": { "value": 40 } } ] } } }
4.計算每一個tag下的商品的平均價格,而且按照平均價格降序排序
GET /ecommerce/product/_search { "size": 0, "aggs" : { "all_tags" : { "terms" : { "field" : "tags", "order": { "avg_price": "desc" } }, "aggs" : { "avg_price" : { "avg" : { "field" : "price" } } } } } }
5.按照指定的價格範圍區間進行分組,而後在每組內再按照tag進行分組,最後再計算每組的平均價格
GET /ecommerce/product/_search { "size": 0, "aggs": { "group_by_price": { "range": { "field": "price", "ranges": [ { "from": 0, "to": 20 }, { "from": 20, "to": 40 }, { "from": 40, "to": 50 } ] }, "aggs": { "group_by_tags": { "terms": { "field": "tags" }, "aggs": { "average_price": { "avg": { "field": "price" } } } } } } } }