ElasticSearch7.6

2020-08-12 13:56:07

ElasticSearch概述

ElasticSearch,簡稱es,es是一個開源的高拓展分佈式全文檢索引擎,它可以近乎實時的儲存檢索數據;本身拓展性很好,它可以拓展到上百台伺服器,處理PB級別的數據。es也使用java開發並使用Lucene的複雜性,從而讓全文檢索變得簡單
據國際權威的數據庫產品評測機構DB Engines的統計,2016年1月,ElasticSearch已超過solr等成爲排名第一的搜尋引擎類應用

ElasticSearch和solr的差別

ElasticSearch簡介

ElasticSearch是一個實時分佈式搜尋和分析引擎,它讓你以前所未有的速度處理大數據的可能
它用於全文搜尋,結構化搜尋,分析以及這三者混合使用
ElasticSearch是一個基於Apache Lucene™的開源搜尋引擎。無論是在開源還是專有鄰域,Lucene可以被認爲是迄今爲止最先進、效能最好的,功能最全的搜尋引擎庫。
但是。Lucene只是一個庫。想要使用它,你必須使用java作爲開發語言並將其直接整合到你的應用中,更糟糕的是,Lucene非常複雜,你需要更深入的瞭解檢索的相關知識來理解它是如何工作的。
ElasticSearch也使用java開發並使用Lucene作爲其核心來實現所有索引和功能,但是它的目的是通過簡單的RESTful API來隱藏Lucene的複雜性,從而讓全文檢索變得簡單

Solr簡介

Solr是Apache下的頂級開源專案,採用java開發,它是基於Lucene的全文檢索伺服器。solr提供優化比Lucene跟爲豐富的查詢語言,同時實現了可設定、可拓展,並對索引、搜尋效能進行了優化
solr可以獨立執行,執行在jetty、tomcat等這些servlet容器中,Sole索引的實現方法很簡單,用post方法向solr伺服器發送一條可描述Filed及其內容的XML文件,Solr根據xml文件的新增、刪除、更新索引、Solr搜尋只需要發送HTTP GET請求,然後對solr返回xml、json等格式的查詢結果進行解析,組織頁面佈局、solr不提供構建UI的功能,solr提供了一個管理介面,通過管理介面可以對查詢的solr的設定和執行情況
Solr是一個開源搜尋平臺,用於構建搜尋應用程式。
是一個獨立的企業級搜尋應用伺服器,它對外提供類似於Web-service的API介面
它建立在Lucene(全文搜尋引擎)之上。 Solr是企業級的,快速的和高度可延伸的。

Lucene簡介

Lucene 是一個基於 Java 的全文資訊檢索工具包,它不是一個完整的搜尋應用程式,而是爲你的應用程式提供索引和搜尋功能的一個開源框架。Lucene 目前是 Apache Jakarta 家族中的一個開源專案。也是目前最爲流行的基於 Java 開源全文檢索工具包。

目前已經有很多應用程式的搜尋功能是基於 Lucene 的,比如 Eclipse 的幫助系統的搜尋功能。Lucene 能夠爲文字型別的數據建立索引,所以你只要能把你要索引的數據格式轉化的文字的,Lucene 就能對你的文件進行索引和搜尋。比如你要對一些 HTML 文件,PDF 文件進行索引的話你就首先需要把 HTML 文件和 PDF 文件轉化成文字格式的,然後將轉化後的內容交給 Lucene 進行索引,然後把建立好的索引檔案儲存到磁碟或者記憶體中,最後根據使用者輸入的查詢條件在索引檔案上進行查詢。不指定要索引的文件的格式也使 Lucene 能夠幾乎適用於所有的搜尋應用程式。

ElasticSearch與solr比較

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
ElasticSearch vs solr 總結

  1. es基本就是開箱使用,非常簡單,Solr安裝比較複雜一點
  2. Solr支援更多格式的數據,比如json,xml,csv,而ElasticSearch僅支援json檔案格式
  3. Solr利用Zookeeper進行分佈式管理,而ElasticSearch自身帶有分佈式協調管理功能。
  4. Solr官方提供的功能更多,而ElasticSearch本身更注重與核心功能,高階功能多有第三方外掛提供,例如圖形化頁面需要kibana友好支撐
  5. Solr查詢快,但更新索引滿,用於電商等查詢多的應用
  6. ElasticSearch建立索引快(查詢慢),實時性查詢快,用於facebook新浪等搜尋
  7. Solr是傳統搜尋應用的有力解決方案,但ElasticSearch更適用新興的實時搜尋應用
  8. Solr比較成熟,有一個更大,更成熟的使用者、開發和貢獻者社羣,而ElasticSearch相對開發維護者較少,更新太快,學習使用成本較高

