1. ElasticSearch概述
Elaticsearch,簡(jiǎn)稱為es, es是一個(gè)開(kāi)源的高擴(kuò)展的分布式全文檢索引擎,它可以近乎實(shí)時(shí)的存儲(chǔ)、檢索數(shù)據(jù);本身擴(kuò)展性很好,可以擴(kuò)展到上百臺(tái)服務(wù)器,處理PB級(jí)別(大數(shù)據(jù)時(shí)代)的數(shù)據(jù)。es也使用Java開(kāi)發(fā)并使用Lucene作為其核心來(lái)實(shí)現(xiàn)所有索引和搜索的功能,但是它的目的是通過(guò)簡(jiǎn)單的RESTful API來(lái)隱藏Lucene的復(fù)雜性,從而讓全文搜索變得簡(jiǎn)單。
據(jù)國(guó)際權(quán)威的數(shù)據(jù)庫(kù)產(chǎn)品評(píng)測(cè)機(jī)構(gòu)DB Engines的統(tǒng)計(jì),在2016年1月,ElasticSearch已超過(guò)Solr等,成為排名第一的搜索引擎類應(yīng)用。
2. ES和solr的差別
2.1 Elasticsearch簡(jiǎn)介
Elasticsearch是一個(gè)實(shí)時(shí)分布式搜索和分析引擎。它讓你以前所未有的速度處理大數(shù)據(jù)成為可能。
它用于全文搜索、結(jié)構(gòu)化搜索、分析以及將這三者混合使用:
維基百科使用Elasticsearch提供全文搜索并高亮關(guān)鍵字,以及輸入實(shí)時(shí)搜索(search-asyou-type)和搜索糾錯(cuò)(did-you-mean)等搜索建議功能。
英國(guó)衛(wèi)報(bào)使用Elasticsearch結(jié)合用戶日志和社交網(wǎng)絡(luò)數(shù)據(jù)提供給他們的編輯以實(shí)時(shí)的反饋,以便及時(shí)了解公眾對(duì)新發(fā)表的文章的回應(yīng)。
StackOverflow結(jié)合全文搜索與地理位置查詢,以及more-like-this功能來(lái)找到相關(guān)的問(wèn)題和答案。
Github使用Elasticsearch檢索1300億行的代碼。
但是Elasticsearch不僅用于大型企業(yè),它還讓像DataDog以及Klout這樣的創(chuàng)業(yè)公司將最初的想法變成可擴(kuò)展的解決方案。
Elasticsearch可以在你的筆記本上運(yùn)行,也可以在數(shù)以百計(jì)的服務(wù)器上處理PB級(jí)別的數(shù)據(jù) 。
Elasticsearch是一個(gè)基于Apache Lucene(TM)的開(kāi)源搜索引擎。無(wú)論在開(kāi)源還是專有領(lǐng)域,Lucene可以被認(rèn)為是迄今為止最先進(jìn)、性能最好的、功能最全的搜索引擎庫(kù)。
但是,Lucene只是一個(gè)庫(kù)。想要使用它,你必須使用Java來(lái)作為開(kāi)發(fā)語(yǔ)言并將其直接集成到你的應(yīng)用中,更糟糕的是,Lucene非常復(fù)雜,你需要深入了解檢索的相關(guān)知識(shí)來(lái)理解它是如何工作的。
Elasticsearch也使用Java開(kāi)發(fā)并使用Lucene作為其核心來(lái)實(shí)現(xiàn)所有索引和搜索的功能,但是它的目的是通過(guò)簡(jiǎn)單的RESTful API來(lái)隱藏Lucene的復(fù)雜性,從而讓全文搜索變得簡(jiǎn)單。
2.2 Solr簡(jiǎn)介
Solr 是Apache下的一個(gè)頂級(jí)開(kāi)源項(xiàng)目,采用Java開(kāi)發(fā),它是基于Lucene的全文搜索服務(wù)器。Solr提供了比Lucene更為豐富的查詢語(yǔ)言,同時(shí)實(shí)現(xiàn)了可配置、可擴(kuò)展,并對(duì)索引、搜索性能進(jìn)行了優(yōu)化
Solr可以獨(dú)立運(yùn)行,運(yùn)行在Jetty、Tomcat等這些Servlet容器中,Solr 索引的實(shí)現(xiàn)方法很簡(jiǎn)單,用 POST方法向 Solr 服務(wù)器發(fā)送一個(gè)描述 Field 及其內(nèi)容的 XML 文檔,Solr根據(jù)xml文檔添加、刪除、更新索引。Solr 搜索只需要發(fā)送 HTTP GET 請(qǐng)求,然后對(duì) Solr 返回Xml、json等格式的查詢結(jié)果進(jìn)行解析,組織頁(yè)面布局。Solr不提供構(gòu)建UI的功能,Solr提供了一個(gè)管理界面,通過(guò)管理界面可以查詢Solr的配置和運(yùn)行情況。
solr是基于lucene開(kāi)發(fā)企業(yè)級(jí)搜索服務(wù)器,實(shí)際上就是封裝了lucene。
Solr是一個(gè)獨(dú)立的企業(yè)級(jí)搜索應(yīng)用服務(wù)器,它對(duì)外提供類似于Web-service的API接口。用戶可以通過(guò)http請(qǐng)求,向搜索引擎服務(wù)器提交一定格式的文件,生成索引;也可以通過(guò)提出查找請(qǐng)求,并得到返回結(jié)果。
2.3 Lucene簡(jiǎn)介
Lucene是apache軟件基金會(huì)4 jakarta項(xiàng)目組的一個(gè)子項(xiàng)目,是一個(gè)開(kāi)放源代碼的全文檢索引擎工具包,但它不是一個(gè)完整的全文檢索引擎,而是一個(gè)全文檢索引擎的架構(gòu),提供了完整的查詢引擎和索引引擎,部分文本分析引擎(英文與德文兩種西方語(yǔ)言)。Lucene的目的是為軟件開(kāi)發(fā)人員提供一個(gè)簡(jiǎn)單易用的工具包,以方便的在目標(biāo)系統(tǒng)中實(shí)現(xiàn)全文檢索的功能,或者是以此為基礎(chǔ)建立起完整的全文檢索引擎。Lucene是一套用于全文檢索和搜尋的開(kāi)源程式庫(kù),由Apache軟件基金會(huì)支持和提供。Lucene提供了一個(gè)簡(jiǎn)單卻強(qiáng)大的應(yīng)用程式接口,能夠做全文索引和搜尋。在Java開(kāi)發(fā)環(huán)境里L(fēng)ucene是一個(gè)成熟的免費(fèi)開(kāi)源工具。就其本身而言,Lucene是當(dāng)前以及最近幾年最受歡迎的免費(fèi)Java信息檢索程序庫(kù)。人們經(jīng)常提到信息檢索程序庫(kù),雖然與搜索引擎有關(guān),但不應(yīng)該將信息檢索程序庫(kù)與搜索引擎相混淆。
Lucene是一個(gè)全文檢索引擎的架構(gòu)。那什么是全文搜索引擎?
全文搜索引擎是名副其實(shí)的搜索引擎,國(guó)外具代表性的有Google、Fast/AllTheWeb、AltaVista、Inktomi、Teoma、WiseNut等,國(guó)內(nèi)著名的有百度(Baidu)。它們都是通過(guò)從互聯(lián)網(wǎng)上提取的各個(gè)網(wǎng)站的信息(以網(wǎng)頁(yè)文字為主)而建立的數(shù)據(jù)庫(kù)中,檢索與用戶查詢條件匹配的相關(guān)記錄,然后按一定的排列順序?qū)⒔Y(jié)果返回給用戶,因此他們是真正的搜索引擎。
從搜索結(jié)果來(lái)源的角度,全文搜索引擎又可細(xì)分為兩種,一種是擁有自己的檢索程序(Indexer),俗稱“蜘蛛”(Spider)程序或“機(jī)器人”(Robot)程序,并自建網(wǎng)頁(yè)數(shù)據(jù)庫(kù),搜索結(jié)果直接從自身的數(shù)據(jù)庫(kù)中調(diào)用,如上面提到的7家引擎;另一種則是租用其他引擎的數(shù)據(jù)庫(kù),并按自定的格式排列搜索結(jié)果,如Lycos引擎。
2.4 Elasticsearch和Solr比較




