為什么不能使用數(shù)據(jù)庫(kù)做搜索苍柏?
1、比方說吟温,每條記錄的指定字段的文本序仙,可能會(huì)很長(zhǎng)突颊,比如說“商品描述”字段的長(zhǎng)度鲁豪,有長(zhǎng)達(dá)數(shù)千個(gè)潘悼,甚至數(shù)萬個(gè)字符,這個(gè)時(shí)候爬橡,每次都要對(duì)每條記錄的所有文本進(jìn)行掃描治唤。
你包不包含我指定的這個(gè)關(guān)鍵詞(比如說“牙膏”)
2、還不能將搜索詞拆分開來糙申,盡可能去搜索更多的符合你的期望的結(jié)果宾添,比如輸入“生化機(jī)”,就搜索不出來“生化危機(jī)”
總的來說就是數(shù)據(jù)庫(kù)來實(shí)現(xiàn)搜索柜裸,是不太靠譜的缕陕。通常來說,性能會(huì)很差的疙挺。
另外:
(1)數(shù)據(jù)量較大扛邑,es的分布式本質(zhì),可以幫助你快速進(jìn)行擴(kuò)容铐然,承載大量數(shù)據(jù)
(2)數(shù)據(jù)結(jié)構(gòu)靈活多變蔬崩,隨時(shí)可能會(huì)變化,而且數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系搀暑,非常復(fù)雜沥阳,如果我們用傳統(tǒng)數(shù)據(jù)庫(kù),那是不是很坑自点,因?yàn)橐媾R大量的表
(3)對(duì)數(shù)據(jù)的相關(guān)操作桐罕,較為簡(jiǎn)單,比如就是一些簡(jiǎn)單的增刪改查桂敛,用我們之前講解的那些document操作就可以搞定
(4)NoSQL數(shù)據(jù)庫(kù)冈绊,適用的也是類似于上面的這種場(chǎng)景
什么是全文檢索和Lucene?
lucene埠啃,就是一個(gè)jar包死宣,里面包含了封裝好的各種建立倒排索引,以及進(jìn)行搜索的代碼碴开,包括各種算法毅该。我們就用java開發(fā)的時(shí)候,引入lucene jar潦牛,然后基于lucene的api進(jìn)行去進(jìn)行開發(fā)就可以了眶掌。
用lucene,我們就可以去將已有的數(shù)據(jù)建立索引巴碗,lucene會(huì)在本地磁盤上面朴爬,給我們組織索引的數(shù)據(jù)結(jié)構(gòu)。另外的話橡淆,我們也可以用lucene提供的一些功能和api來針對(duì)磁盤上進(jìn)行操作和查詢召噩。
什么是Elasticsearch母赵?
Elasticsearch的功能,干什么的
(1)分布式的搜索引擎和數(shù)據(jù)分析引擎
搜索:百度具滴,網(wǎng)站的站內(nèi)搜索凹嘲,IT系統(tǒng)的檢索
數(shù)據(jù)分析:電商網(wǎng)站,最近7天牙膏這種商品銷量排名前10的商家有哪些构韵;新聞網(wǎng)站周蹭,最近1個(gè)月訪問量排名前3的新聞版塊是哪些
分布式,搜索疲恢,數(shù)據(jù)分析
(2)全文檢索凶朗,結(jié)構(gòu)化檢索,數(shù)據(jù)分析
全文檢索:我想搜索商品名稱包含牙膏的商品显拳,select * from products where product_name like "%牙膏%"
結(jié)構(gòu)化檢索:我想搜索商品分類為日化用品的商品都有哪些俱尼,select * from products where category_id='日化用品'
部分匹配、自動(dòng)完成萎攒、搜索糾錯(cuò)遇八、搜索推薦
數(shù)據(jù)分析:我們分析每一個(gè)商品分類下有多少個(gè)商品,select category_id,count(*) from products group by category_id
(3)對(duì)海量數(shù)據(jù)進(jìn)行近實(shí)時(shí)的處理
分布式:ES自動(dòng)可以將海量數(shù)據(jù)分散到多臺(tái)服務(wù)器上去存儲(chǔ)和檢索
海聯(lián)數(shù)據(jù)的處理:分布式以后耍休,就可以采用大量的服務(wù)器去存儲(chǔ)和檢索數(shù)據(jù)刃永,自然而然就可以實(shí)現(xiàn)海量數(shù)據(jù)的處理了
近實(shí)時(shí):檢索個(gè)數(shù)據(jù)要花費(fèi)1小時(shí)(這就不要近實(shí)時(shí),離線批處理羊精,batch-processing)斯够;在秒級(jí)別對(duì)數(shù)據(jù)進(jìn)行搜索和分析
跟分布式/海量數(shù)據(jù)相反的:lucene,單機(jī)應(yīng)用喧锦,只能在單臺(tái)服務(wù)器上使用读规,最多只能處理單臺(tái)服務(wù)器可以處理的數(shù)據(jù)量
elasticsearch的核心概念
(1)Near Realtime(RT):近實(shí)時(shí),數(shù)據(jù)被寫入到es 到可以被搜索到這個(gè)時(shí)間 在一秒內(nèi)可以完成燃少。
(2)Cluster:集群束亏,包含多個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)屬于哪個(gè)集群是通過一個(gè)配置(集群名稱阵具,默認(rèn)是elasticsearch)來決定的碍遍,對(duì)于中小型應(yīng)用來說,剛開始一個(gè)集群就一個(gè)節(jié)點(diǎn)很正常
(3)Node:節(jié)點(diǎn)阳液,集群中的一個(gè)節(jié)點(diǎn)怕敬,節(jié)點(diǎn)也有一個(gè)名稱(默認(rèn)是隨機(jī)分配的),節(jié)點(diǎn)名稱很重要(在執(zhí)行運(yùn)維管理操作的時(shí)候)帘皿,默認(rèn)節(jié)點(diǎn)會(huì)去加入一個(gè)名稱為“elasticsearch”的集群东跪,如果直接啟動(dòng)一堆節(jié)點(diǎn),那么它們會(huì)自動(dòng)組成一個(gè)elasticsearch集群,當(dāng)然一個(gè)節(jié)點(diǎn)也可以組成一個(gè)elasticsearch集群
(4)Document&field:文檔虽填,es中的最小數(shù)據(jù)單元丁恭,一個(gè)document可以是一條客戶數(shù)據(jù),一條商品分類數(shù)據(jù)卤唉,一條訂單數(shù)據(jù)涩惑,通常用JSON數(shù)據(jù)結(jié)構(gòu)表示仁期,
每個(gè)index下的type中桑驱,都可以去存儲(chǔ)多個(gè)document。一個(gè)document里面有多個(gè)field跛蛋,每個(gè)field就是一個(gè)數(shù)據(jù)字段熬的。
product document
{
"product_id": "1",
"product_name": "高露潔牙膏",
"product_desc": "高效美白",
"category_id": "2",
"category_name": "日化用品"
}
(5)Index:索引,包含一堆有相似結(jié)構(gòu)的文檔數(shù)據(jù)赊级,比如可以有一個(gè)客戶索引押框,商品分類索引,訂單索引理逊,索引有一個(gè)名稱橡伞。一個(gè)index包含很多document,一個(gè)index就代表了一類類似的或者相同的document晋被。比如說建立一個(gè)product index兑徘,商品索引,里面可能就存放了所有的商品數(shù)據(jù)羡洛,所有的商品document挂脑。
(6)Type:類型,每個(gè)索引里都可以有一個(gè)或多個(gè)type欲侮,type是index中的一個(gè)邏輯數(shù)據(jù)分類崭闲,一個(gè)type下的document,都有相同的field威蕉,比如博客系統(tǒng)刁俭,有一個(gè)索引,可以定義用戶數(shù)據(jù)type韧涨,博客數(shù)據(jù)type薄翅,評(píng)論數(shù)據(jù)type。
type氓奈,日化商品type翘魄,電器商品type,生鮮商品type
日化商品type:product_id舀奶,product_name暑竟,product_desc,category_id,category_name
電器商品type:product_id但荤,product_name罗岖,product_desc,category_id腹躁,category_name桑包,service_period
生鮮商品type:product_id,product_name纺非,product_desc哑了,category_id,category_name烧颖,eat_period
每一個(gè)type里面弱左,都會(huì)包含一堆document,類型于數(shù)據(jù)庫(kù)中炕淮,這里的每一行數(shù)據(jù)就是一個(gè)document拆火,
{
"product_id": "2",
"product_name": "長(zhǎng)虹電視機(jī)",
"product_desc": "4k高清",
"category_id": "3",
"category_name": "電器",
"service_period": "1年"
}
{
"product_id": "3",
"product_name": "基圍蝦",
"product_desc": "純天然,冰島產(chǎn)",
"category_id": "4",
"category_name": "生鮮",
"eat_period": "7天"
}
(7)shard:?jiǎn)闻_(tái)機(jī)器無法存儲(chǔ)大量數(shù)據(jù)涂圆,es可以將一個(gè)索引中的數(shù)據(jù)切分為多個(gè)shard们镜,分布在多臺(tái)服務(wù)器上存儲(chǔ)。有了shard就可以橫向擴(kuò)展润歉,存儲(chǔ)更多數(shù)據(jù)模狭,讓搜索和分析等操作分布到多臺(tái)服務(wù)器上去執(zhí)行,提升吞吐量和性能卡辰。每個(gè)shard都是一個(gè)lucene index胞皱。
(8)replica:任何一個(gè)服務(wù)器隨時(shí)可能故障或宕機(jī),此時(shí)shard可能就會(huì)丟失九妈,因此可以為每個(gè)shard創(chuàng)建多個(gè)replica副本反砌。replica可以在shard故障時(shí)提供備用服務(wù),保證數(shù)據(jù)不丟失萌朱,多個(gè)replica還可以提升搜索操作的吞吐量和性能宴树。primary shard(建立索引時(shí)一次設(shè)置,不能修改晶疼,默認(rèn)5個(gè))酒贬,replica shard(隨時(shí)修改數(shù)量,默認(rèn)1個(gè))翠霍,默認(rèn)每個(gè)索引10個(gè)shard锭吨,5個(gè)primary shard,5個(gè)replica shard寒匙,最小的高可用配置零如,是2臺(tái)服務(wù)器。
elasticsearch核心概念 vs. 數(shù)據(jù)庫(kù)核心概念
Elasticsearch | 數(shù)據(jù)庫(kù) |
---|---|
Index | 庫(kù) |
Type | 表 |
Document | 行 |
Filed | 列 |
windows 下使用es
先安裝java環(huán)境,至少JDK1.8考蕾,分別下載解壓 elasticsearch-5.2.0.zip祸憋,kibana-5.2.0-windows-x86.zip,進(jìn)入到各自bin目錄下肖卧,啟動(dòng)elasticsearch.bat蚯窥,kibana.bat腳本,
檢驗(yàn)是否啟動(dòng)成功http://localhost:9200/?pretty
http://localhost:5601/
es中的數(shù)據(jù)與關(guān)系型db中的數(shù)據(jù)
對(duì)象數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)中塞帐,只能拆解開來拦赠,變?yōu)楸馄降亩鄰埍恚看尾樵兊臅r(shí)候還得還原回對(duì)象格式壁榕,相當(dāng)麻煩矛紫。ES是面向文檔的赎瞎,文檔中存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu)牌里,與面向?qū)ο蟮臄?shù)據(jù)結(jié)構(gòu)是一樣的,基于這種文檔數(shù)據(jù)結(jié)構(gòu)务甥,es可以提供復(fù)雜的索引牡辽,全文檢索,分析聚合等功能
如以下es 中的數(shù)據(jù)
{
"email": "zhangsan@sina.com",
"first_name": "san",
"last_name": "zhang",
"info": {
"bio": "curious and modest",
"age": 30,
"interests": [ "bike", "climb" ]
},
"join_date": "2017/01/01"
}
es存儲(chǔ)的數(shù)據(jù)基本與客戶端提交上來的面向?qū)ο髷?shù)據(jù)一致敞临,但是假設(shè)我們將這個(gè)數(shù)據(jù)持久化到mysql中态辛,我們需要建立兩張表 然后用一個(gè)字段來關(guān)聯(lián)起來。
es API
- cat api
GET /_cat/health?v
如何快速了解集群的健康狀況挺尿?green奏黑、yellow、red编矾?
green:每個(gè)索引的primary shard和replica shard都是active狀態(tài)的
yellow:每個(gè)索引的primary shard都是active狀態(tài)的熟史,但是部分replica shard不是active狀態(tài),處于不可用的狀態(tài)
red:不是所有索引的primary shard都是active狀態(tài)的窄俏,部分索引有數(shù)據(jù)丟失了
- 快速查看集群中有哪些索引
GET /_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open .kibana Sonk96QMSgmP7seyOVhx8A 1 1 1 0 3.1kb 3.1kb
- (1)新增商品:新增文檔蹂匹,建立索引。 es會(huì)自動(dòng)建立index和type凹蜈,不需要提前創(chuàng)建限寞,而且es默認(rèn)會(huì)對(duì)document每個(gè)field都建立倒排索引,讓其可以被搜索
語(yǔ)法:
PUT /index/type/id
{
"json數(shù)據(jù)"
}
PUT /ecommerce/product/1
{
"name" : "gaolujie yagao",
"desc" : "gaoxiao meibai",
"price" : 30,
"producer" : "gaolujie producer",
"tags": [ "meibai", "fangzhu" ]
}
// 返回以下數(shù)據(jù)
{
"_index": "ecommerce",
"_type": "product",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
- (2)查詢商品:檢索文檔
語(yǔ)法: GET /index/type/id
GET /ecommerce/product/1
{
"_index": "ecommerce",
"_type": "product",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"name": "gaolujie yagao",
"desc": "gaoxiao meibai",
"price": 30,
"producer": "gaolujie producer",
"tags": [
"meibai",
"fangzhu"
]
}
}
- (3)修改商品:替換文檔
PUT /ecommerce/product/1
{
"name" : "jiaqiangban gaolujie yagao",
"desc" : "gaoxiao meibai",
"price" : 30,
"producer" : "gaolujie producer",
"tags": [ "meibai", "fangzhu" ]
}
修改數(shù)據(jù)的時(shí)候 用這種方式仰坦,有一個(gè)容易出業(yè)務(wù)
bug
的地方是 其他字段會(huì)被清空履植。如下面的命令執(zhí)行之后 這個(gè)數(shù)據(jù)就只剩下name 這一個(gè)filed了,其他沒了悄晃。修改數(shù)據(jù)主post會(huì)比較好一點(diǎn)
PUT /ecommerce/product/1
{
"name" : "jiaqiangban gaolujie yagao"
}
- (4)修改商品:更新文檔 (推薦)玫霎,也叫 partial update 語(yǔ)法
POST /ecommerce/product/1/_update
{
"doc": {
"name": "jiaqiangban gaolujie yagao"
}
}
- (5)刪除商品:刪除文檔
語(yǔ)法 DELETE /ecommerce/product/1
DELETE /ecommerce/product/1
{
"found": true,
"_index": "ecommerce",
"_type": "product",
"_id": "1",
"_version": 9,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
多種搜索方式
- 1、query string search --這種方式幾乎不會(huì)用
搜索商品名稱中包含yagao的商品,而且按照售價(jià)降序排序:GET /ecommerce/product/_search?q=name:yagao&sort=price:desc
query string search的由來鼠渺,因?yàn)閟earch參數(shù)都是以http請(qǐng)求的query string來附帶的 - 2鸭巴、query DSL , DSL:Domain Specified Language拦盹,特定領(lǐng)域的語(yǔ)言 --這種方式更好用
查詢所有的商品
GET /ecommerce/product/_search
{
"query": { "match_all": {} }
}
查詢名稱包含yagao的商品鹃祖,同時(shí)按照價(jià)格降序排序
GET /ecommerce/product/_search
{
"query" : {
"match" : {
"name" : "yagao"
}
},
"sort": [
{ "price": "desc" }
]
}
分頁(yè)查詢商品,總共3條商品普舆,假設(shè)每頁(yè)就顯示1條商品恬口,現(xiàn)在顯示第2頁(yè),所以就查出來第2個(gè)商品
GET /ecommerce/product/_search
{
"query": { "match_all": {} },
"from": 1,
"size": 1
}
不查詢所有列沼侣,指定特定的列 下面只查詢name和price列
GET /ecommerce/product/_search
{
"query": { "match_all": {} },
"_source": ["name", "price"]
}
- 3祖能、query filter
搜索商品名稱包含yagao,而且售價(jià)大于25元的商品
GET /ecommerce/product/_search
{
"query" : {
"bool" : {
"must" : {
"match" : {
"name" : "yagao"
}
},
"filter" : {
"range" : {
"price" : { "gt" : 25 }
}
}
}
}
}
- 4蛾洛,full-text search(全文檢索)這里與之前的區(qū)別是"match" 內(nèi)的字段的值是兩個(gè)詞
GET /ecommerce/product/_search
{
"query" : {
"match" : {
"producer" : "yagao producer"
}
}
}
producer 這個(gè)字段养铸,會(huì)先被拆解,建立倒排索引
special 4
yagao 4
producer 1,2,3,4
gaoluie 1
zhognhua 3
jiajieshi 2
可以看出 最終的結(jié)果第一條肯定是4 因?yàn)?既包含yagao也包含producer
- 5轧膘、phrase search(短語(yǔ)搜索)
跟全文檢索相對(duì)應(yīng)钞螟,相反,全文檢索會(huì)將輸入的搜索串拆解開來谎碍,去倒排索引里面去一一匹配鳞滨,只要能匹配上任意一個(gè)拆解后的單詞,就可以作為結(jié)果返回
phrase search蟆淀,要求輸入的搜索串拯啦,必須在指定的字段文本中,完全包含一模一樣的熔任,才可以算匹配褒链,才能作為結(jié)果返回
GET /ecommerce/product/_search
{
"query" : {
"match_phrase" : {
"producer" : "yagao producer"
}
}
}
- 6、highlight search(高亮搜索結(jié)果)
GET /ecommerce/product/_search
{
"query" : {
"match" : {
"producer" : "producer"
}
},
"highlight": {
"fields" : {
"producer" : {}
}
}
}
嵌套聚合笋敞,下鉆分析碱蒙,聚合分析
- 1, 計(jì)算每個(gè)tag下的商品數(shù)量 根據(jù)tags字段分組顯示其數(shù)量
GET /ecommerce/product/_search
{
"size": 0,
"aggs": {
"all_tags": {
"terms": { "field": "tags" }
}
}
}
- 2夯巷,對(duì)名稱中包含yagao的商品赛惩,計(jì)算每個(gè)tag下的商品數(shù)量 (先搜索再分析)
GET /ecommerce/product/_search
{
"size": 0,
"query": {
"match": {
"name": "yagao"
}
},
"aggs": {
"all_tags": {
"terms": {
"field": "tags"
}
}
}
}
- 3,先分組趁餐,再算每組的平均值喷兼,計(jì)算每個(gè)tag下的商品的平均價(jià)格
GET /ecommerce/product/_search
{
"size": 0,
"aggs" : {
"group_by_tags" : {
"terms" : { "field" : "tags" },
"aggs" : {
"avg_price" : {
"avg" : { "field" : "price" }
}
}
}
}
}
- 4,計(jì)算每個(gè)tag下的商品的平均價(jià)格后雷,并且按照平均價(jià)格降序排序
GET /ecommerce/product/_search
{
"size": 0,
"aggs" : {
"all_tags" : {
"terms" : { "field" : "tags", "order": { "avg_price": "desc" } },
"aggs" : {
"avg_price" : {
"avg" : { "field" : "price" }
}
}
}
}
}
- 5季惯,按照指定的價(jià)格范圍區(qū)間進(jìn)行分組吠各,然后在每組內(nèi)再按照tag進(jìn)行分組,最后再計(jì)算每組的平均價(jià)格
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"
}
}
}
}
}
}
}
}