全文检索Elasticsearch研究
全文檢索Elasticsearch研究
基于虛擬機(jī)服務(wù)器自主部署ELK服務(wù)
學(xué)習(xí)目標(biāo)
-
了解Elasticsearch的應(yīng)用場景 -
學(xué)習(xí)基于服務(wù)器部署ELK服務(wù) -
掌握索引維護(hù)的方法 -
掌握索引維護(hù)的方法 -
掌握基本的搜索API的使用方法
約束
需要提前掌握Lucene的索引方法、搜索方法
ELK的介紹和安裝
1.簡介
? Elasticsearch是一個(gè)基于Lucene的搜索服務(wù)器,它提供了一個(gè)分布式多用戶能力的全文搜索引擎,基于Restful web接口。Elasticsearch是用java開發(fā)的,是當(dāng)前流行的企業(yè)級(jí)搜索引擎。能到達(dá)到實(shí)時(shí)搜索,穩(wěn)定、可靠、快速、安裝使用方便。
? 我們建立一個(gè)網(wǎng)站或應(yīng)用程序,并要添加搜索功能,如果搜索的數(shù)量非常多,而且分類繁雜,如果使用傳統(tǒng)的數(shù)據(jù)庫想要完成搜索工作的創(chuàng)建失非常困難的。我們希望搜索解決方案要運(yùn)行速度快,我們希望有一個(gè)零配置和完全免費(fèi)的搜索模式,能夠簡單的使用JSON通過HTTP來索引數(shù)據(jù),而搜索服務(wù)器始終可用,并且服務(wù)器可以自如擴(kuò)展,我們一般都會(huì)使用全文檢索技術(shù),如solr、Elasticsearch等。
2.突出優(yōu)點(diǎn)
-
擴(kuò)展性好,可部署上百臺(tái)服務(wù)器集群,處理PB級(jí)數(shù)據(jù) -
近實(shí)時(shí)的去索引數(shù)據(jù)、搜索數(shù)據(jù)
3.原理與應(yīng)用
3.1 索引結(jié)構(gòu)
下圖是ElasticSearch的索引結(jié)構(gòu),下邊==黑色部分是物理結(jié)構(gòu)==,上邊==黃色部分是邏輯結(jié)構(gòu)==,邏輯結(jié)構(gòu)可以更好的描述ElasticSearch的工作原理及去使用物理結(jié)構(gòu)中的索引文件。
邏輯結(jié)構(gòu)部分是一個(gè)倒排索引表:
-
將要搜索的文檔內(nèi)容分詞,所有不重復(fù)的詞做成分詞列表。 -
將搜索的文檔最終以Document方式存儲(chǔ)起來。 -
每個(gè)詞和document都有關(guān)聯(lián)。
3.2 RESTFUL應(yīng)用方法
ElasticSearch提供RESTFUL Api接口進(jìn)行索引、搜索、并且支持多種客戶端。
下圖是ElasticSearch在項(xiàng)目中的應(yīng)用方式:
-
用戶在前端搜索關(guān)鍵字 -
項(xiàng)目前端通過http方式請(qǐng)求項(xiàng)目服務(wù)端 -
項(xiàng)目服務(wù)端通過http RESTful方式請(qǐng)求ES集群進(jìn)行搜索 -
ES集群從索引庫檢索數(shù)據(jù)
4.ElasticaSearc安裝
4.1 安裝配置
-
安裝ElasticaSearc7.9.0 -
該版本要求至少jdk1.8以上 -
解壓elasticsearch-7.9.0-linux-x86_64.tar.gz -
bin:腳本目錄,包括:啟動(dòng)、停止等可執(zhí)行腳本 -
config:配置文件目錄 -
data:索引目錄,存放索引文件的地方 -
modules:模板目錄,包括了es的功能模塊 -
plugins:插件目錄,es支持插件機(jī)制
-
4.2 配置文件
ES配置文件的地址根據(jù)安裝形式的不同而不同:
-
使用zip、tar安裝,配置文件的地址在安裝目錄的config下 -
使用RPM安裝,配置文件在/etc/elasticsearch下 -
使用MSI安裝,配置文件的地址在安裝目錄的config下,并且會(huì)自動(dòng)將config目錄地址寫入環(huán)境變量ES_PATH_CONF
4.3 安裝
為了模擬真實(shí)場景,我們將在linux系統(tǒng)下安裝Elasticsearch
4.3.1 新建一個(gè)用戶gavin
處于安全考慮,Elasticsearch默認(rèn)不允許以root賬號(hào)運(yùn)行
創(chuàng)建用戶:
useradd gavin
設(shè)置密碼:
passwd gavin
切換用戶:
su gavin
刪除用戶:
userdel -r gavin
普通用戶增加sudo命令的權(quán)限:
vim /etc/sudoers
gavin ALL=(ALL) ALL
改變目錄及其目錄下所有文件的所有者為當(dāng)前普通用戶:
chown -R yourname dirname
4.3.3 解壓縮
tar -zxvf elasticsearch-7.9.0-linux-x86_64.tar.gz
4.3.4 目錄重命名
mv elasticsearch-7.9.0 elasticsearch
4.3.5 修改配置文件
進(jìn)入config目錄,修改elasticsearch.yml和jvm.options
-
jvm.options
默認(rèn)配置:
-Xms1g
-Xmx1g
內(nèi)存占用太多,設(shè)置為不超過物理內(nèi)存的一半:
-Xms512m
-Xmx512m
-
elasticsearch.yml
修改數(shù)據(jù)和日志目錄
# 數(shù)據(jù)目錄位置
path.data: /home/gavin/elasticsearch/data
# 日志目錄位置
path.logs: /home/gavin/elasticsearch/logs
elasticsearch的安裝目錄默認(rèn)只有logs目錄,沒有data目錄,需要手動(dòng)創(chuàng)建:
mkdir data
修改綁定的ip:
# 綁定0.0.0.0 允許任何ip來訪問,默認(rèn)只允許本機(jī)訪問
network.host: 0.0.0.0
目前我們是學(xué)習(xí)單機(jī)安裝,如果要做集群,只需要在這個(gè)配置文件中添加節(jié)點(diǎn)信息即可。
| 屬性名 | 說明 |
|---|---|
| cluster.name | 配置elasticsearch的集群名稱,默認(rèn)是elasticsearch。建議修改成一個(gè)有意義的名稱。 |
| node.name | 節(jié)點(diǎn)名,es會(huì)默認(rèn)隨機(jī)指定一個(gè)名字,建議指定一個(gè)有意義的名稱,方便管理 |
| path.conf | 設(shè)置配置文件的存儲(chǔ)路徑,tar或zip包安裝默認(rèn)在es根目錄下的config文件夾,rpm安裝默認(rèn)在/etc/ elasticsearch |
| path.data | 設(shè)置索引數(shù)據(jù)的存儲(chǔ)路徑,默認(rèn)是es根目錄下的data文件夾,可以設(shè)置多個(gè)存儲(chǔ)路徑,用逗號(hào)隔開 |
| path.logs | 設(shè)置日志文件的存儲(chǔ)路徑,默認(rèn)是es根目錄下的logs文件夾 |
| path.plugins | 設(shè)置插件的存放路徑,默認(rèn)是es根目錄下的plugins文件夾 |
| bootstrap.memory_lock | 設(shè)置為true可以鎖住ES使用的內(nèi)存,避免內(nèi)存進(jìn)行swap |
| network.host | 設(shè)置bind_host和publish_host,設(shè)置為0.0.0.0允許外網(wǎng)訪問 |
| http.port | 設(shè)置對(duì)外服務(wù)的http端口,默認(rèn)為9200。 |
| transport.tcp.port | 集群結(jié)點(diǎn)之間通信端口 |
| discovery.zen.ping.timeout | 設(shè)置ES自動(dòng)發(fā)現(xiàn)節(jié)點(diǎn)連接超時(shí)的時(shí)間,默認(rèn)為3秒,如果網(wǎng)絡(luò)延遲高可設(shè)置大些 |
| discovery.zen.minimum_master_nodes | 主結(jié)點(diǎn)數(shù)量的最少值 ,此值的公式為:(master_eligible_nodes / 2) + 1 ,比如:有3個(gè)符合要求的主結(jié)點(diǎn),那么這里要設(shè)置為2 |
4.4 運(yùn)行
進(jìn)入elasticsearch/bin*目錄下,可以看到如下的可執(zhí)行文件:
然后輸入運(yùn)行命令:
./elasticsearch
4.5 啟動(dòng)報(bào)錯(cuò)
4.5.1 JDK版本過低 并且 不支持 root用戶啟動(dòng)
解決方案:
1.因?yàn)閑lasticsearch7.9.X內(nèi)置了jdk,默認(rèn)是jdk11,但是向下兼容,所以可以不用處理
2.切換到普通用戶進(jìn)行啟動(dòng),此時(shí)需要修改文件目錄下所有文件的所有者為當(dāng)前用戶。
chown?-R?gavin?/home/gavin/elasticsearch
4.5.2 集群節(jié)點(diǎn)導(dǎo)致啟動(dòng)報(bào)錯(cuò)
解決:
vim elasticsearch.yml
ip替換host1等,多節(jié)點(diǎn)請(qǐng)?zhí)砑佣鄠€(gè)ip地址,單節(jié)點(diǎn)可寫按默認(rèn)來
#配置以下三者,最少其一
#[discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes]
cluster.initial_master_nodes: ["node-1"] #這里的node-1為node-name配置的值
啟動(dòng)成功:
可以看到綁定了兩個(gè)端口:
-
9200:客戶端訪問端口 -
9300:集群節(jié)點(diǎn)之間通訊端口
我們在瀏覽器中訪問:http://192.168.15.100:9200/
5.安裝kibana
kibana是一個(gè)基于Node.js的Elasticsearch索引庫數(shù)據(jù)統(tǒng)計(jì)工具,可以利用Elasticsearch的聚合功能,生成各種圖表,如柱狀圖、線狀圖、餅圖等。
而且還提供了操作Elasticsearch索引數(shù)據(jù)的控制臺(tái),并且提供了一定的API提示,非常有利于學(xué)習(xí)Elasticsearch的語法。
5.1 安裝
因?yàn)镵ibana是依賴于node
查看是否服務(wù)器是否安裝nodejs
[root@centos logs]# node -v
v9.3.0
如果沒有安裝,則安裝步驟如下:
1.可以在下載頁面https://nodejs.org/en/download/中找到下載地址,然后執(zhí)行指令
wget https://nodejs.org/dist/v9.3.0/node-v9.3.0-linux-x64.tar.xz
2.解壓縮
xz?-d?node-v9.3.0-linux-x64.tar.xz
tar?-xf?node-v9.3.0-linux-x64.tar
3.部署bin文件
根據(jù)自己nodejs的實(shí)際路徑,依次執(zhí)行下面命令,建立軟連接:
ln -s /usr/local/software/node/bin/node /usr/bin/node
ln -s /usr/local/software/node/bin/npm /usr/bin/npm
ln -s /usr/local/software/node/bin/npx /usr/bin/npx
4.測試
node -v
npm -v
npx -v
5.1.1 解壓縮kibana
tar -zxvf kibana-7.9.0-linux-x86_64.tar.gz
5.1.2 重命名安裝包
mv?kibana-7.9.0-linux-x86_64?kibana
5.1.3 修改配置
vim /home/gavin/kibana/config/kibana.yml
elasticsearch.hosts:?["http://192.168.15.100:9200"]
5.2 啟動(dòng)
cd /home/gavin/kibana/bin
./kibana
6.安裝ik分析器
Lucene的IK分詞器早在2012年就已經(jīng)沒有維護(hù)了,現(xiàn)在我們要使用的是在其基礎(chǔ)上維護(hù)升級(jí)的版本,并且開發(fā)為ElasticSearch的繼承插件了,與ElasticSearch一起維護(hù)升級(jí)了,版本也保持一致。
6.1 解壓縮
unzip?elasticsearch-analysis-ik-7.9.0.zip?-d?/home/gavin/kibana/plugins/ik-analyzer
6.2 重啟elasticsearch
加載IK分詞器插件、
6.3 測試
在Dev Tools --> console 中輸入下面請(qǐng)求:
POST?_analyze
{
??"analyzer":?"ik_max_word",
??"text":?????"我是中國人"
}
API
Elasticsearch提供了Rest風(fēng)格的API,即http請(qǐng)求接口,而且也提供了各種語言的客戶端API
文檔地址:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
1.客戶端API
Elasticsearch支持的客戶端非常多,如:https://www.elastic.co/guide/en/elasticsearch/client/index.html
點(diǎn)開Java Rest Client后,會(huì)有兩個(gè):
-
Java Low Level REST Client:是低級(jí)別封裝,提供一些基礎(chǔ)功能,但更靈活 -
Java High Level REST Client:是在Low Level Rest Client基礎(chǔ)上進(jìn)行的高級(jí)別封裝,功能更豐富和完善,而且API會(huì)變得簡單
2.如何學(xué)習(xí)
2.1 操作索引
Elasticsearch是基于Lucene的全文檢索庫,本質(zhì)也是存儲(chǔ)數(shù)據(jù),很多概念與mysql類似
對(duì)比關(guān)系:
索引(indices) --------------------------------------------- Databases 數(shù)據(jù)庫
? 類型(type) ------------------------------------------ Table 數(shù)據(jù)表
? 文檔(Document) ---------------------------Row 行
? 字段(field) -----------------------------Columns 列
說明:
| 概念 | 說明 |
|---|---|
| 索引庫(indices) | indices是index的復(fù)數(shù),代表許多的索引 |
| 類型(type) | 類型是模擬mysql中的table概念,一個(gè)索引庫下可以有不同類型的索引,比如商品索引、訂單索引,其數(shù)據(jù)格式不同。不過這會(huì)導(dǎo)致索引庫混亂,因此未來版本中會(huì)移除這個(gè)概念 |
| 文檔(document) | 存入索引庫原始的數(shù)據(jù)。比如每一條商品信息,就是一個(gè)文檔 |
| 字段(field) | 文檔中的屬性 |
| 映射配置(mappings) | 字段的數(shù)據(jù)類型,屬性、是否索引、是否存儲(chǔ)等特性 |
特別說明:
Elasticsearch本身就是分布式的,因此即便你只有一個(gè)節(jié)點(diǎn),Elasticsearch默認(rèn)也會(huì)對(duì)你的數(shù)據(jù)進(jìn)行分片和副本操作,當(dāng)你向集群添加新數(shù)據(jù)時(shí),數(shù)據(jù)也會(huì)在新加入的節(jié)點(diǎn)中進(jìn)行平衡
2.2語法
Elasticsearch采用Rest風(fēng)格API,因此其API就是一次http請(qǐng)求,可以使用任何工具進(jìn)行發(fā)起http請(qǐng)求
2.1.1 索引庫設(shè)置
-
創(chuàng)建索引索引庫設(shè)置:
-
請(qǐng)求方式:PUT
-
請(qǐng)求路徑:/索引名
-
請(qǐng)求參數(shù):json格式:
{
????"settings":?{
????????"number_of_shards":?3,
????????"number_of_replicas":?2
??????}
}settings:索引庫的設(shè)置
number_of_shards:分片數(shù)量
number_of_replicas:副本數(shù)量
測試
-
使用postman進(jìn)行創(chuàng)建索引并對(duì)索引庫進(jìn)行設(shè)置測試
-
? 2. 使用kibana進(jìn)行創(chuàng)建索引并對(duì)索引庫進(jìn)行設(shè)置測試
-
查看索引庫設(shè)置
語法:
GET?ceshi
或者,使用*來查詢所有索引配置:
-
刪除索引庫設(shè)置
語法:
DELETE?/索引庫名
再次查看
2.1.2 映射配置
索引庫創(chuàng)建好之后就是添加數(shù)據(jù),再添加數(shù)據(jù)之前必須定義映射
映射:
定義文檔的過程,文檔包含哪些字段,這些字段是否保存、是否索引、是否分詞等
-
創(chuàng)建映射字段
語法:
請(qǐng)求方式是PUT,類型名稱和_mapping可以互換位置
PUT?/索引庫名稱/_doc/類型名稱
{
??"properties":?{
????"type":?"類型",
????"index":?true,
????"store":?true,
????"analyzer":?"分詞器"
??}
}類型:就是前面提過的type的概念,類似于數(shù)據(jù)庫中的不同表
字段名:任意填寫,可以指定很多屬性,如:
-
type:類型,可以是text、long、short、date、integer、object等 -
index:是否索引,默認(rèn)為true -
store:是否存儲(chǔ),默認(rèn)是false -
analyzer:分詞器,這里的 ik_max_word即表示使用ik分詞器
-
示例:
? 請(qǐng)求:
PUT?ceshi/_doc/goods
{
??"properties":?{
????"title":?{
??????"type":?"text",
??????"analyzer":?"ik_max_word"
????},
????"images":?{
??????"type":?"keyword",
??????"index":?false
????},
????"price":?{
??????"type":?"float"
????}
??}
}
特別說明:
傳統(tǒng)ES6創(chuàng)建映射的時(shí)候是把上面的**_doc換成_mapping**
ES7這個(gè)**_mapping已經(jīng)移除了,使用_doc**代替
否則會(huì)報(bào)如下錯(cuò)誤:
? 響應(yīng)結(jié)果:
{
??"_index"?:?"ceshi",
??"_type"?:?"_doc",
??"_id"?:?"goods",
??"_version"?:?3,
??"result"?:?"created",
??"_shards"?:?{
????"total"?:?2,
????"successful"?:?1,
????"failed"?:?0
??},
??"_seq_no"?:?2,
??"_primary_term"?:?1
}
-
查看映射關(guān)系
語法:
GET?索引庫名/_mapping示例:
GET?ceshi/_mapping結(jié)果:
-
字段屬性詳解
-
3.1 type
Elasticsearch中支持的數(shù)據(jù)類型非常豐富
常用的說明下:
-
String類型,分為兩種: -
text:可分詞,不可參與聚合 -
keyword:不可分詞,數(shù)據(jù)會(huì)作為完整字段進(jìn)行匹配,可以參與聚合
-
-
Numerical:數(shù)值類型,分兩類 -
基本數(shù)據(jù)類型:long、integer、short、byte、double、float、half_float -
浮點(diǎn)數(shù)的高精度類型:scaled_float -
需要指定一個(gè)精度因子,比如10或100。Elasticsearch會(huì)把真實(shí)值乘以這個(gè)因子以后存儲(chǔ),取出時(shí)再還原。
-
-
-
Date:日期類型 -
Elasticsearch可以對(duì)日期格式化為字符串存儲(chǔ),但是建議我們存儲(chǔ)為毫秒值,存儲(chǔ)為long,節(jié)省空間。
-
3.2 index
index影響字段的索引情況
-
true:字段會(huì)被索引,則可以用來進(jìn)行搜索。默認(rèn)值是 true -
false:字段不會(huì)被索引,不能用來搜索
特別說明:
index的默認(rèn)值就是
true,也就是說你不進(jìn)行任何配置,所有字段都會(huì)被索引。但是有些字段我們不希望索引的,就需要手動(dòng)設(shè)置index為false
3.3 store
是否將數(shù)據(jù)額外存儲(chǔ)
在lucene和solr中,我們設(shè)置store字段為false,那么這個(gè)字段在文檔列表中就不會(huì)有這個(gè)字段的值,用戶搜索結(jié)果中就不會(huì)顯示出來。
但在Elasticsearch中,即便設(shè)置為false,也可以搜索結(jié)果。
原因是Elasticsearch在創(chuàng)建文檔索引庫時(shí),會(huì)將文檔中的原始數(shù)據(jù)備份,保存到一個(gè)叫_source的屬性中,而且我們可以通過過濾_source來選擇哪些要顯示,哪些不顯示。
而如果設(shè)置store為true,就會(huì)在_source以外額外存儲(chǔ)一份數(shù)據(jù),多余,因此我們一般都會(huì)講store設(shè)置為false,事實(shí)上,store的默認(rèn)是就是false。
2.1.3 新增數(shù)據(jù)
1.隨機(jī)生成id
通過POST請(qǐng)求,可以向一個(gè)已經(jīng)存在的索引庫中添加數(shù)據(jù)
語法:
POST?/索引庫名/_doc/類型名
{
??"key":?"value"
}
示例:
POST?/ceshi/_doc/goods
{
??"title":?"小米手機(jī)",
??"images":?"http://image.leyou.com/12479122.jpg",
??"price":?2688.01
}
運(yùn)行結(jié)果:
查看新增數(shù)據(jù)結(jié)果
GET?/ceshi/_search
{
????"query":{
????????"match_all":{}
????}
}
_source:源文檔信息,所有數(shù)據(jù)都在里面 _id:這條文檔的唯一標(biāo)識(shí),與文檔自己的id沒有關(guān)聯(lián)
2.自定義id
如果我們在新增數(shù)據(jù)的時(shí)候指定id,可以按如下操作:
語法:
POST?/索引庫名/_doc/id
{
??"key":?"value"
}
示例:
POST?/ceshi/_doc/2
{
??"title":?"小米手機(jī)",
??"images":?"http://image.leyou.com/12479122.jpg",
??"price":?2988.02
}
2.1.4 智能判斷
在學(xué)習(xí)solr時(shí),我們在新增數(shù)據(jù)時(shí),智能使用提前批配置好映射屬性的字段,否則就會(huì)報(bào)錯(cuò)
不過在Elasticsearch中,可以不需要給索引庫設(shè)置任何的映射屬性的字段,它也可以根據(jù)輸入的數(shù)據(jù)來判斷類型,動(dòng)態(tài)添加數(shù)據(jù)映射
示例:
POST?/ceshi/_doc/3
{
????"title":"超米手機(jī)",
????"images":"http://image.leyou.com/12479122.jpg",
????"price":2899.00,
????"stock":?200,
????"saleable":true
}
我們發(fā)現(xiàn),ceshi索引庫額外增加了stock庫存和saleable是否上架兩個(gè)字段。
查看此時(shí)的索引庫映射關(guān)系
GET?ceshi/_mapping
2.1.5 修改數(shù)據(jù)
把剛才新增請(qǐng)求的方式改為PUT,就是修改了,不過修改必須指定id
id對(duì)應(yīng)文檔存在,則修改 id對(duì)應(yīng)文檔不存在,則新增
比如,我們把id為3的數(shù)據(jù)進(jìn)行修改:
PUT?/ceshi/_doc/3
{
????"title":"超大米手機(jī)",
????"images":"http://image.leyou.com/12479122.jpg",
????"price":3899.00,
????"stock":?100,
????"saleable":true
}
2.1.6 刪除數(shù)據(jù)
刪除數(shù)據(jù)使用DELETE請(qǐng)求方式,同樣,根據(jù)id進(jìn)行刪除
語法:
DELETE?/索引庫名/_doc/id
示例:
DELETE?/ceshi/_doc/1
結(jié)果:刪除id為1的索引庫數(shù)據(jù)
2.1.7 查詢數(shù)據(jù)
基本查詢 _source過濾 結(jié)果過濾 高級(jí)查詢 排序
1.基本查詢
基本語法
GET?/索引庫名/_search
{
??"query":?{
????"查詢類型":?{
??????"查詢條件":?"查詢條件值"
????}
??}
}
query:表示一個(gè)查詢對(duì)象,里面可以有不同的查詢屬性
查詢類型:如,
mastch_all、match、term、range等查詢條件:
查詢條件會(huì)根據(jù)類型的不同,寫法也有差異,后面詳細(xì)講解
2.查詢所有(match_all)
GET?/ceshi/_search
{
??"query":?{
????"match_all":?{}
??}
}
query:代表查詢對(duì)象 match_all:代表查詢所有
took:查詢花費(fèi)時(shí)間,單位是毫秒 time_out:是否超時(shí) _shards:分片信息 hits:搜索結(jié)果總覽對(duì)象
total:搜索到的總條數(shù) max_score:所有結(jié)果中文檔得分的最高分 hits:搜索結(jié)果的文檔對(duì)象數(shù)組,每個(gè)元素是一條搜索到的文檔信息
_index:索引庫 _type:文檔類型 _id:文檔id _score:文檔得分 _source:文檔的源數(shù)據(jù)
3.匹配查詢(match)
先增加一條數(shù)據(jù),便于測試
PUT?/ceshi/_doc/1
{
????"title":"小米電視4A",
????"images":"http://image.leyou.com/12479122.jpg",
????"price":1899.00
}
特別說明:增加數(shù)據(jù)使用
POST和PUT的區(qū)別
PUT:需要指定id,否則會(huì)報(bào)錯(cuò),冪等操作 POST:指定的id存在,則更新數(shù)據(jù),不存在要么自定義id,要么隨機(jī)生成,非冪等操作
從結(jié)果中看到,索引庫中有2部手機(jī),1臺(tái)電視
-
or關(guān)系
match類型查詢,會(huì)把查詢條件進(jìn)行分詞。然后進(jìn)行查詢,多個(gè)詞條之間是or的關(guān)系
GET?/ceshi/_search
{
??"query":?{
????"match":?{
??????"title":?"小米電視"
????}
??}
}
默認(rèn)情況下,是會(huì)通過分詞,使多個(gè)詞之間是or的關(guān)系。
-
and關(guān)系
某些時(shí)候需要精確查找,需要將多個(gè)詞關(guān)系設(shè)置為and。
GET?/ceshi/_search
{
??"query":?{
????"match":?{
??????"title":?{
????????"query":?"小米電視",
????????"operator":?"and"
??????}
????}
??}
}
本例中,只有同時(shí)包含
小米和電視的詞條才會(huì)被搜索到
-
or and and 之間
場景:如果用戶給定的條件分詞后有5個(gè)查詢詞項(xiàng),想查找只包含其中4個(gè)詞的文檔,該如何處理?將operator操作符設(shè)置成and只會(huì)將此文檔排除。
有時(shí)候這正是我們期望的,但在全文搜索的大多數(shù)應(yīng)用場景下,我們既想包含那些可能相關(guān)的文檔,同時(shí)又排除那些不太相關(guān)的。換句話說,我們想要處于中間某種結(jié)果。
match查詢支持minimum_should_match最小匹配參數(shù),這讓我們可以指定匹配的詞項(xiàng)數(shù)用來表示一個(gè)文檔是否相關(guān)。我們可以將其設(shè)置為某個(gè)具體數(shù)字,更常用的做法是將其設(shè)置為一個(gè)百分?jǐn)?shù),因?yàn)槲覀儫o法控制用戶搜索時(shí)輸入的單詞數(shù)量。
示例:
GET?/ceshi/_search
{
??"query":?{
????"match":?{
??????"title":?{
????????"query":?"小米曲面電視",
????????"minimum_should_match":?"75%"
??????}
????}
??}
}
-
多字段查詢(multi_match)
match和multi_match類似,不同的是multi_match可以在多個(gè)字段中查詢
示例:
GET?/ceshi/_search
{
????"query":{
????????"multi_match":?{
????????????"query":????"小",
????????????"fields":???[?"title",?"subTitle"?]
????????}
?}
}
-
詞條匹配(term)
term查詢被用于精確值匹配,這些精確值可能是數(shù)字、時(shí)間、布爾或者那些未分詞的字符串
示例:
GET?/ceshi/_search
{
??"query":?{
????"term":?{
?????"price":?"1899"
????}
??}
}
-
多詞條精確匹配(terms)
terms查詢和term查詢一樣,但它允許你指定多值進(jìn)行匹配。如果這個(gè)字段中包含了指定值中的任何一個(gè)值,那么這個(gè)文檔滿足條件:
-
結(jié)果過濾
默認(rèn)情況下,elasticsearch在搜索結(jié)果中,會(huì)把文檔中保存在
_source的所有字段返回。但是,如果我們只想要獲取其中的部分字段,我們可以添加_source的過濾。
-
直接指定字段
示例:
GET?/ceshi/_search
{
??"_source":?["title","price"],
??"query":?{
????"term":?{
??????"price":?1899
????}
??}
}2. 指定includes和excludes
我們也可以通過“
-
includes:來指定想要顯示的字段 -
excludes:來指定不想要顯示的字段
示例:
GET?/ceshi/_search
{
??"_source":?{
????"includes":?["title","images"]
??},
??"query":?{
????"term":?{
??????"price":?1899
????}
??}
}
GET?/ceshi/_search
{
??"_source":?{
????"excludes":?["title","images"]
??},
??"query":?{
????"term":?{
??????"price":?1899
????}
??}
} -
2.18 高級(jí)查詢
1.布爾組合(bool)
bool把各種其他查詢通過must(與)、must_not(非)、shoud(或)的當(dāng)時(shí)組合
示例
#?查詢title可能包含“大米”,但一定包含“手機(jī)”的數(shù)據(jù)
GET?/ceshi/_search
{
??"query":?{
????"bool":?{
??????"must":?{"match":{"title":"大米"}},
??????"must_not":{"match":{"title":"電視"}},
??????"should":{"match":{"title":"手機(jī)"}}
????}
??}
}
2.范圍查詢(range)
range查詢找出那些落在指定區(qū)間內(nèi)的數(shù)字或時(shí)間
示例
#?查詢price在1000-2900范圍內(nèi)的數(shù)據(jù)
GET?/ceshi/_search
{
??"query":?{
????"range":?{
??????"price":?{
????????"gte":?1000,
????????"lte":?2900
??????}
????}
??}
}
range查詢允許以下字符:
| 操作符 | 說明 |
|---|---|
| gt | 大于 |
| gte | 大于等于 |
| lt | 小于 |
| lte | 小于等于 |
3.模糊查詢(fuzzy)
新增一條數(shù)據(jù)
POST?/ceshi/_doc/4
{
????"title":"apple手機(jī)",
????"images":"http://image.leyou.com/12479122.jpg",
????"price":6899.00
}
fuzzy查詢時(shí)term查詢的模糊等價(jià)。它允許用戶搜索詞條與實(shí)際詞條的拼寫出現(xiàn)偏差,但是偏差的編輯距離不得超過2
POST?/ceshi/_doc/4
{
????"title":"apple手機(jī)",
????"images":"http://image.leyou.com/12479122.jpg",
????"price":6899.00
}
上面查詢也是可以查到apple手機(jī)數(shù)據(jù)的
我們可以通過fuzziness屬性來指定允許的偏差距離:
GET?/ceshi/_search
{
??"query":?{
????"fuzzy":?{
??????"title":?{
????????"value":?"appaa",
????????"fuzziness":?3
??????}
????}
??}
}
也是可以查到數(shù)據(jù)
注意:
fuzzinexx值越大,偏差距離也越大,模糊查詢的范圍也越大,反之。
4.過濾(filter)
條件查詢找那個(gè)進(jìn)行過濾
所有的查詢都會(huì)影響到文檔的評(píng)分及排名。如果我們需要在查詢結(jié)果中進(jìn)行過濾,并且不希望過濾條件影響評(píng)分,那么就不要吧過濾條件作為查詢條件來用。而是使用filter方式:
GET?/ceshi/_search
{
??"query":?{
????"bool":?{
??????"must":{"match":{"title":"手機(jī)"}},
??????"filter":?{
????????"range":?{
??????????"price":?{
????????????"gte":?1000,
????????????"lte":?5000
??????????}
????????}
??????}
????}
??}
}
注意:
filet中還可以再次進(jìn)行bool組合條件過濾
無查詢條件,直接過濾
如果一個(gè)查詢只有過濾,沒有查詢條件,不希望進(jìn)行評(píng)分,我們可以使用constant_score取代只有filter語句的bool查詢。在性能上時(shí)完全相同的,但對(duì)于提高查詢簡潔性和清晰度有很大幫助。
示例:
GET?/ceshi/_search
{
??"query":?{
????"constant_score":?{
??????"filter":?{
????????"range":?{
??????????"price":?{
????????????"gte":?1000,
????????????"lte":?4000
??????????}
????????}
??????}
????}
??}
}
5.排序
需求:想要將查詢條件title和price范圍過濾出來結(jié)果,進(jìn)行首先按照價(jià)格排序,然后按照得分排序:
GET?/ceshi/_search
{
??"query":?{
????"bool":?{
??????"must":{"match":{"title":"手機(jī)"}},
??????"filter":{
????????"range":?{
??????????"price":?{
????????????"gte":?1000,
????????????"lte":?7000
??????????}
????????}
??????}
????}
??},
??"sort":?[
????{"price":?{"order":?"desc"}},
????{"_score":?{"order":?"desc"}}
??]
}
2.3聚合aggregations
聚合可以讓我們及其方便的實(shí)現(xiàn)對(duì)數(shù)據(jù)的統(tǒng)計(jì)、分析。例如:
什么品牌的手機(jī)最受歡迎 這些手機(jī)的平均價(jià)格、最高價(jià)格、最低價(jià)格 這些手機(jī)每月的銷售情況如何
實(shí)現(xiàn)這些統(tǒng)計(jì)功能要比數(shù)據(jù)庫的sql方便的多,而且查詢速度非常快,可以實(shí)現(xiàn)實(shí)時(shí)搜索效果。
2.3.1 基本概念
Elasticsearch中的聚合,包含多種類型,最常用的兩種:
桶 度量
1.桶(bucket)
桶的作用,是按照某種方式對(duì)數(shù)據(jù)進(jìn)行分組,每一組數(shù)據(jù)在ES中稱為一個(gè)桶。例如,我們根據(jù)國籍對(duì)人劃分,可以得到中國桶、英國桶、美國桶。。。
Elasticsearch中提供的劃分桶的方式很多:
-
Date Histogram Aggregation:根據(jù)日期階梯分組,例如給定階梯為周,會(huì)自動(dòng)每周分一組 -
Histogram Aggregation:根據(jù)數(shù)值階梯分組,與日期類似 -
Terms Aggregation:根據(jù)詞條內(nèi)容分組,詞條內(nèi)容完全匹配分為一組 -
Range Aggregation:數(shù)值和日期的范圍分組,指定開始和結(jié)束,然后分段分組 -
。。。
綜上所述,我們發(fā)現(xiàn)bucket aggregations只負(fù)責(zé)對(duì)數(shù)據(jù)進(jìn)行分組,并不進(jìn)行計(jì)算,因此bucket中往往會(huì)嵌套另一種聚合:metrics aggregations 即度量。
2.度量(metrics)
分組完成以后,我們一般會(huì)對(duì)組中的數(shù)據(jù)進(jìn)行聚合運(yùn)算,例如求平均值、最大、最小、求和等操作。這些在ES中稱為度量。
比較常用的一些度量聚合方式:
-
Avg Aggregation:求平均值 -
Max Aggregation:求最大值 -
MIn Aggregation:求最小值 -
Percentiles Aggregation:求百分比 -
Stats Aggregation:同時(shí)返回avg、max、min、sum、count等 -
Sum Aggregation:求和 -
Top hits Aggregation:求前幾 -
Value Count Aggregation:求總數(shù) -
。。。
開始測試
為了方便測試,我們首先批量導(dǎo)入測試數(shù)據(jù)
2.3.2 創(chuàng)建索引庫
PUT?/cars
{
??"settings":?{
????"number_of_shards":?1,
????"number_of_replicas":?0
??},
??"mappings":?{
??????"properties":{
????????"color":{"type":"keyword"},
????????"make":{"type":"keyword"}
????}
??}
}
查看索引庫映射關(guān)系:GET /cars/_mapping
注意:在ES中,需要進(jìn)行聚合、排序、過濾的字段其處理方式比較特殊,因此不能被分詞。這里我們將color和make這兩個(gè)字段類型設(shè)置為keyword類型,這個(gè)類型不會(huì)被分詞,將來就可以參與聚合
導(dǎo)入數(shù)據(jù):
POST?/cars/_bulk
{?"index":?{}}
{?"price"?:?10000,?"color"?:?"red",?"make"?:?"honda",?"sold"?:?"2014-10-28"?}
{?"index":?{}}
{?"price"?:?20000,?"color"?:?"red",?"make"?:?"honda",?"sold"?:?"2014-11-05"?}
{?"index":?{}}
{?"price"?:?30000,?"color"?:?"green",?"make"?:?"ford",?"sold"?:?"2014-05-18"?}
{?"index":?{}}
{?"price"?:?15000,?"color"?:?"blue",?"make"?:?"toyota",?"sold"?:?"2014-07-02"?}
{?"index":?{}}
{?"price"?:?12000,?"color"?:?"green",?"make"?:?"toyota",?"sold"?:?"2014-08-19"?}
{?"index":?{}}
{?"price"?:?20000,?"color"?:?"red",?"make"?:?"honda",?"sold"?:?"2014-11-05"?}
{?"index":?{}}
{?"price"?:?80000,?"color"?:?"red",?"make"?:?"bmw",?"sold"?:?"2014-01-01"?}
{?"index":?{}}
{?"price"?:?25000,?"color"?:?"blue",?"make"?:?"ford",?"sold"?:?"2014-02-12"?}
查看cars索引庫中的數(shù)據(jù):
GET?/cars/_search
{
??"query":?{
????"match_all":?{}
??}
}
2.3.3 聚合為桶
1.按照cars中的color字段來劃分桶
GET?/cars/_search
{
????"size"?:?0,
????"aggs"?:?{?
????????"popular_colors"?:?{?
????????????"terms"?:?{?
??????????????"field"?:?"color"
????????????}
????????}
????}
}
size:查詢條數(shù),這里設(shè)置為0,因?yàn)槲覀儾魂P(guān)心搜索到的數(shù)據(jù),只關(guān)心聚合結(jié)果,提高效率 aggs:聲明這是一個(gè)聚合查詢,是aggregations的縮寫
popular_color:給這次聚合起一個(gè)名字,任意。
terms:劃分桶的方式,這里是根據(jù)詞條劃分
field:劃分桶的字段
hits:查詢結(jié)果為空,因?yàn)槲覀冊O(shè)置了size為0 aggregations:聚合的結(jié)果
popular_clor:我們定義的聚合名稱
buckets:查找到的桶,每個(gè)不同的color字段值都會(huì)形成一個(gè)桶
key:這個(gè)桶對(duì)應(yīng)的color字段的值 doc_count:這個(gè)桶中的文檔數(shù)量 總結(jié):通過聚合的結(jié)果我們發(fā)現(xiàn),目前紅色的小車比較暢銷
2.3.4 桶內(nèi)度量
前面的例子告訴我們每個(gè)桶里面的文檔數(shù)量。但通常,我們的應(yīng)用需要提供更為復(fù)雜的文檔度量。例如,每種顏色騎車的平均價(jià)格是多少?
因此,我們需要告訴Elasticsearch使用哪個(gè)字段,使用何種度量方式進(jìn)行運(yùn)算,這些信息要嵌套在==桶內(nèi)==,度量的運(yùn)算會(huì)基于==桶內(nèi)==的文檔進(jìn)行。
示例:
需求:按照cars中的color字段劃分桶,并求相應(yīng)每個(gè)桶中的平均價(jià)格
GET?/cars/_search
{
??"size":?0,
??"aggs":?{
????"popular_color":?{
??????"terms":?{
????????"field":?"color"
??????},
??????"aggs":?{
????????"avg_price":?{
??????????"avg":?{
????????????"field":?"price"
??????????}
????????}
??????}
????}
??}
}
arrgs:我們在aggs(popular_color)中添加新的aggs。可見==度量也是一個(gè)聚合,度量是在桶中的聚合==。 avg_price:度量聚合的名稱,任意 avg:度量的類型,這里是求平均值 field:度量運(yùn)算的字段
結(jié)果:
我們可以看到每個(gè)桶中都有自己的avg_price字段,這就是度量聚合的結(jié)果
2.3.5 桶內(nèi)嵌套桶
上面示例是桶內(nèi)嵌套度量運(yùn)算。事實(shí)上桶內(nèi)不僅可以嵌套運(yùn)算,還可以嵌套其他桶。也就是說在每個(gè)分組中,可以再分更多桶。
示例:
需求:我們想要統(tǒng)計(jì)每種顏色的汽車中,分別屬于哪個(gè)制造商,按照make字段在進(jìn)行分桶
GET?/cars/_search
{
??"size":?0,
??"aggs":?{
????"popular_color":?{
??????"terms":?{
????????"field":?"color"
??????},
??????"aggs":?{
????????"avg_price":?{
??????????"avg":?{
????????????"field":?"price"
??????????}
????????},
????????"maker":{
??????????"terms":?{
????????????"field":?"make"
??????????}
????????}
??????}
????}
??}
}
結(jié)果:
{
??"took"?:?14,
??"timed_out"?:?false,
??"_shards"?:?{
????"total"?:?1,
????"successful"?:?1,
????"skipped"?:?0,
????"failed"?:?0
??},
??"hits"?:?{
????"total"?:?{
??????"value"?:?8,
??????"relation"?:?"eq"
????},
????"max_score"?:?null,
????"hits"?:?[?]
??},
??"aggregations"?:?{
????"popular_color"?:?{
??????"doc_count_error_upper_bound"?:?0,
??????"sum_other_doc_count"?:?0,
??????"buckets"?:?[
????????{
??????????"key"?:?"red",
??????????"doc_count"?:?4,
??????????"maker"?:?{
????????????"doc_count_error_upper_bound"?:?0,
????????????"sum_other_doc_count"?:?0,
????????????"buckets"?:?[
??????????????{
????????????????"key"?:?"honda",
????????????????"doc_count"?:?3
??????????????},
??????????????{
????????????????"key"?:?"bmw",
????????????????"doc_count"?:?1
??????????????}
????????????]
??????????},
??????????"avg_price"?:?{
????????????"value"?:?32500.0
??????????}
????????},
????????{
??????????"key"?:?"blue",
??????????"doc_count"?:?2,
??????????"maker"?:?{
????????????"doc_count_error_upper_bound"?:?0,
????????????"sum_other_doc_count"?:?0,
????????????"buckets"?:?[
??????????????{
????????????????"key"?:?"ford",
????????????????"doc_count"?:?1
??????????????},
??????????????{
????????????????"key"?:?"toyota",
????????????????"doc_count"?:?1
??????????????}
????????????]
??????????},
??????????"avg_price"?:?{
????????????"value"?:?20000.0
??????????}
????????},
????????{
??????????"key"?:?"green",
??????????"doc_count"?:?2,
??????????"maker"?:?{
????????????"doc_count_error_upper_bound"?:?0,
????????????"sum_other_doc_count"?:?0,
????????????"buckets"?:?[
??????????????{
????????????????"key"?:?"ford",
????????????????"doc_count"?:?1
??????????????},
??????????????{
????????????????"key"?:?"toyota",
????????????????"doc_count"?:?1
??????????????}
????????????]
??????????},
??????????"avg_price"?:?{
????????????"value"?:?21000.0
??????????}
????????}
??????]
????}
??}
}
我們可以看到,新的聚合maker被嵌套在原來每一個(gè)color的桶中。 每個(gè)顏色下面都根據(jù)make字段進(jìn)行了分組 我們從結(jié)果中讀到的信息:
紅色車共有4輛 紅色車的平均售價(jià)32500 其中3輛是Honda本田制造,1輛是BMW寶馬制造
2.3.6 階梯分桶(Histogram)
histogram是把數(shù)值類型的字段,按照一定的階梯大小進(jìn)行分組。需要指定一個(gè)階梯值(interval)來劃分階梯大小
示例
需求:比如你有價(jià)格字段,如果你設(shè)定interval的值為200.那么階梯就會(huì)是這樣的:
0,200,400,600,。。。
上面列出的是每個(gè)階梯的key,也是區(qū)間的起點(diǎn)
如果一件商品的價(jià)格是450,會(huì)落在哪個(gè)階梯區(qū)間呢?計(jì)算公式如下:
bucket_key = Math.floor((value-offset)/interval)*interval+offset
value:就是當(dāng)前數(shù)據(jù)的值,本例中是450 offset:起始偏移值,默認(rèn)為0 interval:階梯間隔,比如200
總結(jié)
以上是生活随笔為你收集整理的全文检索Elasticsearch研究的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WEB 服务器配置
- 下一篇: powerpc-linux-gcc,关于