ElasticSearch安裝

宣告:JDK1.8,最低要求,ElasticSearch用戶端,介面工具
java開發,ElasticSearch的版本和我們之後對應的java的核心jar包!版本對應,JDK環境是正常

下載 https://www.elastic.co/cn/
在这里插入图片描述
在这里插入图片描述
華爲雲的映象去下載
ElasticSearch: https://mirrors.huaweicloud.com/elasticsearch/?C=N&O=D
logstash: https://mirrors.huaweicloud.com/logstash/?C=N&O=D
kibana: https://mirrors.huaweicloud.com/kibana/?C=N&O=D

鏈接: https://pan.baidu.com/s/1xhpIqT8Tm-jN_h2ir9xlwA 提取碼: jv4h

  1. 下載後解壓
    在这里插入图片描述
  2. 目錄介紹
bin  啓動檔案
config  組態檔
		log4j2 日誌組態檔
		jvm.options  java虛擬機器相關設定
		elasticsearch.yml  elasticsearch的組態檔  預設9200埠! 跨域!
lib      相關jar包
modules  功能目錄
plugins  外掛
  1. 雙擊bin/elasticsearch.bat檔案
    在这里插入图片描述
  2. 存取http://127.0.0.1:9200
    在这里插入图片描述
    在这里插入图片描述
  3. 安裝視覺化介面 ElasticSearch head
    下載:https://github.com/mobz/elasticsearch-head
    在这里插入图片描述
    在这里插入图片描述
  4. 報錯:跨域問題
    解決:
    開啓elasticsearch.yml檔案進行設定
    在这里插入图片描述
http.cors.enabled: true
http.cors.allow-origin: "*"
  1. 重新啓動elasticSearch和elasticsearch-head
    在这里插入图片描述
    索引:相當於一個數據庫
    在这里插入图片描述
    新建一個索引
    在这里插入图片描述

安裝kibana

瞭解ELK

ELK是elasticSearch、Logstash、kibana三大開源框架首字母大寫的簡稱。市面上也被稱爲Elastic Stack。其中elasticSearch是一個基於Lucene、分佈式、通過RESTful方式進行互動的近實時搜尋平臺框架。像類似於百度、谷歌這種大數據全文搜尋引擎的場景都可以使用elasticSearch作爲底層支援框架、可見elasticSearch提供的搜尋能力確實強大,elasticSearch也被市面上簡稱爲es。
Logstash是ELK的中央數據引流引擎,用於從不同目標(檔案/數據儲存/MQ)收集的不同格式數據,經過過濾後支援輸出帶不同的目的地(檔案/MQ/redis/elasticSearch/kafka)等。kibana可以將elasticSearch的數據通過友好的頁面展示出來,提供實時分析的功能
在这里插入图片描述

下載地址:https://www.elastic.co/cn/downloads/kibana
注意:es版本和kibana版本儘量保持一致
在这里插入图片描述

下載完解壓
在这里插入图片描述
啓動測試:bin/kibana.bat
在这里插入图片描述
埠:5601
存取:http://localhost:5601
在这里插入图片描述
英文看不懂咋辦?使用漢化外掛

開啓/config/kibana.yml檔案 設定i18n.locale: 「zh-CN」
在这里插入图片描述

重新啓動kibana
在这里插入图片描述

ES核心概念

1、索引
2、欄位型別(mapping)
3、文件(documents)

概述
elasticsearch是面向文件,關係型數據庫和elasticsearch客觀的對比
叢集,節點所以,型別,文件,分片,對映是什麼?

Relational DB elasticsearch
數據庫(database) 索引(indices)
表(tables) type
行(rows) documents
欄位(colums) fieds

elasticsearch(叢集)中可以包含多個索引(數據庫),每個索引可以包含多個型別(表),每個型別可以包含多個文件(行),每個文件中有保安多個欄位(列)。

物理設計:
elasticsearch在後台吧每個索引劃分成多個分片,每分分片可以在叢集中的不同伺服器間遷移

