文章目錄
一. 什麼是es
Elasticsearch是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful
web接口。Elasticsearch是用Java語言開發的,並作爲Apache許可條款下的開放源碼發佈,是一種流行的企業級搜索引擎。Elasticsearch用於雲計算中,能夠達到實時搜索,穩定,可靠,快速,安裝使用方便。官方客戶端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和許多其他語言中都是可用的。根據DB-Engines的排名顯示,Elasticsearch是最受歡迎的企業搜索引擎,其次是Apache Solr,也是基於Lucene。
二. es的核心概念
2.1 es中的概念與數據庫中概念的對應
es | 數據庫 |
---|---|
索引(index) | 表 |
文檔 (document) | 行(記錄) |
字段 (fields) | 列 |
類型(type) | 字段屬性 |
- 在新版本中已經沒有類型這個概念了
數據演示:
stu_index //這個就是索引
//這就是一個行
{
//這就是一個列
id: 1001,
name: jason,
age: 19
},
{
id: 1002,
name: tom,
age: 18
},
{
id: 1003,
name: rose,
age: 22
}
2.2 集羣相關
分片(shard):把索引庫拆分爲多份,分別放在不同的節點上,比如有3個節點,3個節點的所有數據內容加在一起是一個完整的索引庫。分別保存到三個節點上,目的爲了水平擴展,提高吞吐量。
備份(replica):每個shard的備份。
簡稱
shard = primary shard(主分片)
replica = replica shard(備份節點)
2.3 正排索引與倒排索引
1. 正排索引
通過id去尋找內容,比如我想查到‘我喜歡學java’這個內容,我就需要知道他的id來查找這個內容,這個就是正排索引,通過id來建立索引
id | 內容 |
---|---|
1 | 我喜歡學java語言 |
2 | java是世界上最好的語言 |
3 | 996是福報 |
2. 倒排索引
倒排索引源於實際應用中需要根據屬性的值來查找記錄。這種索引表中的每一項都包括一個屬性值和具有該屬性值的各記錄的地址。由於不是由記錄來確定屬性值,而是由屬性值來確定記錄的位置,因而稱爲倒排索引(inverted index)。帶有倒排索引的文件我們稱爲倒排索引文件,簡稱倒排文件(inverted file)。
簡單來說就是不通過key來進行搜索,而是根據value來進行搜索。
利用value來進行搜索有以下幾個好處:
- 提升查詢速度
- 可以更好的優化查詢
詞頻TF:位置POS:
文檔id:出現次數:在文檔中的位置
單詞 | 文檔ids | 詞頻TF:位置POS |
---|---|---|
我 | 1 | 1:1<1> |
喜歡 | 1 | 1:1<2> |
學 | 1 | 1:1<3> |
java | 1,2 | 1:1:<4>,2:1:<1> |
是 | 2,3 | 2:1:<2>,3:1:<2> |
世界上 | 2 | 2:1:<3> |
最好 | 2 | 2:1:<4> |
的 | 2 | 2:1:<5> |
語言 | 1,2 | 1:1:<5>,2:1:<6> |
996 | 3 | 3:1:<1> |
福報 | 3 | 3:1:<3> |
三. linux下es的安裝
linux版本:centos7
資源地址:
鏈接:https://pan.baidu.com/s/13HBOtno8Z7sHYWbS9cwCLg
提取碼:kygy
3.1 ES 目錄介紹
- bin:可執行文件在裏面,運行es的命令就在這個裏面,包含了一些腳本文件等
- config:配置文件目錄
- JDK:java環境
- lib:依賴的jar,類庫
- logs:日誌文件
- modules:es相關的模塊
- plugins:可以自己開發的插件
- data:這個目錄沒有,自己新建一下,後面要用 -> mkdir data,這個作爲索引目錄
3.2 安裝步驟
-
將文件上傳的服務器上
-
解壓縮文件
tar -zxvf elasticsearch-7.4.2-linux-x86_64.tar.gz
-
將解壓後的文件夾移動到local下好管理
mv elasticsearch-7.4.2 /usr/local
-
進入到local文件夾下
cd /usr/local
-
修改核心配置文件
-
修改集羣名稱,雖然目前是單機,但是也會有默認的
-
爲當前的es節點取個名稱,名稱隨意,如果在集羣環境中,都要有相應的名字
-
修改data數據保存地址
-
修改日誌數據保存地址
-
綁定es網絡ip,原理同redis默認端口號,可以自定義修改
-
集羣節點,名字可以先改成之前的那個節點名稱
-
-
添加用戶 ES不允許使用root操作es,需要添加用戶,操作如下:
useradd esuser
chown -R esuser:esuser /usr/local/elasticsearch-7.4.2
su esuser
whoami
- 進入到/bin目錄下,啓動es
./elasticsearch
- 啓動成功後訪問
IP:9200
注意:如果啓動失敗請往下看!!!
3.3 啓動失敗原因與解決辦法
1. 用的虛擬機或服務啓的內存太小,導致啓動失敗
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000c5330000, 986513408, 0) failed; error='Cannot allocate memory' (errno=12)
解決辦法:
注:如果你的安裝步驟和我一樣,那麼這個配置文件就在這個目錄下面,如果不一樣,請到你自己的es安裝目錄下修改這個配置文件
vim /usr/.local/elasticsearch-7.4.2/config/jvm.options
- 默認jvm的大小是1G,可以改成128m
2. vm.max_map_count設置過小報錯
ERROR: [1] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
解決辦法:
- 修改配置文件
vim /etc/sysctl.conf
- 在配置文件中添加
vm.max_map_count=262145
sysctl -p
刷新一下
3. 用root用戶啓動es
Caused by: java.lang.RuntimeException: can not run elasticsearch as root
解決辦法:新建一個用戶,切換到新建用戶下啓動
useradd esuser
chown -R esuser:esuser /usr/local/elasticsearch-7.4.2
su esuser
whoami
4. 配置文件設置太小
解決辦法:
- 修改配置文件
vim /etc/security/limits.conf
- 在配置文件最後添加
* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096
5. 啓動沒有異常,但是頁面進不去
解決辦法:雲服務器記得添加安全組配置,虛擬機把防火牆關掉
四. es的集羣
4.1 es的集羣原理
es進行搜索是很快,但是還是會有瓶頸的,如果一臺es的吞吐量爲1000/s,那麼當請求超過1000的時候,es就處理不了的,這個時候怎麼辦呢?es提供了一種解決辦法,就是將多臺es做成一個集羣來處理請求,而集羣中的每一個es就被稱爲shard(分片),用戶的請求會平均分配到集羣中的每一個分片上,並且每一個分片都可以並行的處理用戶的請求,通過es的集羣就可以加大es的請求處理數,但是數據是平均分配到各個分片上的,如果有一臺es崩潰了怎麼辦,那不就是會有一批數據搜索不到了嘛,這個時候就得引出另外一個名詞了備份(replica),在每一個分片上在加上一個備份節點,這樣如果shard崩潰了,還有備份節點可以工作,保證數據的準確性。
4.2 集羣實現
每個索引可以被分片,就相當於吃披薩的時候被切了好幾塊,然後分給不同的人吃
假如有三臺服務器配成集羣,那麼每一個分片會分配到不同的集羣上,並且同一個分片和副本不會分配到同一臺服務器上
4.3 集羣讀寫原理
1. 文檔讀原理
- 客戶端會選擇一個節點作爲調節節點,類似於調度層(controller),用於接受用戶的請求
- 協調節點會把請求轉發到主分片或者副本分片上,輪詢操作(相當於是負載均衡)
- 查詢後把請求跳回到協調節點上
- 由協調節點來響應給客戶端
2. 文檔寫原理
- 客戶端會選擇一個節點作爲調節節點,類似於調度層(controller),用於接受用戶的請求
- 用這個協調節點來選擇(hash算法)由哪個分片來進行操作,假設路由後轉發到P1主分片上
- 當p1寫完後,會同步到R1副分片上
- 當R1寫完後,會把請求再次跳到協調節點上
- 由協調節點來響應給客戶端
4.4 集羣的配置
- 如果你是直接拷貝安裝好的es到其他服務器中的話,記得把es下的data文件夾下的數據都刪掉,這裏麪包含了原先的索引庫數據。
rm -rf nodes/
- 修改elasticsearch.yml配置文件
# 配置集羣名稱,保證每個節點的名稱相同,如此就能都處於一個集羣之內了
cluster.name: imooc-es-cluster
# 每一個節點的名稱,必須不一樣
node.name: es-node1
# http端口(使用默認即可)
http.port: 9200
# 主節點,作用主要是用於來管理整個集羣,負責創建或刪除索引,管理其他非master節點(相當於企業老總)
node.master: true
# 數據節點,用於對文檔數據的增刪改查
node.data: true
# 集羣列表
discovery.seed_hosts: ["192.168.1.184", "192.168.1.185", "192.168.1.186"]
# 啓動的時候使用一個master節點
cluster.initial_master_nodes: ["es-node1"]
- 最後可以通過如下命令查看配置文件的內容:
more elasticsearch.yml | grep [#] - 將集羣中的es分別啓動
- 可以在head插件中查看,訪問哪個ip都可以
五. 安裝ik中文分詞器
5.1 安裝步驟
1.將壓縮包上傳的linux上
2.解壓縮zip包,將解壓後的文件放到{Elasticsearch}/plugin/ik(ik自己建)
unzip elasticsearch-analysis-ik-6.4.3\ .zip -d /usr/local/elasticsearch-6.4.3/ik
注:如果環境上沒有unzip ,就先安裝
yum -y install zip unzip
3.重啓 Elasticsearch
5.2 驗證方式
請求方式:POST
請求路徑:/_analyze
請求信息:
{
"analyzer": "ik_max_word",
"text": "上下班車流量很大"
}
響應結果:
{
"tokens": [
{
"token": "上下班",
"start_offset": 0,
"end_offset": 3,
"type": "CN_WORD",
"position": 0
},
{
"token": "上下",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 1
},
{
"token": "下班",
"start_offset": 1,
"end_offset": 3,
"type": "CN_WORD",
"position": 2
},
{
"token": "班車",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 3
},
{
"token": "車流量",
"start_offset": 3,
"end_offset": 6,
"type": "CN_WORD",
"position": 4
},
{
"token": "車流",
"start_offset": 3,
"end_offset": 5,
"type": "CN_WORD",
"position": 5
},
{
"token": "流量",
"start_offset": 4,
"end_offset": 6,
"type": "CN_WORD",
"position": 6
},
{
"token": "很大",
"start_offset": 6,
"end_offset": 8,
"type": "CN_WORD",
"position": 7
}
]
}
5.3 分詞模式
- ik_max_word: 會將文本做最細粒度的拆分,比如會將“中華人民共和國國歌”拆分爲“中華人民共和國,中華人民,中華,華人,人民共和國,人民,人,民,共和國,共和,和,國國,國歌”,會窮盡各種可能的組合,適合 Term Query;
- ik_smart: 會做最粗粒度的拆分,比如會將“中華人民共和國國歌”拆分爲“中華人民共和國,國歌”,適合 Phrase 查詢。
5.4 自定義中文詞庫
- 在{es}/plugins/ik/config下創建.dic文件vim custom.dic
- 在dic文件裏面添加詞庫內容
- 在IKAnalyzer.cfg.xml配置文件中添加custom.dic
custom.dic
4.重啓
六. 索引和文檔的基本操作
都是用的Restful形式
6.1 基礎知識
元數據
_index:文檔數據所屬那個索引,理解爲數據庫的某張表即可。
_type:文檔數據屬於哪個類型,新版本使用_doc。
_id:文檔數據的唯一標識,類似數據庫中某張表的主鍵。可以自動生成或者手動指定。
_score:查詢相關度,是否契合用戶匹配,分數越高用戶的搜索體驗越高。
_version:版本號。
_source:文檔數據,json格式。
有關於文檔刪除
文檔刪除不是立即刪除,文檔還是保存在磁盤上,索引增長越來越多,纔會把那些曾經標識過刪除的,進行清理,從磁盤上移出去
版本號
每次修改版本號都會更新
關於mapping
注:如果索引沒有手動建立mappings,那麼當插入文檔數據的時候,會根據文檔類型自動設置屬性類型。這個就是es的動態映射,幫我們在index索引庫中去建立數據結構的相關配置信息。
“fields”: {“type”: “keyword”}
對一個字段設置多種索引模式,使用text類型做全文檢索,也可使用keyword類型做聚合和排序“ignore_above” : 256
設置字段索引和存儲的長度最大值,超過則被忽略
數據類型
- text, keyword, string
- long, integer, short, byte
- double, float
- boolean
- date
- object
- 數組不能混,類型一致
字符串
- text:文字類需要被分詞被倒排索引的內容,比如商品名稱,商品詳情,商品介紹,使用text。
- keyword:不會被分詞,不會被倒排索引,直接匹配搜索,比如訂單狀態,用戶qq,微信號,手機號等,這些精確匹配,無需分詞。
6.2 請求接口
1.獲取es信息
請求方式:GET
請求路徑:http://112.126.61.225:9200/
返回值:
{
"name": "node-1",
"cluster_name": "my-application",
"cluster_uuid": "KfGgM2rdTRqqtkv1prR3aA",
"version": {
"number": "7.4.2",
"build_flavor": "default",
"build_type": "tar",
"build_hash": "2f90bbf7b93631e52bafb59b3b049cb44ec25e96",
"build_date": "2019-10-28T20:40:44.881551Z",
"build_snapshot": false,
"lucene_version": "8.2.0",
"minimum_wire_compatibility_version": "6.8.0",
"minimum_index_compatibility_version": "6.0.0-beta1"
},
"tagline": "You Know, for Search"
}
2.獲取健康度等信息
請求方式:GET
請求路徑:http://112.126.61.225:9200/_cluster/health
返回值:
{
"cluster_name": "my-application",
"status": "green",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 2,
"active_shards": 2,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0,
"number_of_in_flight_fetch": 0,
"task_max_waiting_in_queue_millis": 0,
"active_shards_percent_as_number": 100.0
}
3.添加索引
請求方式:PUT
請求路徑:http://112.126.61.225:9200/my_doc
返回值:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "my_doc"
}
4.刪除索引
請求方式:DELETE
請求路徑:http://112.126.61.225:9200/demo
返回值:
{
"acknowledged": true
}
5.查看所有索引
請求方式:GET
請求路徑:http://112.126.61.225:9200/_cat/indices?v
返回值:
{
"index_demo": {
"aliases": {},
"mappings": {},
"settings": {
"index": {
"creation_date": "1588839521441",
"number_of_shards": "2",
"number_of_replicas": "0",
"uuid": "_6jMGpZfTu2E4Vfp7yd9bg",
"version": {
"created": "7040299"
},
"provided_name": "index_demo"
}
}
}
}
6.查看某個索引信息
請求方式:GET
請求路徑:http://112.126.61.225:9200/index_demo
返回值:
{
"index_demo": {
"aliases": {},
"mappings": {},
"settings": {
"index": {
"creation_date": "1588839521441",
"number_of_shards": "2",
"number_of_replicas": "0",
"uuid": "_6jMGpZfTu2E4Vfp7yd9bg",
"version": {
"created": "7040299"
},
"provided_name": "index_demo"
}
}
}
}
7.創建索引與mapping
請求方式:PUT
請求路徑:http://112.126.61.225:9200/index_test
請求參數:
{
"mappings": {
"properties": {
"realname": {
"type": "text",
"index": true
},
"username": {
"type": "keyword",
"index": false
}
}
}
}
返回值:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "index_test"
}
8.在原有mapping上添加新的mapping
請求方式:PUST
請求路徑:http://112.126.61.225:9200/index_test/_mapping
請求參數:
{
"properties": {
"name": {
"type": "long"
}
}
}
返回值:
{
"acknowledged": true
}
9.查看分詞效果
請求方式:GET
請求路徑:http://112.126.61.225:9200/index_test/_analyze
請求參數:
{
"field": "realname",
"text": "spj is good"
}
返回值:
{
"tokens": [
{
"token": "spj",
"start_offset": 0,
"end_offset": 3,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "is",
"start_offset": 4,
"end_offset": 6,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "good",
"start_offset": 7,
"end_offset": 11,
"type": "<ALPHANUM>",
"position": 2
}
]
}
10.添加文檔
請求方式:POST
請求路徑:http://112.126.61.225:9200/my_doc/_doc/2
請求參數:
{
"id": 1002,
"name": "imooc-2",
"desc": "china is fashion, !",
"create_date": "2019-12-25"
}
返回值:
{
"_index": "my_doc",
"_type": "_doc",
"_id": "2",
"_version": 1,
"result": "created",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 5,
"_primary_term": 4
}
11.刪除文檔
請求方式:DELETE
請求路徑:http://112.126.61.225:9200/my_doc/_doc/2
請求參數:
{
"id": 1002,
"name": "imooc-2",
"desc": "china is fashion, !",
"create_date": "2019-12-25"
}
返回值:
{
"_index": "my_doc",
"_type": "_doc",
"_id": "2",
"_version": 2,
"result": "deleted",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 2
}
12.修改文檔(增量修改)
請求方式:POST
請求路徑:http://112.126.61.225:9200/my_doc/_doc/1/_update
請求參數:
{
"doc": {
"name": "奧"
}
}
返回值:
{
"_index": "my_doc",
"_type": "_doc",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 2
}
13.修改文檔(全量修改)
請求方式:PUT
請求路徑:http://112.126.61.225:9200/my_doc/_doc/1
請求參數:
{
"id": 1001,
"name": "test-1",
"desc": "china is very good, 中國非常牛!",
"create_date": "2020-05-08"
}
返回值:
{
"_index": "my_doc",
"_type": "_doc",
"_id": "1",
"_version": 4,
"result": "updated",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 6,
"_primary_term": 4
}
14.查詢文檔(查詢所有)
請求方式:GET
請求路徑:http://112.126.61.225:9200/my_doc/_doc/_search
返回值:
{
"took": 2056,
"timed_out": false,
"_shards": {
"total": 2,
"successful": 2,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "my_doc",
"_type": "_doc",
"_id": "1",
"_score": 1.0,
"_source": {
"id": 1001,
"name": "test-1",
"desc": "china is very good, 中國非常牛!",
"create_date": "2020-05-08"
}
}
]
}
}
15.查詢文檔(通過id定向查找)
請求方式:GET
請求路徑:http://112.126.61.225:9200/my_doc/_doc/1
返回值:
{
"_index": "my_doc",
"_type": "_doc",
"_id": "1",
"_version": 4,
"_seq_no": 6,
"_primary_term": 4,
"found": true,
"_source": {
"id": 1001,
"name": "test-1",
"desc": "china is very good, 中國非常牛!",
"create_date": "2020-05-08"
}
}
16.查詢文檔(定製結果集)
請求方式:GET
請求路徑:http://112.126.61.225:9200/my_doc/_doc/1?_source=id,name
返回值:
{
"_index": "my_doc",
"_type": "_doc",
"_id": "1",
"_version": 4,
"_seq_no": 6,
"_primary_term": 4,
"found": true,
"_source": {
"name": "test-1",
"id": 1001
}
}
七. Springboot整合es
7.1 整合es
- 添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<!--<version>2.1.5.RELEASE</version>-->
<version>2.2.2.RELEASE</version>
</dependency>
- 配置yml文件
Spring:
data:
elasticsearch:
cluster-nodes: 192.168.10.182:9300
cluster-name: my-application
- 代碼實現
注入ElasticsearchTemplate
@Autowired
private ElasticsearchTemplate esTemplate;
- 注意事項
es版本和spring-boot-starter-data-elasticsearch的版本要一直
如何查看spring-boot-starter-data-elasticsearch的版本
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LvB9pdzU-1589685969666)(en-resource://database/1575:1)]
7. 2 對索引的操作(不建議在代碼中使用)
- 創建索引對象
package com.es.pojo;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Document(indexName = "stu",type = "_doc")
public class Stu {
@Id
private Long stuid;
@Field(store = true)
private String name;
@Field()
private Integer age;
@Field(store = true)
private Float money;
@Field(store = true, type = FieldType.Keyword)
private String sign;
@Field(store = true)
private String description;
public Long getStuid() {
return stuid;
}
public void setStuid(Long stuid) {
this.stuid = stuid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Stu{" +
"stuid=" + stuid +
", name='" + name + '\'' +
", age=" + age +
", money=" + money +
", sign='" + sign + '\'' +
", description='" + description + '\'' +
'}';
}
}
- 創建索引
public void createIndexStu(){
Stu stu = new Stu();
stu.setStuid(1004L);
stu.setName("toto");
stu.setAge(30);
stu.setMoney(1999.8f);
stu.setSign("I am very wuwu");
stu.setDescription("i am fine");
IndexQuery indexQuery = new IndexQueryBuilder().withObject(stu).build();
esTemplate.index(indexQuery);
}
- 刪除索引
public void deleteIndexStu(){
esTemplate.deleteIndex(Stu.class);
}
7.3 對文檔操作
pojo對象還是用的上面的那個對象
- 修改文檔
public void updateStuDoc(){
Map map = new HashMap();
map.put("age",45);
IndexRequest indexRequest =new IndexRequest();
indexRequest.source(map);
UpdateQuery query = new UpdateQueryBuilder().withClass(Stu.class).withId("1001").withIndexRequest(indexRequest).build();
esTemplate.update(query);
}
- 查詢文檔
public void getStuDec(){
GetQuery query = new GetQuery();
query.setId("1001");
Stu stu = esTemplate.queryForObject(query,Stu.class);
System.out.println(stu);
}
- 刪除文檔
public void deleteStuDec(){
esTemplate.delete(Stu.class,"1001");
}
- 通過擴展原生查詢實現分頁查詢
public void searchStuDoc(){
//分頁參數
Pageable pageable = PageRequest.of(0,2);
//查詢語句
SearchQuery query = new NativeSearchQueryBuilder().withPageable(pageable).withQuery(QueryBuilders.matchQuery("sign","am")).build();
//查詢
AggregatedPage<Stu> pageStu = esTemplate.queryForPage(query,Stu.class);
//查詢結果
List<Stu> stuList = pageStu.getContent();
System.out.println("總頁數:"+pageStu.getTotalPages());
for(Stu s:stuList){
System.out.println(s);
}
}
- 通過重寫返回值實現高亮查詢
public void highlightStuDoc(){
String preTags = "<font color='red'>";
String postTags = "</font>";
//分頁配置
Pageable pageable = PageRequest.of(0,2);
//排序配置
SortBuilder sortBuilder = new FieldSortBuilder("money").order(SortOrder.ASC);
List<Stu> stuListHighlight = new ArrayList<>();
SearchQuery query = new NativeSearchQueryBuilder()
.withPageable(pageable)//分頁
.withQuery(QueryBuilders.matchQuery("sign","am"))//查詢
.withHighlightFields(new HighlightBuilder.Field("sign").preTags(preTags).postTags(postTags))//高亮
.withSort(sortBuilder)//排序
.build();
AggregatedPage<Stu> pageStu = esTemplate.queryForPage(query,Stu.class, new SearchResultMapper() {
//重寫返回結果
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
SearchHits hits = response.getHits();
for(SearchHit h:hits){
HighlightField highlightField=h.getHighlightFields().get("sign");
String sign = highlightField.getFragments()[0].toString();
Object stuId = (Object)h.getSourceAsMap().get("stuid");
String name = (String)h.getSourceAsMap().get("name");
Integer age = (Integer)h.getSourceAsMap().get("age");
String description = (String)h.getSourceAsMap().get("description");
Object money = (Object)h.getSourceAsMap().get("money");
Stu stuHL = new Stu();
stuHL.setDescription(description);
stuHL.setStuid(Long.valueOf(stuId.toString()));
stuHL.setName(name);
stuHL.setAge(age);
stuHL.setSign(sign);
stuHL.setMoney(Float.valueOf(money.toString()));
stuListHighlight.add(stuHL);
}
return new AggregatedPageImpl<>((List<T>)stuListHighlight);
}
});
List<Stu> stuList = pageStu.getContent();
System.out.println("總頁數:"+pageStu.getTotalPages());
for(Stu s:stuList){
System.out.println(s);
}
}
八. Logstash
8.1 什麼是Logstash
Logstash是elastic技術棧中的一個技術。它是一個數據採集引擎,可以從數據庫採集數據到es中。我們可以通過設置自增id主鍵或者時間來控制數據的自動同步,這個id或者時間就是用於給logstash進行識別的
- id:假設現在有1000條數據,Logstatsh識別後會進行一次同步,同步完會記錄這個id爲1000,以後數據庫新增數據,那麼id會一直累加,Logstatsh會有定時任務,發現有id大於1000了,則增量加入到es中
- 時間:同理,一開始同步1000條數據,每條數據都有一個字段,爲time,初次同步完畢後,記錄這個time,下次同步的時候進行時間比對,如果有超過這個時間的,那麼就可以做同步,這裏可以同步新增數據,或者修改元數據,因爲同一條數據的時間更改會被識別,而id則不會。
8.2 logstatsh數據同步 - 數據同步配置
- 解壓Logstash壓縮包
tar -zxvf logstash-6.4.3.tar.gz
- 將解壓後的文件放到
/usr/local/
(注:這步不是必須的,只是爲了好管理) - 在logstatsh下面創建sync文件夾
mkdir sync
- 將MySQL驅動放入這個文件夾下面
- 在
sync
下面創建配置文件logstash-db-sync.conf
vim logstash-db-sync.conf
5.1 配置文件:
input {
jdbc {
# 設置 MySql/MariaDB 數據庫url以及數據庫名稱
jdbc_connection_string => "jdbc:mysql://192.168.1.6:3306/foodie-shop-dev?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true"
# 用戶名和密碼
jdbc_user => "root"
jdbc_password => "root"
# 數據庫驅動所在位置,可以是絕對路徑或者相對路徑
jdbc_driver_library => "/usr/local/logstash-6.4.3/sync/mysql-connector-java-5.1.41.jar"
# 驅動類名
jdbc_driver_class => "com.mysql.jdbc.Driver"
# 開啓分頁
jdbc_paging_enabled => "true"
# 分頁每頁數量,可以自定義
jdbc_page_size => "10000"
# 執行的sql文件路徑
statement_filepath => "/usr/local/logstash-6.4.3/sync/foodie-items.sql"
# 設置定時任務間隔 含義:分、時、天、月、年,全部爲*默認含義爲每分鐘跑一次任務
schedule => "* * * * *"
# 索引類型
type => "_doc"
# 是否開啓記錄上次追蹤的結果,也就是上次更新的時間,這個會記錄到 last_run_metadata_path 的文件
use_column_value => true
# 記錄上一次追蹤的結果值
last_run_metadata_path => "/usr/local/logstash-6.4.3/sync/track_time"
# 如果 use_column_value 爲true, 配置本參數,追蹤的 column 名,可以是自增id或者時間
tracking_column => "updated_time"
# tracking_column 對應字段的類型
tracking_column_type => "timestamp"
# 是否清除 last_run_metadata_path 的記錄,true則每次都從頭開始查詢所有的數據庫記錄
clean_run => false
# 數據庫字段名稱大寫轉小寫
lowercase_column_names => false
}
}
output {
elasticsearch {
# es地址
hosts => ["192.168.1.187:9200"]
# 同步的索引名
index => "foodie-items"
# 設置_docID和數據相同,這個id是sql語句要有的
document_id => "%{id}"
}
# 日誌輸出
stdout {
codec => json_lines
}
}
- 創建數據庫查詢腳本,用來把mysql數據同步到es中
vim foodie-items.sql
- 跳回到Logstash的bin目錄下啓動Logstash,
./logstash -f /usr/local/logstash-6.4.3/sync/logstash-db-sync.conf
注:Logstash的版本要和es的版本一致
8.3 自定義模板配置中文分詞
如果沒有配置中文分詞器,那麼中文不會識別,這塊有兩種方式,一種就是手動創建索引,自己配置分詞器,一種就是自定義模板配置中文分詞。
- 查看Logstash默認模板
GET /_template/logstash
返回信息
{
"logstash": {
"order": 0,
"version": 60001,
"index_patterns": [
"logstash-*"
],
"settings": {
"index": {
"refresh_interval": "5s"
}
},
"mappings": {
"_default_": {
"dynamic_templates": [
{
"message_field": {
"path_match": "message",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"norms": false
}
}
},
{
"string_fields": {
"match": "*",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"norms": false,
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
],
"properties": {
"@timestamp": {
"type": "date"
},
"@version": {
"type": "keyword"
},
"geoip": {
"dynamic": true,
"properties": {
"ip": {
"type": "ip"
},
"location": {
"type": "geo_point"
},
"latitude": {
"type": "half_float"
},
"longitude": {
"type": "half_float"
}
}
}
}
}
},
"aliases": {}
}
}
- 修改模板
在string_fields下mapping節點中添加中文分詞器
"analyzer": "ik_max_word",
修改後的模板:
{
"order": 0,
"version": 1,
"index_patterns": ["*"],
"settings": {
"index": {
"refresh_interval": "5s"
}
},
"mappings": {
"_default_": {
"dynamic_templates": [
{
"message_field": {
"path_match": "message",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"norms": false
}
}
},
{
"string_fields": {
"match": "*",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"norms": false,
"analyzer": "ik_max_word",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
],
"properties": {
"@timestamp": {
"type": "date"
},
"@version": {
"type": "keyword"
},
"geoip": {
"dynamic": true,
"properties": {
"ip": {
"type": "ip"
},
"location": {
"type": "geo_point"
},
"latitude": {
"type": "half_float"
},
"longitude": {
"type": "half_float"
}
}
}
}
}
},
"aliases": {}
}
- 創建json文件,把上一步的模板放進去
vi /usr/local/logstash-6.4.3/sync/logstash-ik.json
- 在配置文件中新增配置
# 定義模板名稱
template_name => "myik"
# 模板所在位置
template => "/usr/local/logstash-6.4.3/sync/logstash-ik.json"
# 重寫模板
template_overwrite => true
# 默認爲true,false關閉logstash自動管理模板功能,如果自定義模板,則設置爲false
manage_template => false
- 重新運行Logstash進行同步
./logstash -f /usr/local/logstash-6.4.3/sync/logstash-db-sync.conf
注:最好是新建索引來做配置中文分詞