2.5 ElasticSearch vs Solr 總結(jié)
- es基本是開(kāi)箱即用(解壓就可以用 ! ),非常簡(jiǎn)單。Solr安裝略微復(fù)雜一丟丟!
- Solr 利用 Zookeeper 進(jìn)行分布式管理,而 Elasticsearch 自身帶有分布式協(xié)調(diào)管理功能。
- Solr 支持更多格式的數(shù)據(jù),比如JSON、XML、CSV,而 Elasticsearch 僅支持json文件格式。
- Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高級(jí)功能多有第三方插件提供,例如圖形化界面需要kibana友好支撐~!
- Solr 查詢快,但更新索引時(shí)慢(即插入刪除慢),用于電商等查詢多的應(yīng)用;
- ES建立索引快(即查詢慢),即實(shí)時(shí)性查詢快,用于facebook新浪等搜索。
- Solr 是傳統(tǒng)搜索應(yīng)用的有力解決方案,但 Elasticsearch 更適用于新興的實(shí)時(shí)搜索應(yīng)用。
- Solr比較成熟,有一個(gè)更大,更成熟的用戶、開(kāi)發(fā)和貢獻(xiàn)者社區(qū),而 Elasticsearch相對(duì)開(kāi)發(fā)維護(hù)者較少,更新太快,學(xué)習(xí)使用成本較高。(趨勢(shì)?。?/li>
3. ElasticSearch安裝
聲明:JDK1.8 ,最低要求! ElasticSearch 客戶端,界面工具!
Java開(kāi)發(fā),ElasticSearch 的版本和我們之后對(duì)應(yīng)的 Java 的核心jar包! 版本對(duì)應(yīng)!JDK 環(huán)境是正常!
下載
官網(wǎng):https://www.elastic.co/
下載地址:https://www.elastic.co/cn/downloads/elasticsearch
window 下安裝!
3.1 解壓就可以使用了!

3.2 熟悉目錄!
bin 啟動(dòng)文件
config 配置文件
log4j2 日志配置文件
jvm.options java 虛擬機(jī)相關(guān)的配置
elasticsearch.yml elasticsearch 的配置文件! 默認(rèn) 9200 端口! 跨域!
lib 相關(guān)jar包
logs 日志!
modules 功能模塊
plugins 插件!
3.3 啟動(dòng),訪問(wèn)9200;
啟動(dòng)不起來(lái)在elasticsearch.yml末尾添加
xpack.ml.enabled: false

3.4 訪問(wèn)測(cè)試!

安裝可視化界面 es head的插件
需要node.js環(huán)境
-
啟動(dòng)
npm install npm run start -
連接測(cè)試發(fā)現(xiàn),存在跨域問(wèn)題:配置es
http.cors.enabled: true http.cors.allow-origin: "*" -
重啟es服務(wù)器,然后再次連接
初學(xué),就把es當(dāng)做一個(gè)數(shù)據(jù)庫(kù)! (可以建立索引(庫(kù)),文檔(庫(kù)中的數(shù)據(jù)!))
這個(gè)head我們就把它當(dāng)做數(shù)據(jù)展示工具!我們后面所有的查詢,Kibana!
了解 ELK
ELK是Elasticsearch、Logstash、Kibana三大開(kāi)源框架首字母大寫(xiě)簡(jiǎn)稱。市面上也被成為ElasticStack。其中Elasticsearch是一個(gè)基于Lucene、分布式、通過(guò)Restful方式進(jìn)行交互的近實(shí)時(shí)搜索平臺(tái)框架。像類似百度、谷歌這種大數(shù)據(jù)全文搜索引擎的場(chǎng)景都可以使用Elasticsearch作為底層支持框架,可見(jiàn)Elasticsearch提供的搜索能力確實(shí)強(qiáng)大,市面上很多時(shí)候我們簡(jiǎn)稱Elasticsearch為es。Logstash是ELK的中央數(shù)據(jù)流引擎,用于從不同目標(biāo)(文件/數(shù)據(jù)存儲(chǔ)/MQ)收集的不同格式數(shù)據(jù),經(jīng)過(guò)過(guò)濾后支持輸出到不同目的地(文件/MQ/redis/elasticsearch/kafka等)。Kibana可以將elasticsearch的數(shù)據(jù)通過(guò)友好
的頁(yè)面展示出來(lái),提供實(shí)時(shí)分析的功能。
市面上很多開(kāi)發(fā)只要提到ELK能夠一致說(shuō)出它是一個(gè)日志分析架構(gòu)技術(shù)??偡Q,但實(shí)際上ELK不僅僅適用于日志分析,它還可以支持其它任何數(shù)據(jù)分析和收集的場(chǎng)景,日志分析和收集只是更具有代表性。并非唯一性。

安裝Kibana
Kibana是一個(gè)針對(duì)Elasticsearch的開(kāi)源分析及可視化平臺(tái),用來(lái)搜索、查看交互存儲(chǔ)在Elasticsearch索引中的數(shù)據(jù)。使用Kibana,可以通過(guò)各種圖表進(jìn)行高級(jí)數(shù)據(jù)分析及展示。Kibana讓海量數(shù)據(jù)更容易理解。它操作簡(jiǎn)單,基于瀏覽器的用戶界面可以快速創(chuàng)建儀表板(dashboard)實(shí)時(shí)顯示Elasticsearch查詢動(dòng)態(tài)。設(shè)置Kibana非常簡(jiǎn)單。無(wú)需編碼或者額外的基礎(chǔ)架構(gòu),幾分鐘內(nèi)就可以完成Kibana安裝并啟動(dòng)Elasticsearch索引監(jiān)測(cè)
官網(wǎng):https://www.elastic.co/cn/kibana
Kibana 版本要和 Es 一致!
啟動(dòng)測(cè)試:
-
解壓后端的目錄
-
啟動(dòng)
-
訪問(wèn)測(cè)試
-
開(kāi)發(fā)工具! (Post、curl、head、谷歌瀏覽器插件測(cè)試?。?/p>
-
漢化!自己修改kibana配置即可! zh-CN!
kibaba.yml文件末尾添加
i18n.locale: "zn-CH"
4. ES核心概念
- 索引
- 字段類型(mapping)
- 文檔(documents)
概述
在前面的學(xué)習(xí)中,我們已經(jīng)掌握了es是什么,同時(shí)也把es的服務(wù)已經(jīng)安裝啟動(dòng),那么es是如何去存儲(chǔ)數(shù)據(jù),數(shù)據(jù)結(jié)構(gòu)是什么,又是如何實(shí)現(xiàn)搜索的呢?我們先來(lái)聊聊ElasticSearch的相關(guān)概念吧!
集群,節(jié)點(diǎn),索引,類型,文檔,分片,映射是什么?
elasticsearch是面向文檔,關(guān)系行數(shù)據(jù)庫(kù) 和 elasticsearch 客觀的對(duì)比!一切都是JSON!
| Relational DB | Elasticsearch |
|---|---|
| 數(shù)據(jù)庫(kù)(database) | 索引(indices) |
| 表(tables) | types |
| 行(rows) | documents |
| 字段(columns) | fields |
elasticsearch(集群)中可以包含多個(gè)索引(數(shù)據(jù)庫(kù)),每個(gè)索引中可以包含多個(gè)類型(表),每個(gè)類型下又包含多 個(gè)文檔(行),每個(gè)文檔中又包含多個(gè)字段(列)。
物理設(shè)計(jì):
elasticsearch 在后臺(tái)把每個(gè)索引劃分成多個(gè)分片,每分分片可以在集群中的不同服務(wù)器間遷移
一個(gè)人就是一個(gè)集群!默認(rèn)的集群名稱就是 elaticsearh

邏輯設(shè)計(jì):
一個(gè)索引類型中,包含多個(gè)文檔,比如說(shuō)文檔1,文檔2。 當(dāng)我們索引一篇文檔時(shí),可以通過(guò)這樣的一各順序找到 它: 索引 ? 類型 ? 文檔ID ,通過(guò)這個(gè)組合我們就能索引到某個(gè)具體的文檔。 注意:ID不必是整數(shù),實(shí)際上它是個(gè)字 符串。
文檔
就是我們的一條條數(shù)據(jù)
user
1 zhangsan 18
2 kuangshen 3
之前說(shuō)elasticsearch是面向文檔的,那么就意味著索引和搜索數(shù)據(jù)的最小單位是文檔,elasticsearch中,文檔有幾個(gè) 重要屬性 :
- 自我包含,一篇文檔同時(shí)包含字段和對(duì)應(yīng)的值,也就是同時(shí)包含 key:value!
- 可以是層次型的,一個(gè)文檔中包含自文檔,復(fù)雜的邏輯實(shí)體就是這么來(lái)的! {就是一個(gè)json對(duì)象!fastjson進(jìn)行自動(dòng)轉(zhuǎn)換!}
- 靈活的結(jié)構(gòu),文檔不依賴預(yù)先定義的模式,我們知道關(guān)系型數(shù)據(jù)庫(kù)中,要提前定義字段才能使用,在elasticsearch中,對(duì)于字段是非常靈活的,有時(shí)候,我們可以忽略該字段,或者動(dòng)態(tài)的添加一個(gè)新的字段。
盡管我們可以隨意的新增或者忽略某個(gè)字段,但是,每個(gè)字段的類型非常重要,比如一個(gè)年齡字段類型,可以是字符 串也可以是整形。因?yàn)閑lasticsearch會(huì)保存字段和類型之間的映射及其他的設(shè)置。這種映射具體到每個(gè)映射的每種類型,這也是為什么在elasticsearch中,類型有時(shí)候也稱為映射類型。
類型

類型是文檔的邏輯容器,就像關(guān)系型數(shù)據(jù)庫(kù)一樣,表格是行的容器。 類型中對(duì)于字段的定義稱為映射,比如 name 映 射為字符串類型。 我們說(shuō)文檔是無(wú)模式的,它們不需要擁有映射中所定義的所有字段,比如新增一個(gè)字段,那么elasticsearch是怎么做的呢?elasticsearch會(huì)自動(dòng)的將新字段加入映射,但是這個(gè)字段的不確定它是什么類型,elasticsearch就開(kāi)始猜,如果這個(gè)值是18,那么elasticsearch會(huì)認(rèn)為它是整形。 但是elasticsearch也可能猜不對(duì), 所以最安全的方式就是提前定義好所需要的映射,這點(diǎn)跟關(guān)系型數(shù)據(jù)庫(kù)殊途同歸了,先定義好字段,然后再使用,別 整什么幺蛾子。
索引
就是數(shù)據(jù)庫(kù)!
索引是映射類型的容器,elasticsearch中的索引是一個(gè)非常大的文檔集合。索引存儲(chǔ)了映射類型的字段和其他設(shè)置。 然后它們被存儲(chǔ)到了各個(gè)分片上了。 我們來(lái)研究下分片是如何工作的。
物理設(shè)計(jì) :節(jié)點(diǎn)和分片 如何工作

一個(gè)集群至少有一個(gè)節(jié)點(diǎn),而一個(gè)節(jié)點(diǎn)就是一個(gè)elasricsearch進(jìn)程,節(jié)點(diǎn)可以有多個(gè)索引默認(rèn)的,如果你創(chuàng)建索引,那么索引將會(huì)有個(gè)5個(gè)分片 ( primary shard ,又稱主分片 ) 構(gòu)成的,每一個(gè)主分片會(huì)有一個(gè)副本 ( replica shard ,又稱復(fù)制分片 )

上圖是一個(gè)有3個(gè)節(jié)點(diǎn)的集群,可以看到主分片和對(duì)應(yīng)的復(fù)制分片都不會(huì)在同一個(gè)節(jié)點(diǎn)內(nèi),這樣有利于某個(gè)節(jié)點(diǎn)掛掉 了,數(shù)據(jù)也不至于丟失。 實(shí)際上,一個(gè)分片是一個(gè)Lucene索引,一個(gè)包含倒排索引的文件目錄,倒排索引的結(jié)構(gòu)使 得elasticsearch在不掃描全部文檔的情況下,就能告訴你哪些文檔包含特定的關(guān)鍵字。 不過(guò),等等,倒排索引是什 么鬼?
倒排索引
elasticsearch使用的是一種稱為倒排索引的結(jié)構(gòu),采用Lucene倒排索作為底層。這種結(jié)構(gòu)適用于快速的全文搜索, 一個(gè)索引由文檔中所有不重復(fù)的列表構(gòu)成,對(duì)于每一個(gè)詞,都有一個(gè)包含它的文檔列表。 例如,現(xiàn)在有兩個(gè)文檔, 每個(gè)文檔包含如下內(nèi)容:
Study every day, good good up to forever # 文檔1包含的內(nèi)容
To forever, study every day, good good up # 文檔2包含的內(nèi)容
為了創(chuàng)建倒排索引,我們首先要將每個(gè)文檔拆分成獨(dú)立的詞(或稱為詞條或者tokens),然后創(chuàng)建一個(gè)包含所有不重 復(fù)的詞條的排序列表,然后列出每個(gè)詞條出現(xiàn)在哪個(gè)文檔 :
| term | doc_1 | doc_2 |
|---|---|---|
| Study | √ | x |
| To | x | x |
| every | √ | √ |
| forever | √ | √ |
| day | √ | √ |
| study | x | √ |
| good | √ | √ |
| every | √ | √ |
| to | √ | x |
| up | √ | √ |
現(xiàn)在,我們?cè)噲D搜索 to forever,只需要查看包含每個(gè)詞條的文檔 score
| term | doc_1 | doc_2 |
|---|---|---|
| to | √ | × |
| forever | √ | √ |
| total | 2 | 1 |
兩個(gè)文檔都匹配,但是第一個(gè)文檔比第二個(gè)匹配程度更高。如果沒(méi)有別的條件,現(xiàn)在,這兩個(gè)包含關(guān)鍵字的文檔都將返回。
再來(lái)看一個(gè)示例,比如我們通過(guò)博客標(biāo)簽來(lái)搜索博客文章。那么倒排索引列表就是這樣的一個(gè)結(jié)構(gòu) :