邏輯設計:
一個索引型別中,包含多個文件,比如說文件1,文件2。當我們索引一篇文件時,可以通過這樣的一個順序找到它:索引>型別>文件id>,通過這個組合我們就能索引帶某個具體的文件。注意:ID不必是整數,實際上是一個字串

文件

之前說 elasticsearch是面向文件的,那麼就意味着索引和搜尋數據的最小單位是文件, elasticsearch中,文件有幾個重要屬性:

  • 自我包含,一文件同時包含欄位和對應的值,也就是同時包含 key: value!name: guangshen
  • 可以是層次型的,一個文件中包含自文件,複雜的邏輯實體就是這麼來的
  • 靈活的結構,文件不依賴預先定義的模式,我們知道關係型數據庫中,要提前定義欄位才能 纔能使用,在 elasticsearch中,對於字
    段是非常靈活的,有時候,我們可以忽略該欄位,或者動態的新增一個新的欄位。

型別

型別是文件的邏輯容器,就像關係型數據庫一樣,表格是行的容器。型別中對於欄位的定義稱爲對映,比如name對映爲字串型別。我們說文件是無模式的,它們不需要擁有對映中所定義的所有欄位,比如新增一個欄位,那麼 elasticsearch是怎麼做的呢?
elasticsearch會自動的將新欄位加入對映,但是這個欄位的不確定它是什麼型別, elasticsearch就開始猜,如果這個值是18,那elasticsearch會認爲它是整形。但是 elasticsearch也可能猜不對,所以最安全的方式就是提前定義好所需要的對映,這點跟關係
型數據庫殊途同歸了,先定義好欄位,然後再使用,別整什麼蛾子。

索引

就是數據庫!
索引是對映型別的容器, elasticsearch中的索引是一個非常大的文件集合。索引儲存了對映型別的欄位和其他設定。然後它們被儲存到了各個分片上了。我們來研究下分片是如何工作的
在这里插入图片描述

物理設計:節點和分片如何工作
一個叢集至少有一個節點,而一個節點就是一個 elasricsearch進程,節點可以有多個索引預設的,如果你建立索引,那麼索引將會
有個5個分片( primary shard,又稱主分片)構成的,毎一個主分片會有一個副本( replica shard,又稱複製分片)
在这里插入图片描述
上圖是一個有3個節點的叢集,可以看到主分片和對應的複製分片都不會在同一個節點內,這樣有利於某個節點掛掉了,數據也不於丟失。
實際上,一個分片是一個 Lucene索引,一個包含倒排索引的檔案目錄,倒排素引的結構使得 elasticsearchi在不掃描全部文件的情況下,就能告訴你哪些文件包含特定的關鍵字。不過,等等,倒排索引是什麼鬼?

倒排索引

elasticsearch使用的是一種稱爲倒排索引的結構,採用 lucene倒排索作爲底層。這種結構適用於快速的全文搜尋,一個索引由文件中所有不重複的列表構成,對於每一個詞,都有一個包含它的文件列表。例如,現在有兩個文件,每個文件包含如下內容

Study every day , good good up to forever # 文件1包含的內容
To forever  , Study every day, good good up  # 文件2包含的內容

爲了建立倒排索引,我們首先要將每個文件拆分成獨立的詞或稱爲詞條或者 tokens),然後建立一個包含所有不重複的詞條的排序列表,然後列出每個詞條出現在哪個文件

term doc_1 doc_2
Study
To
ever
forever
day
study
good
every
to
up

來看一個範例,比如我們通過部落格標籤來搜尋部落格文章。那麼倒排索引列表就是這樣的一個結構
在这里插入图片描述
如果要搜尋含有 python標籤的文章,那相對於査找所有原始數據而言,查詢倒排索引後的數據將會快的多。只需要檢視標籤這欄,然後獲取相關的文章ID即可。完全過濾掉無關的所有數據,提高效率!

elasticsearche的索引和 Lucene的索引對比

在 elasticsearcht中,索引這個詞被頻繁使用,這就是術語的使用。在 elasticsearch中,索引被分爲多個分片,每份分片是一個
Lucene的索引。所以一個 elasticsearch素引是由多個 Lucene索引組成的。別問爲什麼,誰讓 elasticsearch使用 Lucene作爲底層呢!
如無特指,說起索引都是指 elasticsearchi的索引
接下來的一切操作都在 kibana中 Dev Tools下的 Consale裡完成。
基礎操作

IK分詞器外掛

