Java程序員如何通過 ElasticSearch 構(gòu)建極致的搜索體驗(yàn)?
搜索引擎在任何人的日常生活和工作中都承擔(dān)著很重要的角色,說到搜索大家想到的最多可能就是百度,谷歌,必應(yīng)等搜索引擎。
這些確實(shí)是 PC 互聯(lián)網(wǎng)時代的搜索先鋒,但是現(xiàn)在移動互聯(lián)網(wǎng)時代搜索已經(jīng)很普及了,各大應(yīng)用基本上都支持搜索,像抖音,微信,知乎等等應(yīng)用程序,都會內(nèi)置搜索引擎來實(shí)現(xiàn)自家內(nèi)容的搜索。
Elasticsearch 是一個實(shí)時的分布式搜索分析引擎,它的搜索速度和規(guī)模,堪稱前所未有。我們只需要把數(shù)據(jù)按照規(guī)定的索引格式去存儲,后續(xù)就可以進(jìn)行極致的搜索,因此 Elasticsearch 被廣泛的應(yīng)用于各大互聯(lián)網(wǎng)公司。
根據(jù) Elasticsearch 的官方介紹,Wikipedia,Github,Stack Overflow 等大廠都在使用。
Wikipedia 使用 Elasticsearch 提供帶有高亮片段的全文搜索,還有 search-as-you-type 和 did-you-mean 的建議。
衛(wèi)報(bào)使用 Elasticsearch 將網(wǎng)絡(luò)社交數(shù)據(jù)結(jié)合到訪客日志中,為它的編輯們提供公眾對于新文章的實(shí)時反饋。
Stack Overflow 將地理位置查詢?nèi)谌肴臋z索中去,并且使用 more-like-this 接口去查找相關(guān)的問題和回答。
GitHub 使用 Elasticsearch 對1300億行代碼進(jìn)行查詢。
安裝使用
Elasticsearch 提供了開箱即用的功能,我們通過在官網(wǎng) https://www.elastic.co/downloads/elasticsearch 下載最新的符合自己電腦系統(tǒng)的穩(wěn)定版本,然后解壓后執(zhí)行./bin/elasticsearch
顯示 successfully 表示啟動成功,再通過執(zhí)行命令curl 'http://localhost:9200/?pretty' 可以看到如下輸出,表示 Elasticsearch 本地啟動成功。
在使用 Elasticsearch 之前,我們先簡單介紹一個 Elasticsearch 的存儲結(jié)構(gòu),便于我們后面進(jìn)行學(xué)習(xí)。
首先我們要知道一個事情那就是 Elasticsearch 是面向文檔的,所謂文檔就是一個 document,如果用過 MongoDB的話,小伙伴對文檔應(yīng)該比較熟悉,是一個 NoSQL 的形式,可以理解為一個JSON 形式的結(jié)構(gòu),跟我們常用的 MySQL 關(guān)系型的結(jié)構(gòu)不一樣,目前基本上任何一門語言的對象都可以直接轉(zhuǎn)化成 JSON 形式,這極大方便了我們的使用。
文檔的形式
文檔的組成由文檔數(shù)據(jù)和元數(shù)據(jù)組成,其中元數(shù)據(jù)包括_index,_type,_id 三個特別重要的元數(shù)據(jù),其中 _index 表示文檔在哪存放,_type 表示文檔的對象類別,_id文檔唯一標(biāo)識。
雖然 Elasticsearch 是以文檔形式存儲的,但這里我們可以用關(guān)系型數(shù)據(jù)庫作類比,比如這里的_index 可以類似于 MySQL 的 database,_type 類似有 MySQL 的 table,其中_id 類似于 ID 字段。
與 Elasticsearch 進(jìn)行交互
通過官方文檔我們可以知道一個 Elasticsearch 請求和任何 HTTP 請求一樣由若干相同的部件組成:curl -X
被 < > 標(biāo)記的部分表示含義如下:
標(biāo)記 | 含義 |
---|---|
VERB |
適當(dāng)?shù)?HTTP 方法 或 謂詞 : GET 、 POST 、 PUT 、 HEAD 或者DELETE 。 |
PROTOCOL |
http 或者 https (如果你在 Elasticsearch 前面有一個 https 代理) |
HOST |
Elasticsearch 集群中任意節(jié)點(diǎn)的主機(jī)名,或者用 localhost 代表本地機(jī)器上的節(jié)點(diǎn)。 |
PORT |
運(yùn)行 Elasticsearch HTTP 服務(wù)的端口號,默認(rèn)是 9200 。 |
PATH |
API 的終端路徑(例如 _count 將返回集群中文檔數(shù)量)。Path 可能包含多個組件,例如:_cluster/stats 和 _nodes/stats/jvm 。 |
QUERY_STRING |
任意可選的查詢字符串參數(shù) (例如 ?pretty 將格式化地輸出 JSON 返回值,使其更容易閱讀) |
BODY |
一個 JSON 格式的請求體 (如果請求需要的話) |
示例
查看 Elasticsearch 集群中文檔的個數(shù):
- curl -XGET 'http://localhost:9200/_count?pretty' -H 'Content-Type:application/json' -d '
- "query": {
- "match_all": {}
- }
- '
返回如下,其中 count 為 0,表示我們集群中暫時還沒有文檔:
索引文檔
通過我們上面提到的內(nèi)容,這里我們嘗試進(jìn)行一個文檔的索引,語句如下,然后再查詢一下文檔的數(shù)據(jù),結(jié)果如下
- curl -XPUT 'http://localhost:9200/student/class1/1?pretty' -H 'Content-Type:application/json' -d '
- {
- "name": "ziyou",
- "age": "18",
- "date": "2021/12/19"
- }
- '
這里我們通過像 student 索引 class1 的 type 下面索引了一篇 id 為 1 的學(xué)生,通過 pretty 參數(shù)將返回美化查看,通過上面的操作,現(xiàn)在我們的 Elasticsearch 集群里面已經(jīng)存在了一個 id 為 1 的學(xué)生了。
查詢文檔
索引文檔過后,我們再根據(jù)下面的語句進(jìn)行文檔的獲取
- curl -XGET 'http://localhost:9200/student/class1/1?pretty'
更新文檔
我們可以通過前面 PUT 語句再次執(zhí)行,進(jìn)行文檔的更新,如下所示
- curl -XPUT 'http://localhost:9200/student/class1/1?pretty' -H 'Content-Type:application/json' -d '
- {
- "name": "ziyou",
- "age": "20",
- "date": "2021/12/19"
- }
說明:可以看到 age 這個字段已經(jīng)變更了,但是這里我們還看到多了一個 version 字段,正常這里應(yīng)該是 2 ,阿粉只是多操作了幾次所以這里是 7。
需要說明的是,更新文檔并不是更新原來的文檔,Elasticsearch 底層幫我們把原來的文檔標(biāo)記成刪除狀態(tài),然后創(chuàng)建了一個新的文檔,再加上了一個版本號,因?yàn)槲臋n ID 是沒有變化的。
當(dāng)隨著我們索引數(shù)據(jù)的越來越多,Elasticsearch 底層會幫我們清理這些刪除的文檔數(shù)據(jù),從我們的視角來看,就是文檔已經(jīng)更新了。
刪除文檔
- curl -XDELETE 'http://localhost:9200/student/class1/1
通過 DELETE 指令,我們可以將文檔進(jìn)行刪除,刪除也同更新一樣,只是標(biāo)記為刪除狀態(tài),并不會立馬從磁盤中刪除,隨著不斷的索引更多的數(shù)據(jù),Elasticsearch 將會在后臺清理標(biāo)記為已刪除的文檔。同時進(jìn)行刪除的時候,version 版本也會進(jìn)行增加。