最近項(xiàng)目要用到全文搜索,需要有中文、拼音檢索以及混合搜索以及數(shù)據(jù)聚合功能,使用到了 Elsaticsearch
關(guān)于 Elasticsearch
Elasticsearch 是一個(gè)基于 Lucene 的搜索服務(wù)器。它提供了一個(gè)分布式多用戶能力的全文搜索引擎,Elasticsearch 是用 Java 語言開發(fā)的,基于 RESTful web 接口,其客戶端在其他語言中都是可用的
Lucene 被認(rèn)為是目前最先進(jìn),性能最好、功能最全的搜索引擎庫,不過,Lucene 只是一個(gè)庫,需要使用 java 集成到應(yīng)用中,而且 Lucene 是非常復(fù)雜的,需要深入了解檢索的相關(guān)知識來理解它的工作原理。一般我們會選擇 Solr 和 Elasticsearch 來做搜索服務(wù),兩者的對比可以網(wǎng)上自行了解
Elasticsearch 基于 Lucene,提供一套簡單一致的 RESTful API,隱藏 Lucene 的復(fù)雜性,使得全文檢索變得更簡單,不過 Elasticsearch 也不僅僅只是全文搜索引擎
- 一個(gè)分布式的實(shí)時(shí)文檔存儲,每個(gè)字段 可以被索引與搜索
- 一個(gè)分布式實(shí)時(shí)分析搜索引擎
- 能勝任上百個(gè)服務(wù)節(jié)點(diǎn)的擴(kuò)展,并支持 PB 級別的結(jié)構(gòu)化或者非結(jié)構(gòu)化數(shù)據(jù)
回憶時(shí)光
許多年前,一個(gè)剛結(jié)婚的名叫 Shay Banon 的失業(yè)開發(fā)者,跟著他的妻子去了倫敦,他的妻子在那里學(xué)習(xí)廚師。 在尋找一個(gè)賺錢的工作的時(shí)候,為了給他的妻子做一個(gè)食譜搜索引擎,他開始使用 Lucene 的一個(gè)早期版本。
直接使用 Lucene 是很難的,因此 Shay 開始做一個(gè)抽象層,Java 開發(fā)者使用它可以很簡單的給他們的程序添加搜索功能。 他發(fā)布了他的第一個(gè)開源項(xiàng)目 Compass。
后來 Shay 獲得了一份工作,主要是高性能,分布式環(huán)境下的內(nèi)存數(shù)據(jù)網(wǎng)格。這個(gè)對于高性能,實(shí)時(shí),分布式搜索引擎的需求尤為突出, 他決定重寫 Compass,把它變?yōu)橐粋€(gè)獨(dú)立的服務(wù)并取名 Elasticsearch。
第一個(gè)公開版本在2010年2月發(fā)布,從此以后,Elasticsearch 已經(jīng)成為了 Github 上最活躍的項(xiàng)目之一,他擁有超過300名 contributors(目前736名 contributors )。 一家公司已經(jīng)開始圍繞 Elasticsearch 提供商業(yè)服務(wù),并開發(fā)新的特性,但是,Elasticsearch 將永遠(yuǎn)開源并對所有人可用。
據(jù)說,Shay 的妻子還在等著她的食譜搜索引擎…
Elasticsearch 安裝
從官網(wǎng) elastic.co下載最新或合適版本的 Elasticsearch(這里是7.6.2)
解壓之后進(jìn)入目錄下
修改配置文件config/elasticsearch.yml
vim config/elasticsearch.yml
# 集群名稱,建議修改,防止誤用默認(rèn)集群
cluster.name: es-zou
# 配置綁定地址,配置外網(wǎng)可以訪問(或本地地址)
network.host: 0.0.0.0
# 配置訪問端口
http.port: 9200
運(yùn)行命令
bin/elasticsearch
# 后臺啟動(dòng)
bin/elasticsearch -d
運(yùn)行 curl http://localhost:9200/ 可以看到以下信息,啟動(dòng)成功
{
"name" : "DESKTOP-G11TC44",
"cluster_name" : "es-zou",
"cluster_uuid" : "yoq-PT-sTVml0H0Vrna6xQ",
"version" : {
"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "zip",
"build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date" : "2020-03-26T06:34:37.794943Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
在 Linux 下,network.host 設(shè)置為 0.0.0.0 啟動(dòng)可能遇見的問題
[1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
切換到root用戶,修改配置文件 /etc/security/limits.conf,增加配置
vi /etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536
[2]: max number of threads [3818] for user [es] is too low, increase to at least [4096]
最大線程個(gè)數(shù)太低。修改配置文件 etc/security/limits.conf,增加配置
vi /etc/security/limits.conf
* soft nproc 4096
* hard nproc 4096
[3]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
修改 /etc/sysctl.conf,增加配置
vi /etc/sysctl.conf
vm.max_map_count=262144
執(zhí)行命令 sysctl -p 生效
[4]: system call filters failed to install; check the logs and fix your configuration or disable system call filters at your own risk
問題原因:因?yàn)?Centos6 不支持 SecComp,而ES5.2.1默認(rèn) bootstrap.system_call_filter 為 true 進(jìn)行檢測,所以導(dǎo)致檢測失敗,失敗后直接導(dǎo)致ES不能啟動(dòng)
解決方法:在 elasticsearch.yml 中配置 bootstrap.system_call_filter 為 false,注意要在 Memory下面:
bootstrap.memory_lock: false
bootstrap.system_call_filter: false
Kibana 安裝
Kibana 是官方的數(shù)據(jù)可視化工具,不過我們暫時(shí)用不到那些數(shù)據(jù)分析的功能,其中有個(gè) Dev Tools 開發(fā)工具可以比較方便的與 Elasticsearch 服務(wù)進(jìn)行交互
下載對應(yīng) Elasticsearch 版本的 Kibana 并解壓(與 Elasticsearch 保持一致,這里都是 7.6.2)
編輯配置文件 config/kibana.yml
vim config/kibana.yml
# 服務(wù)地址,對外暴露地址,(服務(wù)器地址)
#server.host: "localhost"
server.host: "127.0.0.1"
# 配置 elasticsearch 地址
elasticsearch.hosts: ["http://localhost:9200"]
# 中文支持
i18n.locale: "zh-CN"
啟動(dòng)命令
bin/kibana
# 使用nohup命令 后臺啟動(dòng)
nohup bin/kibana >/dev/null &
啟動(dòng)后,瀏覽器輸入地址 http://localhost:5601

可以使用開發(fā)工具 Dev Tools 與 Elasticsearch 服務(wù)進(jìn)行交互
基本概念
操作之前,先簡單了解一波 Elasticsearch 中的數(shù)據(jù)模型和一些基本概念
全文搜索(full-text search)
全文檢索是指計(jì)算機(jī)索引程序通過掃描文章中的每一個(gè)詞,對每一個(gè)詞建立一個(gè)索引,指明該詞在文章中出現(xiàn)的次數(shù)和位置,當(dāng)用戶查詢時(shí),檢索程序就根據(jù)事先建立的索引進(jìn)行查找,并將查找的結(jié)果反饋給用戶的檢索方式。這個(gè)過程類似于通過字典中的檢索字表查字的過程。全文搜索搜索引擎數(shù)據(jù)庫中的數(shù)據(jù)
集群、節(jié)點(diǎn)(cluster & node)
一個(gè)節(jié)點(diǎn)(node)就是一個(gè) Elasticsearch 實(shí)例,而一個(gè)集群(cluster)由一個(gè)或多個(gè)節(jié)點(diǎn)組成,它們具有相同的 cluster.name (默認(rèn)為 “elasticsearch”),節(jié)點(diǎn)可以通過這個(gè)集群名加入群集,可以在 elasticsearch.yml 自定義集群名稱和節(jié)點(diǎn)名稱
# Use a descriptive name for your cluster:
cluster.name: my-application
# Use a descriptive name for the node:
node.name: node-1
索引(index)
index 包含兩層意思,一是名詞索引,類似于關(guān)系型數(shù)據(jù)庫中的一個(gè)數(shù)據(jù)庫,是一個(gè)存儲關(guān)系型文檔的地方;二是動(dòng)詞,表示建立索引,存儲一個(gè)文檔到索引中以被檢索查詢
一個(gè) Elasticsearch 集群可以包含多個(gè) 索引 ,相應(yīng)的每個(gè)索引可以包含多個(gè) 類型 ,這些不同的類型存儲著多個(gè) 文檔 ,每個(gè)文檔又有多個(gè) 屬性 。我們可以與關(guān)系型數(shù)據(jù)庫做個(gè)簡單對比
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields
類型(mapping type)
之前的版本中,每個(gè)索引下可以建立多個(gè)類型,存儲文檔的時(shí)候需要指定 index 和 type,但是從 6.0 開始每個(gè)索引只能有一個(gè)類型,7.0 以后不建議使用,8.0 以后將完全不支持
為什么要移除映射類型
開始的時(shí)候,我們把索引(index)和類型(type)類比于SQL數(shù)據(jù)庫中的 database 和 table,但是這樣類比是不合適的。在SQL數(shù)據(jù)庫中,表之間是相互獨(dú)立的。一個(gè)表中的各列并不會影響到其它表中的同名的列。而在映射類型(mapping type)中卻不是這樣的。
在同一個(gè) Elasticsearch 索引中,其中不同映射類型中的同名字段在內(nèi)部是由同一個(gè) Lucene 字段來支持的。換句話說,使用上面的例子,user 類型中的 user_name 字段與 tweet 類型中的 user_name 字段是完全一樣的,并且兩個(gè) user_name 字段在兩個(gè)類型中必須具有相同的映射(定義)。
這會在某些情況下導(dǎo)致一些混亂,比如,在同一個(gè)索引中,當(dāng)你想在其中的一個(gè)類型中將 deleted 字段作為 date 類型,而在另一個(gè)類型中將其作為 boolean 字段。
在此之上需要考慮一點(diǎn),如果同一個(gè)索引中存儲的各個(gè)實(shí)體如果只有很少或者根本沒有同樣的字段,這種情況會導(dǎo)致稀疏數(shù)據(jù),并且會影響到Lucene的高效壓縮數(shù)據(jù)的能力
文檔(document)
索引里存儲的單條數(shù)據(jù),被索引信息的基本單位
Elasticsearch 是面向文檔(document oriented)的,這意味著它可以存儲整個(gè)對象或文檔(document),還會索引(index)每個(gè)文檔的內(nèi)容使之可以被搜索。在 Elasticsearch 中,你可以對文檔(而非成行成列的數(shù)據(jù))進(jìn)行索引、搜索、排序、過濾。這種理解數(shù)據(jù)的方式與以往完全不同,這也是Elasticsearch能夠執(zhí)行復(fù)雜的全文搜索的原因之一
映射、字段(mapping & field)
Elasticsearch 是使用 JSON 作為文檔序列化格式,映射就定義了文檔的結(jié)構(gòu),會包含許多字段。一個(gè)映射定義了字段類型,每個(gè)字段的數(shù)據(jù)類型,以及字段被 Elasticsearch 處理的方式。映射還用于設(shè)置關(guān)聯(lián)到類型上的元數(shù)據(jù)
快速入門
使用 RESTful API 通過端口 9200 可以和 Elasticsearch 進(jìn)行交互,可以使用 curl 命令,也可以用 Kibana 的 Dev Tools 更加方便
這里簡單創(chuàng)建一個(gè)索引,并添加幾條數(shù)據(jù)
創(chuàng)建索引
用 curl 命令創(chuàng)建了一個(gè) commodity 商品索引
curl -X PUT "localhost:9200/commodity?pretty"
也使用 Kibana,并配置參數(shù)和映射
PUT /commodity
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"commodity_id": {
"type": "long"
},
"commodity_name": {
"type": "text"
},
"picture_url": {
"type": "keyword"
},
"price": {
"type": "double"
}
}
}
}
創(chuàng)建了一個(gè)分片數(shù)為1,副本數(shù)為1的索引,沒有指定類型,默認(rèn)會創(chuàng)建一個(gè) _doc 類型,有四個(gè)不同類型的字段,創(chuàng)建成功返回如下結(jié)果
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "commodity"
}
添加文檔數(shù)據(jù)
PUT /commodity/_doc/1
{
"commodity_id": 1,
"commodity_name": "全面屏手機(jī)",
"picture_url": "/commodity/1",
"price": 1999
}
這里是在 commodity 索引的 _doc 類型下創(chuàng)建一個(gè) id 為 1 的文檔數(shù)據(jù),創(chuàng)建成功
{
"_index" : "commodity",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
查詢
查詢所有
POST /commodity/_search
查詢名稱
POST /commodity/_search
{
"query": {
"match": {
"commodity_name": "全面"
}
}
}
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.9646722,
"hits" : [
{
"_index" : "commodity",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.9646722,
"_source" : {
"commodity_id" : 1,
"commodity_name" : "全面屏手機(jī)",
"picture_url" : "/commodity/1",
"price" : 1999
}
}
]
}
}
后面再去總結(jié) API 的詳細(xì)用法