什麼是IK分詞器

分詞:即把一段中文或者別的劃分成一個個的關鍵字,我們在搜尋時候會把自己的資訊進行分詞,會把數據庫中或者索引庫中的數據進行分詞,然後進行一個匹配操作,預設的中文分詞是將每個字看成一個詞,比如「我愛jd」會被分爲我",「愛」,「j」,"d」,這顯
然是不符合要求的,所以我們需要安裝中文分詞器K來解決這個問題。

如果要使用中文,建議使用ik分詞器
IK提供了兩個分詞演算法: ik smart和 ik max word,其中 ik smart爲最少切分, ik max word爲最細粒度劃分!一會我們測試!

安裝

下載地址:https://github.com/medcl/elasticsearch-analysis-ik
下載完畢之後,放入到我們的 elasticsearch外掛即可!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通過命令檢視外掛是否載入:elasticsearch-plugin list

使用kibana測試
檢視不同分詞器的效果
其中 ik smart爲最少切分
在这里插入图片描述

ik_max_word爲細粒度拆分
在这里插入图片描述
自定義詞典

  1. 在IK分詞器config目錄下新建一個*.dic檔案
    在这里插入图片描述
    編寫自己的詞彙
    在这里插入图片描述
    設定到IKAnalyzer.cfg.xml中
    在这里插入图片描述
    重新啓動es、kibana
    在这里插入图片描述

Rest風格說明

一種軟體架構風格,而不是標準,只是提供了一組設計原則和約束條件。它主要用於用戶端和伺服器互動類的軟體。基於這個風格設計的軟體可以更筒潔,更有層次,更易於實現快取等機制 機製。

基本Rest命令說明

method url地址 描述
PUT localhost:9200/索引名稱/型別名稱/文件id 建立文件(指定文件d)
POST localhost:9200/索引名稱/型別名稱 建立文件(隨機文件id)
POST locahost:9200/索引名稱/型別名稱/文件id/_ update 修改文件
DELETE localhost::9200/索引名稱/型別名稱/文件id 刪除文件
GET localhost:9200/索引名稱/型別名稱文件id 查詢文件通過文件d
POST localhost::9200/索引名稱/型別名稱/_search 查詢所有數據

索引的基本操作

執行es,kibana、es-head

建立一個索引

PUT /索引名/~型別名~/文件id
{
	請求體
}

在这里插入图片描述
完成了自動増加了索引!數據也成功的新增了
在这里插入图片描述
那麼name這個欄位用不用指定型別呢。畢亮我們關係型數據庫是需要指定型別的啊
預設型別:

  • 字串型別:text、keyword
  • 數值型別:ling,integer,short,byte,double,float,half float,scaled float
  • 日期型別:date
  • te布爾值型別:boolean
  • 二進制型別:binary
  • 等等

指定欄位的型別
在这里插入图片描述

PUT /test2
{
  "mappings": {
    "properties": {
     "name":{
       "type": "text"
     },
     "age":{
       "type": "long"
     },
     "birthday":{
       "type": "date"
     }
    }
  }
}

獲取索引資訊

GET /索引名/~型別名~/文件id

在这里插入图片描述
如果自己的文件欄位沒有指定,那麼es就會給我們預設設定欄位型別

展:通過命令 elasticsearch索引情況!通過get_cat/可以獲得es的當前的很多資訊!
在这里插入图片描述
在这里插入图片描述

修改索引狀態

POST /索引名稱/型別名稱/文件名稱/_update

PUT /test3/_doc/1
{
  "name":"joker",
  "age":18,
  "sex":"男"
}

POST /test3/_doc/1/_update
{
  "doc":{
    "name":"joker_dj"
  }
}

在这里插入图片描述
在这里插入图片描述

刪除索引

通過 DELETE命令實現州除、根據你的請求來判斷是刪除索引還是刪除文件記錄!

DELETE /索引名稱/型別名稱/文件名稱

在这里插入图片描述
刪除指定文件
在这里插入图片描述

DELETE 索引名稱/型別名稱/文件id
{
	方法體
}
例:
DELETE test3/_doc/1
{
  "name":"joker_dj"
}

文件的基本操作

基本操作

建立索引