如果要搜索含有 python 標(biāo)簽的文章,那相對(duì)于查找所有原始數(shù)據(jù)而言,查找倒排索引后的數(shù)據(jù)將會(huì)快的多。只需要 查看標(biāo)簽這一欄,然后獲取相關(guān)的文章ID即可。完全過(guò)濾掉無(wú)關(guān)的所有數(shù)據(jù),提高效率!
elasticsearch的索引和Lucene的索引對(duì)比
在elasticsearch中, 索引 (庫(kù))這個(gè)詞被頻繁使用,這就是術(shù)語(yǔ)的使用。 在elasticsearch中,索引被分為多個(gè)分片,每份 分片是一個(gè)Lucene的索引。所以一個(gè)elasticsearch索引是由多個(gè)Lucene索引組成的。別問(wèn)為什么,誰(shuí)讓elasticsearch使用Lucene作為底層呢! 如無(wú)特指,說(shuō)起索引都是指elasticsearch的索引。
5. IK分詞器插件
什么是IK分詞器?
分詞:即把一段中文或者別的劃分成一個(gè)個(gè)的關(guān)鍵字,我們?cè)谒阉鲿r(shí)候會(huì)把自己的信息進(jìn)行分詞,會(huì)把數(shù)據(jù)庫(kù)中或者索引庫(kù)中的數(shù)據(jù)進(jìn)行分詞,然后進(jìn)行一個(gè)匹配操作,默認(rèn)的中文分詞是將每個(gè)字看成一個(gè)詞,比如 “我愛(ài)狂神” 會(huì)被分為"我","愛(ài)","狂","神",這顯然是不符合要求的,所以我們需要安裝中文分詞器ik來(lái)解決這個(gè)問(wèn)題。
如果要使用中文,建議使用ik分詞器!
IK提供了兩個(gè)分詞算法:ik_smart 和 ik_max_word,其中 ik_smart 為最少切分,ik_max_word為最細(xì)粒度劃分!
安裝
-
下載完畢之后,放入到我們的elasticsearch 插件即可!
-
重啟觀察ES,可以看到ik分詞器被加載了!
-
elasticsearch-plugin 可以通過(guò)這個(gè)命令來(lái)查看加載進(jìn)來(lái)的插件
使用kibana測(cè)試!
查看不同的分詞效果
其中 ik_smart 為最少切分

