本文主要介紹 ElasticSearch的使用
如有需要指厌,可以參考
如有幫助侣夷,不忘 點(diǎn)贊 ?收藏+關(guān)注哦
ELK是一個(gè)免費(fèi)開源的日志分析架構(gòu)技術(shù)棧總稱仑乌,其中包含三大基礎(chǔ)組件,分別是 ElasticSearch琴锭、Logstash晰甚、Kibana。ELK在實(shí)際開發(fā)中不僅僅使用于日志分析决帖,它還可以支持其他任何數(shù)據(jù)搜索厕九、分析和收集的場景,其中日志分析和收集更具有代表性地回。
既然 ELK 這么有用扁远,那這篇我們就先來認(rèn)識(shí)一下什么是 ElasticSearch吧俊鱼!
簡介
簡單來說 ElasticSearch 就是一個(gè)搜索框架。對(duì)于搜索這個(gè)詞我們并不陌生畅买,當(dāng)我們輸入關(guān)鍵詞后并闲,返回含有該關(guān)鍵詞的所有信息結(jié)果。
在我們平時(shí)用到最多的便是數(shù)據(jù)庫搜索:
SELECT * FROM USE WHERE NAME LIKE %小菜%
復(fù)制代碼
但是用數(shù)據(jù)庫做搜索存在著許多弊端谷羞,例如:
- 存儲(chǔ)問題:當(dāng)數(shù)據(jù)量大的時(shí)候就必須進(jìn)行分庫分表帝火。
- 性能問題:當(dāng)數(shù)據(jù)量過大時(shí),使用LIKE會(huì)對(duì)上億條數(shù)據(jù)進(jìn)行逐行掃描湃缎,性能受到嚴(yán)重影響犀填。
- 不能分詞:當(dāng)我們搜索 游戲本電腦 的時(shí)候,只會(huì)返回完全和關(guān)鍵詞一樣的數(shù)據(jù)嗓违,如果搜索 游戲電腦九巡,那么是不是就會(huì)沒有數(shù)據(jù)返回。
因此基于以上問題蹂季,ElasticSearch出現(xiàn)了冕广。它是使用 Java 開發(fā)的,基于 Lucene乏盐、分布式佳窑、通過 Restful 方式進(jìn)行交互的近實(shí)時(shí)搜索平臺(tái)框架。它的優(yōu)點(diǎn)如下:
- 分布式的搜索引擎和數(shù)據(jù)分析引擎
- 全文檢索父能,結(jié)構(gòu)化檢索和數(shù)據(jù)分析
- 對(duì)海量數(shù)據(jù)進(jìn)行近實(shí)時(shí)的處理
Lucene 介紹
Lucene 是一個(gè)功能強(qiáng)大的搜索庫神凑,如果我們直接基于 Lucene 開發(fā),那么會(huì)非常復(fù)雜何吝。而 ElasticSearch 是基于 Lucene 開發(fā)的溉委,封裝了許多 Lucene 底層功能,提供了簡單易用的 RestFul api接口和許多語言的客戶端爱榕。
ElasticSearch核心概念
- NRT(Near Realtime) 近實(shí)時(shí)
- 寫入數(shù)據(jù)時(shí)瓣喊,過 1 秒才會(huì)被搜索到,因?yàn)閮?nèi)部需要分詞黔酥,引入索引
- es 搜索和分析數(shù)據(jù)都是秒級(jí)內(nèi)出結(jié)果
- Cluster 集群
包含一個(gè)或多個(gè)啟動(dòng)著es實(shí)例的機(jī)器群藻三。通常一臺(tái)機(jī)器起一個(gè)es實(shí)例。同一網(wǎng)絡(luò)下跪者,集名一樣的多個(gè)es實(shí)例自動(dòng)組成集群棵帽,自動(dòng)均衡分片等行為。默認(rèn)集群名為“elasticsearch”渣玲。
- Node 節(jié)點(diǎn)
每個(gè)es實(shí)例稱為一個(gè)節(jié)點(diǎn)逗概。節(jié)點(diǎn)名自動(dòng)分配,也可以手動(dòng)配置忘衍。
- Index 索引
包含一堆有相似結(jié)構(gòu)的文檔數(shù)據(jù)逾苫。索引創(chuàng)建規(guī)則:
- 僅限小寫字母
- 不能包含 *\卿城、/、 铅搓、?瑟押、"、<狸吞、>勉耀、|、# 以及空格符等特殊符號(hào)
- 從7.0版本開始不再包含冒號(hào)
- 不能以-蹋偏、_或+開頭
- 不能超過255個(gè)字節(jié)(注意它是字節(jié)便斥,因此多字節(jié)字符將計(jì)入255個(gè)限制)
- Document 文檔
es中的最小數(shù)據(jù)單元。一個(gè)document就像數(shù)據(jù)庫中的一條記錄威始。通常以json格式顯示枢纠。多個(gè)document存儲(chǔ)于一個(gè)索引(Index)中。
- Field 字段
就像數(shù)據(jù)庫中的列(Columns)黎棠,定義每個(gè)document應(yīng)該有的字段晋渺。
- Type 類型
每個(gè)索引里都可以有一個(gè)或多個(gè)type,type是index中的一個(gè)邏輯數(shù)據(jù)分類脓斩,一個(gè)type下的document木西,都有相同的field。
注:6.0之前的版本有type(類型)概念随静,type相當(dāng)于關(guān)系數(shù)據(jù)庫的表八千,ES官方將在ES9.0版本中徹底刪除type。本教程typy都為_doc燎猛。
- Shard 分片
index數(shù)據(jù)過大時(shí)恋捆,將index里面的數(shù)據(jù),分為多個(gè)shard重绷,分布式的存儲(chǔ)在各個(gè)服務(wù)器上面沸停。可以支持海量數(shù)據(jù)和高并發(fā)昭卓,提升性能和吞吐量愤钾,充分利用多臺(tái)機(jī)器的cpu。
- replica 副本
在分布式環(huán)境下候醒,任何一臺(tái)機(jī)器都會(huì)隨時(shí)宕機(jī)绰垂,如果宕機(jī),index一個(gè)分片都沒有火焰,那么導(dǎo)致此index不能搜索。所以胧沫,為了保證數(shù)據(jù)的安全昌简,我們會(huì)將每個(gè)index的分片進(jìn)行備份占业,存儲(chǔ)在另外的機(jī)器上。保證少數(shù)機(jī)器宕機(jī)es集群仍可以搜索纯赎。
能正常提供查詢和插入的分片我們叫做主分片(primary shard)谦疾,其余的叫做備份的分片(replica shard)。
與數(shù)據(jù)庫同比
<colgroup style="box-sizing: border-box;"><col style="box-sizing: border-box;"><col style="box-sizing: border-box;"></colgroup>
|
關(guān)系型數(shù)據(jù)庫
|
非關(guān)系型數(shù)據(jù)庫(Elasticsearch)
|
|
數(shù)據(jù)庫 Database
|
索引 Index
|
|
表 Table
|
索引 Index(原為 Type)
|
|
數(shù)據(jù)行 Row
|
文檔 Document
|
|
數(shù)據(jù)列 Column
|
字段 Field
|
|
約束 Schema
|
映射 Mapping
|
前期準(zhǔn)備
演示環(huán)境: Windows
ElasticSearch 安裝
我們進(jìn)入 ElasticSearch下載地址 下載和解壓 ElasticSearch 犬金,目錄結(jié)構(gòu)如下:
- bin:腳本目錄念恍,包括:啟動(dòng)、停止等可執(zhí)行的腳本
- config:配置文件目錄
- data:索引目錄
- logs:日志目錄
- modules:模塊目錄晚顷,包括了 es 的功能模塊
- plugins:插件目錄峰伙,es 支持插件機(jī)制
準(zhǔn)備好配置文件后,雙擊elasticsearch.bat啟動(dòng)该默,接著訪問http://localhost:9200瞳氓,出現(xiàn)以下界面即為成功:
Kibana 安裝
進(jìn)入下載地址 下載和解壓 Kibana匣摘,修改配置文件后,雙擊kibana.bat啟動(dòng)裹刮,接著訪問http://localhost:5601/音榜,出現(xiàn)以下界面即為成功:
進(jìn)入 Kibana 控制臺(tái)赠叼,輸入 GET /查看ElasticSearch信息,出現(xiàn)以下界面即為成功:
前期準(zhǔn)備工作做好了,咱們現(xiàn)在開始進(jìn)入ElasticSearch的正式環(huán)節(jié)葛家!
ES開講
什么是 Index
Index就相當(dāng)于數(shù)據(jù)庫中的數(shù)據(jù)表癞谒,ElasticSearch會(huì)索引所有字段底燎,經(jīng)過處理后寫入一個(gè)反向索引(Inverted Index)。查找數(shù)據(jù)的時(shí)候弹砚,直接查找該索引双仍。所以,ElasticSearch數(shù)據(jù)管理的頂層單位就叫做 Index(索引)桌吃。注: 每個(gè) Index 的名字必須是小寫朱沃。
- 創(chuàng)建一個(gè) test 索引:
語法:PUT /${index}
- 刪除 test 索引:
語法:DELETE /${index}
其中刪除支持其他語法:
1\. DELETE /test
2. DELETE /test1,test2
3. DELETE /test_*
4. DELETE /_all
復(fù)制代碼
什么是 Document
首先員工和部門對(duì)象如下:
public class Employee{
private String id;
private String name;
private String deptId;
}
public class Department{
private String id;
private String deptName翎卓;
private String describe契邀;
}
復(fù)制代碼
我們?nèi)绻藐P(guān)系型數(shù)據(jù)存數(shù)據(jù)的話,應(yīng)該是一個(gè)員工表和一個(gè)部門表失暴,查詢員工的時(shí)候想要帶上部門的信息就得使用關(guān)聯(lián)查詢坯门。
但是在 ES 中,它是面向文檔的逗扒,文檔中存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu)與對(duì)象一致古戴。一個(gè)對(duì)象可以直接保存成一個(gè)文檔,這就是ES中的 Document缴阎,document 是采用 json 數(shù)據(jù)格式表示允瞧,示例如下:
{
"id":"1",
"name":"小菜",
"department":{
"id":"1",
"deptName":"搬磚部",
"describe":"努力搬好每一塊磚"
}
}
復(fù)制代碼
接下來我們?cè)?employee索引中演示基本的增刪改查操作:
創(chuàng)建員工信息:
獲取員工信息:
修改員工信息:
以下是替換操作建炫,要帶上所有信息
局部更新操作:
局部更新操作的語法為:POST /{index}/_update/{id},其中要更新的信息需要放在doc里面
刪除員工信息:
字段信息
{
"_index" : "employee",
"_type" : "_doc",
"_id" : "1",
"_version" : 4,
"_seq_no" : 7,
"_primary_term" : 1,
"found" : true,
"_source" : {
"id" : "1",
"name" : "小菜",
"department" : {
"id" : "1",
"deptName" : "搬磚部",
"describe" : "努力搬好每一塊磚"
}
}
}
復(fù)制代碼
當(dāng)我們通過GET /employee/_doc/1 可以獲取到一條文檔信息如上,其中出現(xiàn) 8 個(gè)字段稳捆,接下來為你們解析一番重要字段:
- _index:文檔所屬的索引名稱
- _type:類別赠法。在 es9 只有會(huì)刪除此字段,因此不用關(guān)注乔夯,默認(rèn)都為 _doc
- _id:文檔的唯一標(biāo)志砖织,類似于表中的主鍵ID,可以用來標(biāo)識(shí)和定義一個(gè)文檔末荐〔啻浚可以手動(dòng)生成,也可以自動(dòng)生成
1.手動(dòng)生成
2.自動(dòng)生成:
注: 這里用到是 POST請(qǐng)求妹笆,將會(huì)為我們自動(dòng)生成 20 個(gè)字符的 ID
- _version:版本號(hào)
這里的版本號(hào)是在 全量替換 晾浴、 局部更新和 刪除 操作時(shí),版本號(hào)都會(huì)加 1牍白,上面 ID 為 1 的員工信息版本表為4,說明這條記錄已經(jīng)更新了 4 次抖棘。
- _seq_no:序列號(hào)
作用于 version 類似茂腥,當(dāng)數(shù)據(jù)發(fā)生變更時(shí),值就會(huì)加 1
- _source:插入數(shù)據(jù)時(shí)的所有字段和值
我們也可以不需要返回所有字段切省,需要用以下語句:
GET /employee/_doc/1?_source_includes=id,name
當(dāng)然不僅可以使用_source_includes 朝捆,還可以使用_source_excludes般渡,兩個(gè)意思分別是包括和 排除。
樂觀鎖機(jī)制
在我們學(xué)習(xí) Java 并發(fā)的時(shí)候芙盘,我們認(rèn)識(shí)了 CAS 樂觀鎖機(jī)制驯用,在 ES 中我們同樣也可以使用樂觀鎖來控制。
CAS是基于版本號(hào)的儒老,而在上述 Document 字段解析中蝴乔,我們也看到了 _seq_no 這個(gè)字段,不由想象驮樊,我們是否也能根據(jù) _seq_no 來做樂觀鎖控制解決并發(fā)問題呢薇正,答案是可以的。
我們首先創(chuàng)建一條員工記錄:
此時(shí),版本號(hào)毋庸置疑是 1练湿,_seq_no是 10
然后我們將這條員工信息刪除:
接著我們重新創(chuàng)建一條相同的員工信息:
可以看到這個(gè)時(shí)候的版本號(hào)變成了 3,_seq_no 變成了 14贤姆。
這是因?yàn)?ES 內(nèi)部采用了 延遲刪除策略榆苞,這是因?yàn)槿绻麆h除一條數(shù)據(jù)立馬刪除的話,所有分片和副本都要立馬刪除霞捡,這會(huì)對(duì) ES 集群壓力太大坐漏。
進(jìn)行并發(fā)控制:
- 步驟1:我們先查出當(dāng)前的 _seq_no 為 17
語句: PUT /employee/_doc/5?if_seq_no=17&if_primary_term=1
可以看到更新后赊琳,_version 和 _seq_no 都加上了 1
如果 _seq_no 版本不匹配的情況下:
將會(huì)報(bào)出錯(cuò)誤躏筏!
批量操作
批量查詢 (_mget)
上面我們用到的語句都是指定ID單個(gè)查詢板丽,如果我們想要查詢當(dāng)前索引下的所有數(shù)據(jù),那么應(yīng)當(dāng)使用以下語句:
GET /employee/_mget
{
"docs" : [
{
"_id" : 1
},
{
"_id" : 5
}
]
}
復(fù)制代碼
如果我們要同時(shí)查詢不同索引下的 ID 時(shí),應(yīng)當(dāng)使用以下語句:
GET /_mget
{
"docs" : [
{
"_index" : "employee",
"_id" : 1
},
{
"_index" : "employee",
"_id" : 5
}
]
}
復(fù)制代碼
批量增刪改 (bulk)
語法:
POST /_bulk
{"action": {"metadata"}}
{"data"}
復(fù)制代碼
示例:
注:
- delete: 刪除一個(gè)文檔似炎,只需 1 個(gè) json 串
- create: 創(chuàng)建一個(gè)文檔,相當(dāng)于 PUT /index/type/id/_create
- index: 普通的 put 操作悯姊,可以創(chuàng)建文檔羡藐,也可以全量替換文檔
- update: 更新一個(gè)文檔,執(zhí)行的是局部更新
每個(gè)操作之間互不影響挠轴,操作失敗的行會(huì)返回對(duì)應(yīng)的失敗信息
buld 操作請(qǐng)求一次不宜過大传睹, 否則一下子容易擠壓到內(nèi)存中,性能會(huì)下降
與開發(fā)融合
ElasticSearch 是基于 Java 開發(fā)的岸晦,當(dāng)然我們開發(fā)中要使用 ElasticSearch 也是非常方便的欧啤。
首先便是引入依賴
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.9.0</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.9.0</version>
</dependency>
復(fù)制代碼
獲取員工信息示例
/** OUTPUT:
{"id":"1","name":"小菜啊","department":{"id":"1","deptName":"搬磚部","describe":"努力搬好每一塊磚"}}
*/
復(fù)制代碼
如果你覺得只從 getResponse 中獲取一個(gè) source 不滿足邢隧,沒有關(guān)系!我們還可以從getResponse 獲取以下信息:
我們?cè)谏厦娴牟樵兾臋n中發(fā)現(xiàn),如果需要從 ES 中獲取信息包券,我們先要 獲取客戶端連接纫谅,然后再 構(gòu)建請(qǐng)求,最后 執(zhí)行得到結(jié)果溅固。這一系列操作不知道你是否有點(diǎn)熟悉付秕,我們以前用的 JDBC,也是需要這一系列的操作侍郭,后來出現(xiàn)了 Hibernate 和 Mybatis询吴,大大簡化了我們的代碼量掠河。無獨(dú)有偶,ES 也可以完美結(jié)合 Spring 框架開發(fā)猛计。
首先我們需要需要在 application.yaml 文件中定義好elasticsearch 的 host:
server:
port: 8081
spring:
application:
name: search-service
elasticsearch:
address: 127.0.0.1:9200 #多個(gè)節(jié)點(diǎn)用逗號(hào)分隔
復(fù)制代碼
然后我們需要在 Spring 中注冊(cè) RestHighLevelClient
執(zhí)行查詢
我們?cè)谏鲜隼又姓J(rèn)識(shí)到了_source_includes 和_source_excludes的用法,當(dāng)然在 Java 中也是支持的:
而且ES在 Java 中還支持異步查詢:
執(zhí)行新增
在上面我們是用 json 傳遞我們需要新增的參數(shù)吼驶,當(dāng)然也支持另外方式:
//方式1: json
Map<String, String> insertInfo = new HashMap<>();
insertInfo.put("id", "8");
insertInfo.put("name", "老王");
request.source(JSON.toJSONString(insertInfo), XContentType.JSON);
//方式2: map
Map<String, String> insertInfo = new HashMap<>();
insertInfo.put("id", "8");
insertInfo.put("name", "老王");
request.source(insertInfo);
//方式3: XContentBuilder
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
{
builder.field("id", "8");
builder.field("name", "老王");
}
builder.endObject();
request.source(builder);
//方式4: 直接構(gòu)建
request.source("id", "8", "name", "老王");
復(fù)制代碼
當(dāng)然不止新增支持異步操作,更新同樣也支持異步操作:
執(zhí)行修改
異步支持:
執(zhí)行刪除
異步支持:
執(zhí)行批量
Mapping 介紹
什么是Mapping: 自動(dòng)或手動(dòng)為 index 中的 _doc 建立的一種數(shù)據(jù)結(jié)構(gòu)和相關(guān)配置
我們?nèi)绻褂藐P(guān)系型數(shù)據(jù)庫插入一條員工信息涛舍,首先需要建立一個(gè)員工表 employee澄惊,然后表里面有兩個(gè)字段:id,name:
create table website(
id varchar(8),
name varchar(8)
);
復(fù)制代碼
我們往 員工索引 中插入數(shù)據(jù):
PUT /employee/_doc/1
{
"id":"1",
"name":
}
復(fù)制代碼
感覺少了點(diǎn)什么富雅,那就是我們不需要建立字段了掸驱,甚至不需要手動(dòng)建立 employee 索引,只需要一句語句就可以解決没佑!
這是因?yàn)镋S 里面存在動(dòng)態(tài)映射(Dynamic Mapping)毕贼,會(huì)自動(dòng)為我們建立 index,以及對(duì)應(yīng)的 mapping图筹, mapping 中包含了每個(gè) field 對(duì)應(yīng)的數(shù)據(jù)類型帅刀,以及如何分詞等設(shè)置让腹。
我們可以通過 GET /{index}/_mapping 查看自己索引的字段映射:
核心數(shù)據(jù)類型
動(dòng)態(tài)推測類型
<colgroup style="box-sizing: border-box;"><col style="box-sizing: border-box;"><col style="box-sizing: border-box;"></colgroup>
|
JSON datatype
|
ElasticSearch datatype
|
|
true or false
|
boolean
|
|
123
|
long
|
|
123.45
|
double
|
|
2019-01-01
|
date
|
|
"test"
|
text/keyword
|
自定義
我們?cè)趧?chuàng)建完索引后,可以手動(dòng)創(chuàng)建映射:
語法: PUT ${index}/_mapping
PUT department/_mapping
{
"properties": {
"id": {
"type": "text"
},
"description": {
"type": "text",
"analyzer":"english",
"search_analyzer":"english"
}
}
}
復(fù)制代碼
其中可以通過analyzer屬性指定分詞器驱犹。上邊指定了analyzer是指在索引和搜索都使用english嘲恍,如果單獨(dú)想定義搜索時(shí)使用的分詞器則可以通過search_analyzer屬性。
注: 日期類型不支持分詞器
【END】
以上便是 ElasticSearch 的入門介紹啦雄驹!ElasticSearch 可以講的內(nèi)容還有很多哦佃牛,接下來也會(huì)抽時(shí)間整理一下 ElasticSearch 的深入內(nèi)容哦,關(guān)注小編不迷路医舆。路漫漫俘侠,小編與你一同求索!