PUT /joker/user/1
{
  "name":"joker_dj",
  "age":18,
  "desc":"java小萌新",
  "tags":["技術宅","直男"]
}
PUT /joker/user/1
{
  "name":"joker_dj",
  "age":18,
  "desc":"java小萌新",
  "tags":["技術宅","直男"]
}
PUT /joker/user/3
{
  "name":"李四",
  "age":5,
  "desc":"合夥人",
  "tags":["壞人"]
}

獲取文件

GET /索引名稱/型別名稱/文件id
在这里插入图片描述

修改文件

重新put一邊就是修改 (不推薦)
version就是數據被改動的次數
在这里插入图片描述
POST _update,推薦使用這種更新方式
在这里插入图片描述

POST /索引名稱/型別名稱/文件id/_update
{
  "doc":{
    "fieds":"value"
  }
}

POST /joker/user/3/_update
{
  "doc":{
    "name":"張三的哥哥李四"
  }
}

文件搜尋

簡單的搜尋

GET /索引名稱/[型別名稱]/[文件id]

在这里插入图片描述
高階搜尋 條件查詢

GET /索引名稱/[型別名稱]/_search?q=fieds:value

在这里插入图片描述

複雜操作搜尋 select(排序,分頁,高亮,模糊査詢,精準查詢!)

在这里插入图片描述
根據_score分數進行排序 檢視誰最匹配

在这里插入图片描述

只要文件中包含value的就會被查出來 前提是被分詞器捕獲
GET /索引名稱/型別名稱/_search
{
  "query": {
    "match": {
      "fileds": "value"
    } 
  }
}

GET /joker/user/_search
{
  "query": {
    "match": {
      "name": "張三"
    } 
  }
}

在这里插入图片描述

過濾欄位

GET  /索引名稱/型別名稱/_search
{
  "query": {
    "match": {
      "fileds": "value"
    }
  },
  "_source": ["fileds","fileds"]
}

GET /joker/user/_search
{
  "query": {
    "match": {
      "name": "張三"
    }
  },
  "_source": ["desc","name"]
}

在这里插入图片描述

排序

GET  /索引名稱/型別名稱/_search
{
  "query": {
    "match": {
      "fileds": "value"
    }
  },
  "_source": ["fileds","fileds"],
  "sort": [
    {
      "fileds": {
        "order": "desc"
      }
    }
  ]
}

例:
GET /joker/user/_search
{
  "query": {
    "match": {
      "name": "張三"
    }
  },
  "_source": ["desc","name","age"],
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

在这里插入图片描述

分頁查詢

GET /joker/user/_search
{
  "query": {
    "match": {
      "name": "張三"
    }
  },
  "from": 0, # 起始值  page
  "size": 20 # 查詢大小 pageSize
}

在这里插入图片描述
數據下標還是從0開始的,和學的所有數據結構是一樣的!
/seach/{current}/{pageSize}

布爾查詢

多條件查詢
must 相當於 and

GET /joker/user/_search
{
  "query": {
    "bool": {
     "must ": [
       {
         "match": {
           "name": "張三"
         }
       },
       {
         "match": {
           "age": 5
         }
       }
     ]
    }
  }
}

在这里插入图片描述
should相當於 or

GET /joker/user/_search
{
  "query": {
    "bool": {
     "should": [
       {
         "match": {
           "name": "張三"
         }
       },
       {
         "match": {
           "age": 5
         }
       }
     ]
    }
  }
}

在这里插入图片描述

not操作

GET /joker/user/_search
{
  "query": {
    "bool": {
     "must_not": [
       {
         "match": {
           "name": "張三"
         }
       },
       {
         "match": {
           "age": 5
         }
       }
     ]
    }
  }
}

在这里插入图片描述

過濾器 filter

GET /joker/user/_search
{
  "query": {
    "bool": {
     "must_not": [
       {
         "match": {
           "name": "張三"
         }
       }
     ],
     "filter": {
       "range": {
         "age": {
           "gt": 1, 
         }
       }
     }
    }
  }
}

篩選年齡大於1
在这里插入图片描述

  • gt 大於
  • lt 小於
  • gte 大於等於
  • lte 小於等於

匹配多個條件

多個條件之間使用空格隔開
只滿足其中一個即可查出
通過分值基本判斷
在这里插入图片描述

精確查詢

term查詢是直接通過倒排索引指定的詞條進程精確的查詢的!
關於分詞:

  • term :直接查詢精確的
  • match:會使用分詞器解析!(先分析文件,然後在通過分析的文件進行查詢!)

兩個型別 text 、 keyword
keyword不會被分詞器解析
text 會被分詞器解析

多個值匹配的精確查詢

在这里插入图片描述
在这里插入图片描述

高亮查詢

GET /joker/user/_search
{
  "query": {
    "match": {
      "name":"張三"
    }
  },
  "highlight": {
    "fields": {
      "name":{
        
      }
    }
  }
}

在这里插入图片描述
自定義高亮標籤
在这里插入图片描述

GET /joker/user/_search
{
  "query": {
    "match": {
      "name":"張三"
    }
  },
  "highlight": {
    "pre_tags":"<p class='key' style='color:red'>",
    "post_tags":"</p>",
    "fields": {
      "name":{
        
      }
    }
  }
}

整合SpringBoot

官方文件:

https://www.elastic.co/guide/index.html
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

檢視文件

在这里插入图片描述

匯入maven pom依賴

在这里插入图片描述
1、找到原生的依賴

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.6.2</version>
</dependency>

2、初始化
用完後關閉用戶端
在这里插入图片描述
3、分析類中的方法

  1. 建立空的父工程
    在这里插入图片描述

  2. 建立SpringBoot子模組
    在这里插入图片描述
    在这里插入图片描述
    勾選相關依賴
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    下載相關依賴
    在这里插入图片描述
    注意版本問題:要和本地es版本一致,否則可能會出現問題
    在这里插入图片描述
    在这里插入图片描述

  3. 新建設定類
    在这里插入图片描述

@Configuration
public class ElasticSearchclientConfig {
    
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http")));
        return client;

    }
}
  1. Api測試