ik_max_word為最細(xì)粒度劃分!窮盡詞庫(kù)的可能!字典!

我們輸入 超級(jí)喜歡狂神說(shuō)Java

發(fā)現(xiàn)問(wèn)題:狂神說(shuō)被拆開(kāi)了!
這種自己需要的詞,需要自己加到我們的分詞器的字典中!
ik 分詞器增加自己的配置!

重啟es,看細(xì)節(jié)!

再次測(cè)試一下狂神說(shuō),看下效果!

6. Rest風(fēng)格說(shuō)明
一種軟件架構(gòu)風(fēng)格,而不是標(biāo)準(zhǔn),只是提供了一組設(shè)計(jì)原則和約束條件。它主要用于客戶端和服務(wù)器交互類的軟件?;谶@個(gè)風(fēng)格設(shè)計(jì)的軟件可以更簡(jiǎn)潔,更有層次,更易于實(shí)現(xiàn)緩存等機(jī)制。
基本Rest命令說(shuō)明:
| method | url地址 | 描述 |
|---|---|---|
| PUT | localhost:9200/索引名稱/類型名稱/文檔id | 創(chuàng)建文檔(指定文檔id) |
| POST | localhost:9200/索引名稱/類型名稱 | 創(chuàng)建文檔(隨機(jī)文檔id) |
| POST | localhost:9200/索引名稱/類型名稱/文檔id/_update | 修改文檔 |
| DELETE | localhost:9200/索引名稱/類型名稱/文檔id | 刪除文檔 |
| GET | localhost:9200/索引名稱/類型名稱/文檔id | 查詢文檔通過(guò)文檔id |
| POST | localhost:9200/索引名稱/類型名稱/_search | 查詢所有數(shù)據(jù) |
7. 關(guān)于索引的基本操作
7.1 創(chuàng)建一個(gè)索引!
PUT /索引名/~類型名~/文檔id
{請(qǐng)求體}

