Elasticsearch 簡介和實(shí)戰(zhàn)

最近項(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ù)

摘自 Elasticsearch: 權(quán)威指南

回憶時(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

image

可以使用開發(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ì)用法

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容