建立索引

在这里插入图片描述

@SpringBootTest
class ElasticseachApplicationTests {
    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    //索引的建立 Request
    @Test
    void testCerateIndex() throws IOException {
        //1. 建立索引請求
        CreateIndexRequest request = new CreateIndexRequest("joker_index");
        //2. 執行建立請求 indices.create
        CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        System.out.println(createIndexResponse);
    }
}

判斷索引是否存在

在这里插入图片描述

    @Test
    void testGetindex() throws IOException {
        GetIndexRequest request = new GetIndexRequest("joker_index");
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

刪除索引

在这里插入图片描述

//刪除索引
    @Test
    void testDeleteindex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("test2");
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
        System.out.println(delete.isAcknowledged());
    }

建立新增文件

新增fastjson依賴
方便json轉換
在这里插入图片描述

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

在这里插入图片描述

 //新增文件
    @Test
    void testAddDocument() throws IOException {
        User user = new User("joker_dj", 18);
        //建立請求
        IndexRequest request = new IndexRequest("joker_index");
        // 規則 put joker_index/_doc/1
        request.id("1");
        request.timeout(TimeValue.timeValueSeconds(1));
        request.timeout("1s");
        //將我們的數據放入請求 json
        request.source(JSON.toJSONString(user), XContentType.JSON);
        //用戶端發送請求
        IndexResponse indexRespons = client.index(request, RequestOptions.DEFAULT);
        System.out.println(indexRespons.toString());
        System.out.println(indexRespons.status());
    }

獲取文件 判斷文件是否存在

在这里插入图片描述

 //獲取文件 判斷文件是否存在
    @Test
    void testexitdocument() throws IOException {
        GetRequest request = new GetRequest("joker_index", "1");
        //不獲取返回的上下文  _source
        request.fetchSourceContext(new FetchSourceContext(false));
        request.storedFields("_none_");
        boolean exists = client.exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

獲取文件的內容

在这里插入图片描述

//獲取文件的內容
    @Test
    void testGetDocument() throws IOException {
        GetRequest request = new GetRequest("joker_index", "1");
        GetResponse documentFields = client.get(request, RequestOptions.DEFAULT);
        System.out.println(documentFields.toString());//列印文件的內容
    }

更新文件內容

在这里插入图片描述

//更新文件資訊
    @Test
    void testUpdateDocument() throws IOException {
        UpdateRequest request = new UpdateRequest("joker_index", "1");
        request.timeout("1s");
        User user = new User("joker_djs", 20);
        request.doc(JSON.toJSONString(user),XContentType.JSON);
        UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
        System.out.println(update.status());
    }

刪除文件記錄

在这里插入图片描述

 //刪除文件記錄
    @Test
    void testDeleteRequst() throws IOException {
        DeleteRequest request = new DeleteRequest("joker_index", "1");
        request.timeout("1s");
        DeleteResponse delete = client.delete(request, RequestOptions.DEFAULT);
        System.out.println(delete.status());
    }

批次插入數據

在这里插入图片描述

 // 批次插入數據
    @Test
    void testBulkRequest() throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");
        ArrayList<User> userList=new ArrayList<>();
        userList.add(new User("joker1",18));
        userList.add(new User("joker2",18));
        userList.add(new User("joker3",18));
        userList.add(new User("joker4",18));
        userList.add(new User("joker5",18));
        userList.add(new User("joker6",18));
        userList.add(new User("joker7",18));
        userList.add(new User("joker8",18));
        for (int i = 0; i < userList.size(); i++) {
            bulkRequest.add(new IndexRequest("joker_index")
                    .id(""+(i+1))
                    .source(JSON.toJSONString(userList.get(i)),XContentType.JSON));
        }
        BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(bulk.hasFailures()); //false 成功
    }