完成了自動(dòng)增加了索引!數(shù)據(jù)也成功的添加了,這就是我說(shuō)大家在初期可以把它當(dāng)做數(shù)據(jù)庫(kù)學(xué)習(xí)的原因!

那么 name 這個(gè)字段用不用指定類型呢。畢竟我們關(guān)系型數(shù)據(jù)庫(kù) 是需要指定類型的啊 !
- 字符串類型
text 、 keyword - 數(shù)值類型
long, integer, short, byte, double, float, half_float, scaled_float - 日期類型
date - 布爾值類型
boolean - 二進(jìn)制類型
binary - 等等.....
7.2 指定字段的類型

獲得這個(gè)規(guī)則! 可以通過(guò) GET 請(qǐng)求獲取具體的信息!

7.3 查看默認(rèn)的信息


如果自己的文檔字段沒(méi)有指定,那么es 就會(huì)給我們默認(rèn)配置字段類型!
擴(kuò)展: 通過(guò)命令 elasticsearch 索引情況! 通過(guò)get _cat/ 可以獲得es的當(dāng)前的很多信息!

修改 提交還是使用PUT 即可! 然后覆蓋!最新辦法!
曾經(jīng)!

現(xiàn)在的方法!

刪除索引!
通過(guò)DELETE 命令實(shí)現(xiàn)刪除、 根據(jù)你的請(qǐng)求來(lái)判斷是刪除索引還是刪除文檔記錄!
使用RESTFUL 風(fēng)格是我們ES推薦大家使用的!
8. 關(guān)于文檔的基本操作(重點(diǎn))
基本操作
8.1 添加數(shù)據(jù)
PUT /kuangshen/user/1
{
"name": "狂神說(shuō)",
"age": 23,
"desc": "一頓操作猛如虎,一看工資2500",
"tags": ["技術(shù)宅","溫暖","直男"]
}

8.2 獲取數(shù)據(jù) GET

8.3 更新數(shù)據(jù) PUT

8.4 Post _update , 推薦使用這種更新方式!

8.5 簡(jiǎn)單地搜索!
GET kuangshen/user/1
簡(jiǎn)答的條件查詢,可以根據(jù)默認(rèn)的映射規(guī)則,產(chǎn)生基本的查詢!


8.6 復(fù)雜操作搜索 select ( 排序,分頁(yè),高亮,模糊查詢,精準(zhǔn)查詢!)


輸出結(jié)果,不想要那么多!

我們之后使用Java操作es ,所有的方法和對(duì)象就是這里面的 key!
排序!

分頁(yè)查詢!

數(shù)據(jù)下標(biāo)還是從0開(kāi)始的,和學(xué)的所有數(shù)據(jù)結(jié)構(gòu)是一樣的!
/search/{current}/{pagesize}
布爾值查詢
must (and),所有的條件都要符合 where id = 1 and name = xxx

should(or),所有的條件都要符合 where id = 1 or name = xxx

must_not (not)

過(guò)濾器 filter

- gt 大于
- gte 大于等于
- lt 小于
- lte 小于等于!

匹配多個(gè)條件!

精確查詢!
term 查詢是直接通過(guò)倒排索引指定的詞條進(jìn)程精確查找的!
關(guān)于分詞:
- term ,直接查詢精確的
- match,會(huì)使用分詞器解析?。ㄏ确治鑫臋n,然后在通過(guò)分析的文檔進(jìn)行查詢!)
兩個(gè)類型 text keyword