在这里插入图片描述

高階查詢

在这里插入图片描述

//查詢
    //搜尋請求 SearchRequest
    //條件構造 SearchSourceBuilder
    //MatchAllQueryBuilder
    //TermQueryBuilder 精確查詢
    // xxx QueryBuilder 
    @Test
    void testSearch() throws IOException {
        SearchRequest searchRequest = new SearchRequest("joker_index");
        //構建搜尋條件
        SearchSourceBuilder SourceBuilder = new SearchSourceBuilder();
        //高亮
        SourceBuilder.highlighter();
        //查詢條件 我們可以使用QueryBuidler
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "joker1");
//        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        SourceBuilder.query(matchAllQueryBuilder);
        SourceBuilder.timeout(new TimeValue(60,TimeUnit.SECONDS));

        //構建搜尋
        searchRequest.source(SourceBuilder);
        /*用戶端執行*/
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println(JSON.toJSONString(search.getHits()));
        System.out.println("==============================");
        for (SearchHit hit : search.getHits().getHits()) {
            System.out.println(hit.getSourceAsMap());
        }
    }

實戰

專案搭建

  1. 新建一個SpringBoot專案
    在这里插入图片描述
    勾選依賴
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    引入fastjson
 <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

組態檔
在这里插入图片描述
引入靜態頁面
在这里插入图片描述
啓動存取
在这里插入图片描述

爬蟲

數據問題?數據庫獲取,訊息佇列中獲取中,都可以成爲數據源,爬蟲!

爬取數據:(獲取請求返回的頁面資訊,篩選出我們想要的數據就可以了!)

jsoup

在这里插入图片描述

<!--解析網頁jsoup-->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.10.2</version>
        </dependency>

編寫解析網頁工具包

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

把爬取到的數據封裝成物件

在这里插入图片描述

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Content {
    private String title;
    private String img;
    private String price;
}

封裝工具類

在这里插入图片描述

public class HtmlParseUtil {
    public static void main(String[] args) throws IOException {
        new HtmlParseUtil().ParseJD(encode).forEach(System.out::println);
    }

    public  List<Content> ParseJD(String keywords) throws IOException {
        //獲取請求 :https://search.jd.com/Search?keyword=java
        //需要聯網
        String encode = URLEncoder.encode(keywords, "UTF-8");//url字元跳脫
        String url="https://search.jd.com/Search?keyword="+ keywords;
        //解析網頁 (Jsoup返回的Document物件就是JS的Document物件)
        Document document = Jsoup.parse(new URL(url), 30000);
        //所有js的方法都可以使用
        Element element = document.getElementById("J_goodsList");
        //獲取所有的li標籤
        Elements elements = element.getElementsByTag("li");

        ArrayList<Content> goods = new ArrayList<>();
        for (Element el : elements) {
            //關於圖片特別多的網站 所有圖片都是懶載入
            String img = el.getElementsByTag("img").eq(0).attr("src");//圖片
            String price = el.getElementsByClass("p-price").eq(0).text();//價格
            String title = el.getElementsByClass("p-name").eq(0).text();//標題

            Content content = new Content(title, img, price);
            goods.add(content);

        }
        return goods;
    }
}

編寫elasticsearch設定類

ElasticSearchclientConfig

@Configuration
public class ElasticSearchclientConfig {

    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http")));
        return client;

    }
}

建立index索引

在这里插入图片描述

建立業務層

在这里插入图片描述