多個(gè)值匹配精確查詢

高亮查詢!


9. 集成SpringBoot
找官方文檔!



-
找到原生的依賴
<dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.6.2</version> </dependency> -
找對(duì)象
- 分析這個(gè)類中的方法即可!
配置基本的項(xiàng)目
問(wèn)題:一定要保證 我們的導(dǎo)入的依賴和我們的es 版本一致


源碼中提供對(duì)象!

雖然這里導(dǎo)入3個(gè)類,靜態(tài)內(nèi)部類,核心類就一個(gè)!
/**
* Elasticsearch rest client infrastructure configurations.
*
* @author Brian Clozel
* @author Stephane Nicoll
*/
class RestClientConfigurations {
@Configuration(proxyBeanMethods = false)
static class RestClientBuilderConfiguration {
// RestClientBuilder
@Bean
@ConditionalOnMissingBean
RestClientBuilder elasticsearchRestClientBuilder(RestClientProperties
properties,
ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {
HttpHost[] hosts =
properties.getUris().stream().map(HttpHost::create).toArray(HttpHost[]::new);
RestClientBuilder builder = RestClient.builder(hosts);
PropertyMapper map = PropertyMapper.get();
map.from(properties::getUsername).whenHasText().to((username) -> {
CredentialsProvider credentialsProvider = new
BasicCredentialsProvider();
Credentials credentials = new
UsernamePasswordCredentials(properties.getUsername(),
properties.getPassword());
credentialsProvider.setCredentials(AuthScope.ANY, credentials);
builder.setHttpClientConfigCallback(
(httpClientBuilder) ->
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
});
builder.setRequestConfigCallback((requestConfigBuilder) -> {
map.from(properties::getConnectionTimeout).whenNonNull().asInt(Duration::toMill
is)
.to(requestConfigBuilder::setConnectTimeout);
map.from(properties::getReadTimeout).whenNonNull().asInt(Duration::toMillis)
.to(requestConfigBuilder::setSocketTimeout);
return requestConfigBuilder;
});
builderCustomizers.orderedStream().forEach((customizer) ->
customizer.customize(builder));
return builder;
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestHighLevelClient.class)
static class RestHighLevelClientConfiguration {
// RestHighLevelClient 高級(jí)客戶端,也是我們這里要講,后面項(xiàng)目會(huì)用到的客戶端
@Bean
@ConditionalOnMissingBean
RestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder
restClientBuilder) {
return new RestHighLevelClient(restClientBuilder);
}
@Bean
@ConditionalOnMissingBean
RestClient elasticsearchRestClient(RestClientBuilder builder,
ObjectProvider<RestHighLevelClient> restHighLevelClient) {
RestHighLevelClient client = restHighLevelClient.getIfUnique();
if (client != null) {
return client.getLowLevelClient();
}
return builder.build();
}
}
@Configuration(proxyBeanMethods = false)
static class RestClientFallbackConfiguration {
// RestClient 普通的客戶端!
@Bean
@ConditionalOnMissingBean
RestClient elasticsearchRestClient(RestClientBuilder builder) {
return builder.build();
}
}
}
具體的Api測(cè)試!
- 創(chuàng)建索引
- 判斷索引是否存在
- 刪除索引
- 創(chuàng)建文檔
- crud文檔!
@SpringBootTest
class KuangshenEsApiApplicationTests {
// 面向?qū)ο髞?lái)操作
@Autowired
@Qualifier("restHighLevelClient")
private RestHighLevelClient client;
// 測(cè)試索引的創(chuàng)建 Request PUT kuang_index
@Test
void testCreateIndex() throws IOException {
// 1、創(chuàng)建索引請(qǐng)求
CreateIndexRequest request = new CreateIndexRequest("kuang_index");
// 2、客戶端執(zhí)行請(qǐng)求 IndicesClient,請(qǐng)求后獲得響應(yīng)
CreateIndexResponse createIndexResponse =
client.indices().create(request, RequestOptions.DEFAULT);
System.out.println(createIndexResponse);
}
// 測(cè)試獲取索引,判斷其是否存在
@Test
void testExistIndex() throws IOException {
GetIndexRequest request = new GetIndexRequest("kuang_index2");
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
// 測(cè)試刪除索引
@Test
void testDeleteIndex() throws IOException {
DeleteIndexRequest request = new DeleteIndexRequest("kuang_index");
// 刪除
AcknowledgedResponse delete = client.indices().delete(request,
RequestOptions.DEFAULT);
System.out.println(delete.isAcknowledged());
}
// 測(cè)試添加文檔
@Test
void testAddDocument() throws IOException {
// 創(chuàng)建對(duì)象
User user = new User("狂神說(shuō)", 3);
// 創(chuàng)建請(qǐng)求
IndexRequest request = new IndexRequest("kuang_index");
// 規(guī)則 put /kuang_index/_doc/1
request.id("1");
request.timeout(TimeValue.timeValueSeconds(1));
request.timeout("1s");
// 將我們的數(shù)據(jù)放入請(qǐng)求 json
request.source(JSON.toJSONString(user), XContentType.JSON);
// 客戶端發(fā)送請(qǐng)求 , 獲取響應(yīng)的結(jié)果
IndexResponse indexResponse = client.index(request,
RequestOptions.DEFAULT);
System.out.println(indexResponse.toString()); //
System.out.println(indexResponse.status()); // 對(duì)應(yīng)我們命令返回的狀態(tài)
CREATED
}
// 獲取文檔,判斷是否存在 get /index/doc/1
@Test
void testIsExists() throws IOException {
GetRequest getRequest = new GetRequest("kuang_index", "1");
// 不獲取返回的 _source 的上下文了
getRequest.fetchSourceContext(new FetchSourceContext(false));
getRequest.storedFields("_none_");
boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
System.out.println(exists);
}
// 獲得文檔的信息
@Test
void testGetDocument() throws IOException {
GetRequest getRequest = new GetRequest("kuang_index", "1");
GetResponse getResponse = client.get(getRequest,
RequestOptions.DEFAULT);
System.out.println(getResponse.getSourceAsString()); // 打印文檔的內(nèi)容
System.out.println(getResponse); // 返回的全部?jī)?nèi)容和命令式一樣的
}
// 更新文檔的信息
@Test
void testUpdateRequest() throws IOException {
UpdateRequest updateRequest = new UpdateRequest("kuang_index","1");
updateRequest.timeout("1s");
User user = new User("狂神說(shuō)Java", 18);
updateRequest.doc(JSON.toJSONString(user),XContentType.JSON);
UpdateResponse updateResponse = client.update(updateRequest,
RequestOptions.DEFAULT);
System.out.println(updateResponse.status());
}
// 刪除文檔記錄
@Test
void testDeleteRequest() throws IOException {
DeleteRequest request = new DeleteRequest("kuang_index","1");
request.timeout("1s");
DeleteResponse deleteResponse = client.delete(request,
RequestOptions.DEFAULT);
System.out.println(deleteResponse.status());
}
// 特殊的,真的項(xiàng)目一般都會(huì)批量插入數(shù)據(jù)!
@Test
void testBulkRequest() throws IOException {
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
ArrayList<User> userList = new ArrayList<>();
userList.add(new User("kuangshen1",3));
userList.add(new User("kuangshen2",3));
userList.add(new User("kuangshen3",3));
userList.add(new User("qinjiang1",3));
userList.add(new User("qinjiang1",3));
userList.add(new User("qinjiang1",3));
// 批處理請(qǐng)求
for (int i = 0; i < userList.size() ; i++) {
// 批量更新和批量刪除,就在這里修改對(duì)應(yīng)的請(qǐng)求就可以了
bulkRequest.add(
new IndexRequest("kuang_index")
.id(""+(i+1))
.source(JSON.toJSONString(userList.get(i)),XContentType.JSON));
}
BulkResponse bulkResponse = client.bulk(bulkRequest,
RequestOptions.DEFAULT);
System.out.println(bulkResponse.hasFailures()); // 是否失敗,返回 false 代表
成功!
}
// 查詢
// SearchRequest 搜索請(qǐng)求
// SearchSourceBuilder 條件構(gòu)造
// HighlightBuilder 構(gòu)建高亮
// TermQueryBuilder 精確查詢
// MatchAllQueryBuilder
// xxx QueryBuilder 對(duì)應(yīng)我們剛才看到的命令!
@Test
void testSearch() throws IOException {
SearchRequest searchRequest = new SearchRequest("kuang_index");
// 構(gòu)建搜索條件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.highlighter()
// 查詢條件,我們可以使用 QueryBuilders 工具來(lái)實(shí)現(xiàn)
// QueryBuilders.termQuery 精確
// QueryBuilders.matchAllQuery() 匹配所有
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name",
"qinjiang1");
// MatchAllQueryBuilder matchAllQueryBuilder =
QueryBuilders.matchAllQuery();
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(new TimeValue(60,TimeUnit.SECONDS));
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = client.search(searchRequest,
RequestOptions.DEFAULT);
System.out.println(JSON.toJSONString(searchResponse.getHits()));
System.out.println("=================================");
for (SearchHit documentFields : searchResponse.getHits().getHits()) {
System.out.println(documentFields.getSourceAsMap());
}
}
}