//業務編寫
@Service
public class ContentService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    
    //解析數據放入es中
    public boolean parseContent(String keywords) throws IOException {
        List<Content> contents = new HtmlParseUtil().ParseJD(keywords);
        //把查詢得到的數據放到es中
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("2m");
        for (int i = 0; i < contents.size(); i++) {
            bulkRequest.add(new IndexRequest("jd_goods")
                    .source(JSON.toJSONString(contents.get(i)), XContentType.JSON));
                    
        }
        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        return !bulk.hasFailures();
    }
}

編寫controller

在这里插入图片描述

@RestController
public class ContentController {
    @Autowired
    ContentService service;
    @GetMapping("/parse/{keywords}")
    public boolean parse(@PathVariable("keywords") String keywords) throws IOException {
       return service.parseContent(keywords);
    }
}

執行:localhost:9090/parse/java
在这里插入图片描述

獲取數據實現搜尋功能

Service層

 //2. 獲取數據實現搜尋功能
    public List<Map<String,Object>> searchPage(String keywords,int page,int pageSize) throws IOException {
        if(page<=1){
            page=1;
        }
        //條件搜尋
        SearchRequest searchRequest = new SearchRequest("jd_goods");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //分頁
        sourceBuilder.from(page);
        sourceBuilder.size(pageSize);
	 //模糊匹配
        MatchPhraseQueryBuilder title = QueryBuilders.matchPhraseQuery("title", keywords);
        //精確匹配
       // TermQueryBuilder title = QueryBuilders.termQuery("title", keywords);
        sourceBuilder.query(title);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        //執行搜尋
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //解析結果
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : search.getHits().getHits()) {
            list.add(hit.getSourceAsMap());
        }
        return list;
    }

Controller
在这里插入图片描述

   @GetMapping("/search/{keywords}/{page}/{pageSize}")
    public List<Map<String,Object>> search(@PathVariable("keywords") String keywords,@PathVariable("page") int page,@PathVariable("pageSize") int pageSize) throws IOException {
        return  service.searchPage(keywords, page, pageSize);
    }

存取測試
在这里插入图片描述

前端渲染數據 vue

下載vue
npm install vue
npm install axios
在这里插入图片描述
引入工程中
在这里插入图片描述
在这里插入图片描述
編寫vue程式碼
在这里插入图片描述

<script>
new Vue({
    el:"#app",
    data:{
        keywords:"",//搜尋的關鍵字
        result:[]//搜尋的結果
    },
    methods:{
        searchkey(){
            var keyword=this.keywords;
           axios.get("/search/"+keyword+"/1/10").then(res=>{
               this.result=res.data;
           }).catch(err=>{

           })
        }
    }
})
</script>

數據渲染
在这里插入图片描述
在这里插入图片描述

實現搜尋高亮

在这里插入图片描述
在这里插入图片描述

//3. 獲取數據實現高亮搜尋功能
    public List<Map<String,Object>> searchHighlightPage(String keywords,int page,int pageSize) throws IOException {
        if(page<=1){
            page=1;
        }
        //條件搜尋
        SearchRequest searchRequest = new SearchRequest("jd_goods");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.requireFieldMatch(false);//是否多個欄位高亮;
        highlightBuilder.field("title");//設定高亮的欄位
        highlightBuilder.preTags("<span style='color:red'>");//設定字首
        highlightBuilder.postTags("</span>");//設定後綴
        sourceBuilder.highlighter(highlightBuilder);
        //分頁
        sourceBuilder.from(page);
        sourceBuilder.size(pageSize);

        //模糊匹配
        MatchPhraseQueryBuilder titles = QueryBuilders.matchPhraseQuery("title", keywords);
        //精確匹配
        //TermQueryBuilder title = QueryBuilders.termQuery("title", keywords);
        sourceBuilder.query(titles);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        //執行搜尋
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //解析結果
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : search.getHits().getHits()) {

            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField title = highlightFields.get("title");
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();//原來的結果
            //解析高亮的欄位
            if(title!=null){
                Text[] fragments = title.fragments();
                String n_title="";
                for (Text text : fragments) {
                    n_title+=text;
                }
                sourceAsMap.put("title",n_title);
            }
            list.add(sourceAsMap);
        }
        return list;
    }

contrller參照
在这里插入图片描述
存取測試
在这里插入图片描述
推薦視訊 elasticsearch up主 遇見狂神說:
bilibili鏈接