ElasticSearch
Elasticsearch是一個(gè)基于Lucene的搜索服務(wù)器。它提供了一個(gè)分布式多用戶能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java語言開發(fā)的,并作為Apache許可條款下的開放源碼發(fā)布,是一種流行的企業(yè)級搜索引擎。Elasticsearch用于云計(jì)算中,能夠達(dá)到實(shí)時(shí)搜索,穩(wěn)定,可靠,快速,安裝使用方便。官方客戶端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和許多其他語言中都是可用的。根據(jù)DB-Engines的排名顯示,Elasticsearch是最受歡迎的企業(yè)搜索引擎,其次是Apache Solr,也是基于Lucene
如京東,淘寶
Lucene是一個(gè)Java語言的搜索引擎類庫,是Apache公司的頂級項(xiàng)目,由DougCutting于1999年研發(fā)。官網(wǎng)地址: https:// lucene.apache.org/
重要性:
- 分布式的實(shí)時(shí)文件存儲,每個(gè)字段都被索引并可被搜索
- 實(shí)時(shí)分析的分布式搜索引擎
- 可以擴(kuò)展到上百臺服務(wù)器,處理PB級結(jié)構(gòu)化或非結(jié)構(gòu)化數(shù)據(jù)
倒排索引
倒排索引的概念是基于MySQL這樣的正向索引而言的
正向索引
但如果是基于title做模糊查詢,只能是逐行掃描數(shù)據(jù),流程如下:
- 用戶搜索數(shù)據(jù),條件是title符合“
%手機(jī)%
” - 逐行獲取數(shù)據(jù),比如id為1的數(shù)據(jù)
- 判斷數(shù)據(jù)中的title是否符合用戶搜索條件
- 如果符合則放入結(jié)果集,不符合則丟棄?;氐讲襟E1
逐行掃描,也就是全表掃描,隨著數(shù)據(jù)量增加,其查詢效率也會越來越低。當(dāng)數(shù)據(jù)量達(dá)到數(shù)百萬時(shí),就是一場災(zāi)難。
倒排索引
倒排索引中有兩個(gè)非常重要的概念:
- 文檔Document:用來搜索的數(shù)據(jù),其中的每一條數(shù)據(jù)就是一個(gè)文檔。例如一個(gè)網(wǎng)頁、一個(gè)商品信息
- 詞條Term:對文檔數(shù)據(jù)或用戶搜索數(shù)據(jù),利用某種算法分詞,得到的具備含義的詞語就是詞條。例如:我是中國人,就可以分為:我、是、中國人、中國、國人這樣的幾個(gè)詞條
創(chuàng)建倒排索引是對正向索引的一種特殊處理,流程如下:
- 將每一個(gè)文檔的數(shù)據(jù)利用算法分詞,得到一個(gè)個(gè)詞條
- 創(chuàng)建表,每行數(shù)據(jù)包括詞條、詞條所在文檔id、位置等信息
- 因?yàn)樵~條唯一性,可以給詞條創(chuàng)建索引,例如hash表結(jié)構(gòu)索引
倒排索引的搜索流程如下(以搜尋“華為手機(jī)”為例)
- 用戶輸入條件 “華為手機(jī)” 進(jìn)行搜索。
- 對用戶輸入內(nèi)容分詞,得到詞條: 華為 、 手機(jī) 。
- 拿著詞條在倒排索引中查找,可以得到包含詞條的文檔id:1、2、3。
- 拿著文檔id到正向索引中查找具體文檔
雖然要先查詢倒排索引,再查詢倒排索引,但是無論是詞條、還是文檔id都建立了索引,查詢速度非??欤o需全表掃描。
正向和倒排
- 正向索引是最傳統(tǒng)的,根據(jù)id索引的方式。但根據(jù)詞條查詢時(shí),必須先逐條獲取每個(gè)文檔,然后判斷文檔中是否包含所需要的詞條,是根據(jù)文檔找詞條的過程。
- 而倒排索引則相反,是先找到用戶要搜索的詞條,根據(jù)詞條得到保護(hù)詞條的文檔的id,然后根據(jù)id獲取文檔。是根據(jù)詞條找文檔的過程
正向索引
優(yōu)點(diǎn):
- 可以給多個(gè)字段創(chuàng)建索引
- 根據(jù)索引字段搜索、排序速度非???/li>
缺點(diǎn):
- 根據(jù)非索引字段,或者索引字段中的部分詞條查找時(shí),只能全表掃描
倒排索引
優(yōu)點(diǎn):
- 根據(jù)詞條搜索、模糊搜索時(shí),速度非???/li>
缺點(diǎn):
- 只能給詞條創(chuàng)建索引,而不是字段
- 無法根據(jù)字段做排序
ES的一些概念
elasticsearch中有很多獨(dú)有的概念,與mysql中略有差別,但也有相似之處
文檔和字段
elasticsearch是面向**文檔(Document)**存儲的,可以是數(shù)據(jù)庫中的一條商品數(shù)據(jù),一個(gè)訂單信息。文檔數(shù)據(jù)會被序列化為json格式后存儲在elasticsearch中:
而Json文檔中往往包含很多的字段(Field),類似于數(shù)據(jù)庫中的列
索引和映射
索引(Index),就是相同類型的文檔的集合。
例如:
- 所有用戶文檔,就可以組織在一起,稱為用戶的索引;
- 所有商品的文檔,可以組織在一起,稱為商品的索引;
- 所有訂單的文檔,可以組織在一起,稱為訂單的索引;
因此,我們可以把索引當(dāng)做是數(shù)據(jù)庫中的表。
數(shù)據(jù)庫的表會有約束信息,用來定義表的結(jié)構(gòu)、字段的名稱、類型等信息。因此,索引庫中就有映射(mapping),是索引中文檔的字段約束信息,類似表的結(jié)構(gòu)約束。
MySQL和ElasticSearch
我們統(tǒng)一的把mysql與elasticsearch的概念做一下對比
ES環(huán)境安裝
ES環(huán)境需要ES和分詞器
環(huán)境搭建步驟:
- windows版ES下載:網(wǎng)址https://www.elastic.co/cn/downloads/elasticsearch
- 下載分詞器(4IK分詞器):https://github.com/medcl/elasticsearch-analysis-ik/releases
- 解壓縮ES,并且在解壓縮的plugins創(chuàng)建ik文件夾
- 將4IK分詞器解壓后的所有文件拷貝到創(chuàng)建的ik文件夾下
啟動ES:
- 找到ES文件夾下的bin文件夾,雙擊文件 elasticsearch.bat(彈出窗口不要關(guān)閉)
- 瀏覽器訪問localhost:9200能看到j(luò)son代表啟動成功
4IK分詞器
作用:
- 創(chuàng)建倒排索引時(shí)對文檔分詞
- 用戶搜索時(shí),對輸入的內(nèi)容分詞
IK分詞器的模式:
- ik_smart:智能切分,粗粒度
- ik_max_word:最細(xì)切分,細(xì)粒度
索引庫操作
索引庫就類似數(shù)據(jù)庫表,mapping映射就類似表的結(jié)構(gòu)。
我們要向es中存儲數(shù)據(jù),必須先創(chuàng)建“庫”和“表”。
mapping映射屬性
mapping是對索引庫中文檔的約束,常見的mapping屬性包括:
type:字段數(shù)據(jù)類型,常見的簡單類型有:
- 字符串:text(可分詞的文本)、keyword(精確值,例如:品牌、國家、ip地址)
- 數(shù)值:long、integer、short、byte、double、float
- 布爾:boolean
- 日期:date
- 對象:object
index:是否創(chuàng)建索引,默認(rèn)為true
analyzer:使用哪種分詞器
properties:該字段的子字段
Eg:
{
"age": 18,
"weight": 70.2,
"isMarried": false,
"info": "apesourceJavaEE王講師",
"email": "wangls@163.com",
"score": [99.1, 99.5, 98.9],
"name": {
"firstName": "師傅",
"lastName": "王"
}
}
對應(yīng)的每個(gè)字段映射(mapping):
- age:類型為 integer;參與搜索,因此需要index為true;無需分詞器
- weight:類型為float;參與搜索,因此需要index為true;無需分詞器
- isMarried:類型為boolean;參與搜索,因此需要index為true;無需分詞器
- info:類型為字符串,需要分詞,因此是text;參與搜索,因此需要index為true;分詞器可以用ik_smart
- email:類型為字符串,但是不需要分詞,因此是keyword;不參與搜索,因此需要index為false;無需分詞器
- score:雖然是數(shù)組,但是我們只看元素的類型,類型為float;參與搜索,因此需要index為true;無需分詞器
- name:類型為object,需要定義多個(gè)子屬性
- name.firstName;類型為字符串,但是不需要分詞,因此是keyword;參與搜索,因此需要index為true;無需分詞器
- name.lastName;類型為字符串,但是不需要分詞,因此是keyword;參與搜索,因此需要
- index為true;無需分詞器
創(chuàng)建索引庫和映射
基本語法:
- 請求方式:PUT
- 請求路徑:/索引庫名,可以自定義
- 請求參數(shù):mapping
格式:
{
"mappings":{
"properties":{
"age":{
"type":"integer"
},
"isMarried":{
"type":"boolean"
},
"name":{
"type":"text",
"analyzer":"ik_smart"
},
"info":{
"type":"text",
"index":"false"
},
"pet":{
"properties":{
"dog":{
"type":"text"
},
"cat":{
"type":"text"
}
}
}
}
}
}
Postman測試創(chuàng)建索引庫和映射
查詢索引庫
基本語法:
- 請求方式:GET
- 請求路徑:/索引庫名
- 請求參數(shù):無
格式:
GET /索引庫名
eg:postman發(fā)送GET請求:localhost:9200/teachers
修改索引庫
倒排索引結(jié)構(gòu)雖然不復(fù)雜,但是一旦數(shù)據(jù)結(jié)構(gòu)改變(比如改變了分詞器),就需要重新創(chuàng)建倒排索引,這簡直是災(zāi)難。因此索引庫一旦創(chuàng)建,無法修改mapping。
雖然無法修改mapping中已有的字段,但是卻允許添加新的字段到mapping中,因?yàn)椴粫Φ古潘饕a(chǎn)生影響。
語法說明:
PUT /索引庫名/_mapping
{
"properties": {
"新字段名":{
"type": "integer"
}
}
}
eg:postman發(fā)送PUT請求:localhost:9200/teachers/_mapping
刪除索引庫
語法:
- 請求方式:DELETE
- 請求路徑:/索引庫名
- 請求參數(shù):無
格式:
DELETE /索引庫名
postman發(fā)送DELETE請求:localhost:9200/teachers
總結(jié):
- 創(chuàng)建索引庫:PUT /索引庫名
- 查詢索引庫:GET /索引庫名
- 刪除索引庫:DELETE /索引庫名
- 添加字段:PUT /索引庫名/_mapping
文檔操作
新增文檔
語法:
POST /索引庫名/_doc/文檔id
{
"字段1": "值1",
"字段2": "值2",
"字段3": {
"子屬性1": "值3",
"子屬性2": "值4"
},
// ...
}
eg:
POST請求:localhost:9200/teachers/_doc/1
{
"info":"java程序開發(fā)工程師",
"age":"23",
"name":"詹姆斯高斯林",
"pet":{
"拉布拉多":"旺財(cái)",
"英短":"小老弟"
}
}
查詢文檔
根據(jù)rest風(fēng)格,新增是post,查詢應(yīng)該是get,不過查詢一般都需要條件,這里我們把文檔id帶上。
語法:
GET /{索引庫名稱}/_doc/{id}
查看數(shù)據(jù):
GET請求:localhost:9200/teachers/_doc/1
localhost:9200/teachers/_doc/1
刪除文檔
刪除使用DELETE請求,同樣,需要根據(jù)id進(jìn)行刪除
語法:
DELETE /{索引庫名}/_doc/id值
eg:
DELETE請求
localhost:9200/teachers/_doc/1
修改文檔
- 全量修改:直接覆蓋原來的文檔
- 增量修改:修改文檔中的部分字段
全量修改
全量修改是覆蓋原來的文檔,其本質(zhì)是:
- 根據(jù)指定的id刪除文檔
- 新增一個(gè)相同id的文檔
**注意:**如果根據(jù)id刪除時(shí),id不存在,第二步的新增也會執(zhí)行,也就從修改變成了新增操作了
語法:
PUT /{索引庫名}/_doc/文檔id
{
"字段1": "值1",
"字段2": "值2",
// ... 略
}
eg:
postman發(fā)送PUT請求:localhost:9200/teachers/_doc/1
{
"info":"python程序開發(fā)工程",
"name":"吉多范羅蘇姆",
"age":"22",
"pet":{
"拉布拉多":"旺財(cái)",
"英短":"小老弟"
}
}
全量修改
增量修改是只修改指定id匹配的文檔中的部分字段
語法:
POST /{索引庫名}/_update/文檔id
{
"doc": {
"字段名": "新的值",
}
}
eg:
postman發(fā)送POST請求:localhost:9200/teachers/_update/1
{
"doc":{
"name":"詹姆斯高斯林再牛逼也進(jìn)不了谷歌"
}
}
總結(jié):
- 創(chuàng)建文檔:POST /{索引庫名}/_doc/文檔id { json文檔 }
- 查詢文檔:GET /{索引庫名}/_doc/文檔id
- 刪除文檔:DELETE /{索引庫名}/_doc/文檔id
- 修改文檔:
- 全量修改:PUT /{索引庫名}/_doc/文檔id { json文檔 }
- 增量修改:POST /{索引庫名}/_update/文檔id { “doc”: {字段}}
RestAPI
ES官方提供了各種不同語言的客戶端,用來操作ES。這些客戶端的本質(zhì)就是組裝DSL語句,通過http請求發(fā)送給ES。官方文檔地址:https://www.elastic.co/guide/en/elasticsearch/client/index.html
其中的Java Rest Client又包括兩種:
- Java Low Level Rest Client
- Java High Level Rest Client
主要介紹Java High Level Rest Client
數(shù)據(jù)庫建表語句
CREATE TABLE `tb_hotel` (
`id` bigint(20) NOT NULL COMMENT '酒店id',
`name` varchar(255) NOT NULL COMMENT '酒店名稱;例:7天酒店',
`address` varchar(255) NOT NULL COMMENT '酒店地址;例:航頭路',
`price` int(10) NOT NULL COMMENT '酒店價(jià)格;例:329',
`score` int(2) NOT NULL COMMENT '酒店評分;例:45,就是4.5分',
`brand` varchar(32) NOT NULL COMMENT '酒店品牌;例:如家',
`city` varchar(32) NOT NULL COMMENT '所在城市;例:上海',
`star_name` varchar(16) DEFAULT NULL COMMENT '酒店星級,從低到高分別是:1星到5星,1
鉆到5鉆',
`business` varchar(255) DEFAULT NULL COMMENT '商圈;例:虹橋',
`latitude` varchar(32) NOT NULL COMMENT '緯度;例:31.2497',
`longitude` varchar(32) NOT NULL COMMENT '經(jīng)度;例:120.3925',
`pic` varchar(255) DEFAULT NULL COMMENT '酒店圖片;例:/img/1.jpg',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
mapping映射分析
酒店數(shù)據(jù)的索引庫結(jié)構(gòu):
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"name":{
"type": "text",
"analyzer": "ik_max_word",
"copy_to": "all"
},
"address":{
"type": "keyword",
"index": false,
"copy_to": "all"
},
"price":{
"type": "integer"
},
"score":{
"type": "integer"
},
"brand":{
"type": "keyword",
"copy_to": "all"
},
"city":{
"type": "keyword",
"copy_to": "all"
},
"starName":{
"type": "keyword"
},
"business":{
"type": "keyword"
},
"location":{
"type": "geo_point"
},
"pic":{
"type": "keyword",
"index": false
},
"all":{
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
幾個(gè)特殊字段說明:
location:地理坐標(biāo),里面包含精度、緯度
all:一個(gè)組合字段,其目的是將多字段的值 利用copy_to合并,提供給用戶搜索
地理坐標(biāo)說明:
copy_to說明:
JAVA中使用ES
初始化RestClient
在elasticsearch提供的API中,與elasticsearch一切交互都封裝在一個(gè)名為RestHighLevelClient的類中,必須先完成這個(gè)對象的初始化,建立與elasticsearch的連接。
在Spring Boot中使用ES三步驟:
-
引入es的RestHighLevelClient依賴
<dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency>
-
因?yàn)镾pringBoot默認(rèn)的ES版本是7.6.2,所以我們需要覆蓋默認(rèn)的ES版本
<properties> <java.version>1.8</java.version> <elasticsearch.version>7.12.0</elasticsearch.version> </properties>
-
初始化RestHighLevelClient
將RestHighLevelClient注入容器,可以寫配置類,也可以寫在啟動類中
@Bean public RestHighLevelClient restHighLevelClient(){ RestHighLevelClient client = new RestHighLevelClient(RestClient.builder( HttpHost.create("http://localhost:9200") )); }
創(chuàng)建索引庫
-
準(zhǔn)備索引庫映射字符串
public class HotelConstants { public static final String MAPPING_TEMPLATE = "{\n" + " \"mappings\": {\n" + " \"properties\": {\n" + " \"id\": {\n" + " \"type\": \"keyword\"\n" + " },\n" + " \"name\":{\n" + " \"type\": \"text\",\n" + " \"analyzer\": \"ik_max_word\",\n" + " \"copy_to\": \"all\"\n" + " },\n" + " \"address\":{\n" + " \"type\": \"keyword\",\n" + " \"index\": false\n" + " },\n" + " \"price\":{\n" + " \"type\": \"integer\"\n" + " },\n" + " \"score\":{\n" + " \"type\": \"integer\"\n" + " },\n" + " \"brand\":{\n" + " \"type\": \"keyword\",\n" + " \"copy_to\": \"all\"\n" + " },\n" + " \"city\":{\n" + " \"type\": \"keyword\",\n" + " \"copy_to\": \"all\"\n" + " },\n" + " \"starName\":{\n" + " \"type\": \"keyword\"\n" + " },\n" + " \"business\":{\n" + " \"type\": \"keyword\"\n" + " },\n" + " \"location\":{\n" + " \"type\": \"geo_point\"\n" + " },\n" + " \"pic\":{\n" + " \"type\": \"keyword\",\n" + " \"index\": false\n" + " },\n" + " \"all\":{\n" + " \"type\": \"text\",\n" + " \"analyzer\": \"ik_max_word\"\n" + " }\n" + " }\n" + " }\n" + "}"; }
-
索引庫的操作
@SpringBootTest class SpringbootEs01ApplicationTests { private RestHighLevelClient client; @BeforeEach void setUp(){ this.client = new RestHighLevelClient(RestClient.builder( HttpHost.create("http://localhost:9200") )); } @AfterEach void tearDown() throws Exception{ this.client.close(); } // 判斷索引庫是否存在 @Test void testExistsHotelIndex() throws Exception { GetIndexRequest request = new GetIndexRequest("hotels"); boolean exists = client.indices().exists(request, RequestOptions.DEFAULT); System.err.println(exists ? "索引庫已經(jīng)存在":"索引庫不存在"); } // 創(chuàng)建索引庫 @Test void createHotelIndex() throws Exception{ // 創(chuàng)建Request對象 CreateIndexRequest request = new CreateIndexRequest("hotels"); // 準(zhǔn)備請求的參數(shù):DSL語句 request.source(HotelConstants.MAPPING_TEMPLATE, XContentType.JSON); // 發(fā)送請求 client.indices().create(request,RequestOptions.DEFAULT); } // 刪除索引庫 @Test void delteHotelIndex() throws Exception{ // 創(chuàng)建Request對象 DeleteIndexRequest request = new DeleteIndexRequest("hotels"); // 發(fā)送請求 client.indices().delete(request,RequestOptions.DEFAULT); } }
總結(jié)
JavaRestClient操作elasticsearch的流程基本類似。核心是client.indices()方法來獲取索引庫的操作對象
索引庫操作的基本步驟:
- 初始化RestHighLevelClient
- 創(chuàng)建XxxIndexRequest。XXX是Create、Get、Delete
- 準(zhǔn)備DSL( Create時(shí)需要,其它是無參)
- 發(fā)送請求。調(diào)用RestHighLevelClient#indices().xxx()方法,xxx是create、exists、delete
文檔操作
演示在juint單元測試中進(jìn)行,準(zhǔn)備
@SpringBootTest
public class HotelDocumentTests {
// 核心對象
private RestHighLevelClient client;
// 需要從數(shù)據(jù)庫中查數(shù)據(jù)存入es,裝配業(yè)務(wù)
@Autowired(required = false)
private IHotelService service;
@BeforeEach
void setUp(){
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://localhost:9200")
));
}
@AfterEach
void tearDown() throws Exception{
this.client.close();
}
}
-
從數(shù)據(jù)庫中新增一條數(shù)據(jù)到ES
@Test void addDocument() throws Exception{ // 從數(shù)據(jù)庫查詢一條數(shù)據(jù) Hotel hotel = service.getById(395434); System.out.println(hotel); // 轉(zhuǎn)換為文檔類型 HotelDoc hotelDoc = new HotelDoc(hotel); // 將文檔類型轉(zhuǎn)為JSON格式 String json = JSON.toJSONString(hotelDoc); // 準(zhǔn)備request請求對象 IndexRequest request = new IndexRequest("hotels").id(hotelDoc.getId().toString()); // 準(zhǔn)備JSON文檔 request.source(json, XContentType.JSON); // 發(fā)送請求 client.index(request, RequestOptions.DEFAULT); }
-
從ES中刪除一條數(shù)據(jù)
@Test void deleteDocument() throws Exception{ // 準(zhǔn)備刪除請求Request DeleteRequest request = new DeleteRequest("hotels", "395434"); client.delete(request,RequestOptions.DEFAULT); }
-
修改ES中的數(shù)據(jù)
修改有兩種方式:
- 全量修改:本質(zhì)是先根據(jù)id刪除,再新增
- 增量修改:修改文檔中的指定字段值
- 在RestClient的API中,全量修改與新增的API完全一致
@Test void updateDocument() throws Exception{ // 準(zhǔn)備修改請求UpdateRequest UpdateRequest request = new UpdateRequest("hotels", "395434"); // 準(zhǔn)備請求參數(shù)(要修改的數(shù)據(jù)內(nèi)容) request.doc( "name","W酒店", "city","西安", "price","2000", "starName","五星級" ); }
-
批量新增數(shù)據(jù)到ES中
@Test void addAllDocument() throws Exception{ // 數(shù)據(jù)庫全查 List<Hotel> hotels = service.list(); // 準(zhǔn)備請求 BulkRequest bulkRequest = new BulkRequest(); // 準(zhǔn)備參數(shù) for(Hotel hotel : hotels){ // 類型轉(zhuǎn)化 HotelDoc hotelDoc = new HotelDoc(hotel); // 請求添加數(shù)據(jù) bulkRequest.add(new IndexRequest("hotels").id(hotelDoc.getId().toString()).source(JSON.toJSONString(hotelDoc),XContentType.JSON)); } // 發(fā)送請求 client.bulk(bulkRequest,RequestOptions.DEFAULT); }
總結(jié)
文檔操作的基本步驟:
- 初始化RestHighLevelClient
- 創(chuàng)建XxxRequest。XXX是Index、Get、Update、Delete、Bulk
- 準(zhǔn)備參數(shù)(Index、Update、Bulk時(shí)需要)
- 發(fā)送請求。調(diào)用RestHighLevelClient#.xxx()方法,xxx是index、get、update、delete、bulk
- 解析結(jié)果(Get時(shí)需要)
查詢文檔操作
Elasticsearch提供了基于JSON的DSL(Domain Specific Language)來定義查詢。常見的查詢類型包括:
==查詢所有:==查詢出所有數(shù)據(jù),一般測試用(不會顯示出所有,自帶分頁功能)。例如:match_all
==全文檢索(full text)查詢:==利用分詞器對用戶輸入內(nèi)容分詞,然后去倒排索引庫中匹配。例如:
- match_query:單字段查詢
- multi_match_query:多字段查詢,任意一個(gè)字段符合條件就算符合查詢條件
==準(zhǔn)確查詢:==根據(jù)精確詞條值查找數(shù)據(jù),一般是查找keyword、數(shù)值、日期、boolean等類型字段。例如
- ids:id查詢
- range:根據(jù)值的范圍查詢
- term:根據(jù)詞條精確值查詢
==地理(geo)查詢:==根據(jù)經(jīng)緯度查詢。例如:
- geo_distance
- geo_bounding_box
==復(fù)合(compound)查詢:==復(fù)合查詢可以將上述各種查詢條件組合起來,合并查詢條件。例如:
-
bool
-
function_score
-
查詢一條數(shù)據(jù)
@Test void getDocumentById() throws Exception{ // 準(zhǔn)備查詢請求GetRequest GetRequest getRequest = new GetRequest("hotels", "395434"); // 發(fā)送請求,得到響應(yīng) GetResponse response = client.get(getRequest, RequestOptions.DEFAULT); // 解析響應(yīng)結(jié)果 String json = response.getSourceAsString(); HotelDoc hotelDoc = JSON.parseObject(json,HotelDoc.class); System.out.println(hotelDoc); }
-
解析對象方法
// 解析對象方法 public void show(SearchResponse response){ // 解析響應(yīng) SearchHits searchHits = response.getHits(); long total = searchHits.getTotalHits().value; System.out.println("總計(jì)查詢數(shù)據(jù):"+total+"條"); SearchHit[] hits = searchHits.getHits(); for(SearchHit hit :hits){ /// 獲取文檔source String json = hit.getSourceAsString(); // 反序列化 HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class); System.out.println("hotelDoc="+hotelDoc); } }
-
全查
@Test void findAllDocument() throws IOException{ // 準(zhǔn)備request SearchRequest request = new SearchRequest("hotels"); // 2.準(zhǔn)備DSL,QueryBuilders構(gòu)造查詢條件 request.source().query(QueryBuilders.matchAllQuery()); // 3.發(fā)送請求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); show(response); }
-
全文索引----查詢all字段內(nèi)容中含有如家的
@Test void testMacth() throws IOException{ // 準(zhǔn)備請求 SearchRequest request = new SearchRequest("hotels"); // 準(zhǔn)備DSL request.source(). query(QueryBuilders.matchQuery("all","如家")); // 發(fā)送請求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); show(response); }
-
全文索引----多字段查詢
@Test void testMultiMatchQuery()throws IOException { // 準(zhǔn)備請求 SearchRequest request = new SearchRequest("hotels"); // 準(zhǔn)備DSL request.source() .query(QueryBuilders.multiMatchQuery("上海","name","city")); // 發(fā)送請求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); show(response); }
-
精確查詢1
// term:根據(jù)詞條精準(zhǔn)查詢(字段等值查詢) @Test void testTerm() throws IOException{ // 準(zhǔn)備請求 SearchRequest request = new SearchRequest("hotels"); // 準(zhǔn)備DSL request.source() .query(QueryBuilders.termQuery("brand","希爾頓")); // 發(fā)送請求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); show(response); }
-
精確查詢2
// range范圍查詢 @Test void testRange() throws IOException { // 準(zhǔn)備請求 SearchRequest request = new SearchRequest("hotels"); // 準(zhǔn)備DSL request.source() .query(QueryBuilders.rangeQuery("price").gte(200).lte(300)); // 發(fā)送請求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); show(response); }
-
精確查詢3
// ids查詢 @Test void testIds() throws IOException { // 準(zhǔn)備請求 SearchRequest request = new SearchRequest("hotels"); // 準(zhǔn)備DSL request.source() .query(QueryBuilders.idsQuery().addIds("395434","3532")); // 發(fā)送請求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); show(response); }
-
復(fù)合查詢
// bool復(fù)合查詢 @Test void testBool() throws IOException{ // 準(zhǔn)備請求 SearchRequest request = new SearchRequest("hotels"); // 準(zhǔn)備條件 /*-- 方式1 ----*/ // BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); // boolQueryBuilder.must(QueryBuilders.termQuery("city","北京")); // boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(500)); // // 準(zhǔn)備DSL // request.source().query(boolQueryBuilder); /*---- 方式2 ----*/ request.source() .query(QueryBuilders.boolQuery() .must(QueryBuilders.termQuery("city","北京")) .filter(QueryBuilders.rangeQuery("price").lte(500))); // 發(fā)送請求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); show(response); }
-
自定義分頁規(guī)則
// 自定義分頁方式 @Test void testPageAndSort() throws IOException{ int page = 1; //頁碼 int size = 5; //步長 String searchName="希爾頓"; // 查詢條件 // 準(zhǔn)備請求 SearchRequest request = new SearchRequest("hotels"); if (searchName == null){ request.source().query(QueryBuilders.matchAllQuery()); }else { request.source().query(QueryBuilders.matchQuery("brand",searchName)); } // 自定義分頁 request.source().from((page-1)*size).size(size); // 自定義排序 request.source().sort("price", SortOrder.DESC); SearchResponse response = client.search(request, RequestOptions.DEFAULT); show(response); }
總結(jié)
SpringBoot中整合ES的實(shí)現(xiàn)步驟 :
-
導(dǎo)pom文件ES的坐標(biāo)
<properties> <java.version>1.8</java.version> <elasticsearch.version>7.12.0</elasticsearch.version> </properties>
-
寫ES配置類
@Configuration public class ElasticSearchConfig { @Bean public RestHighLevelClient restHighLevelClient(){ return new RestHighLevelClient(RestClient.builder( HttpHost.create("http://localhost:9200") )); } }
-
寫ES映射Mapping
-
建立ES索引庫
public void createEs() throws IOException { GetIndexRequest request = new GetIndexRequest("employee"); // 判斷索引庫是否存在 boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT); // 如果不存在建庫 if(!exists){ // 創(chuàng)建Request對象 CreateIndexRequest createIndexRequest = new CreateIndexRequest("employee"); // 準(zhǔn)備請求的參數(shù)DSL語句 createIndexRequest.source(EmployeeConstants.MAPPING_TEMPLATE, XContentType.JSON); // 發(fā)送請求 restHighLevelClient.indices().create(createIndexRequest,RequestOptions.DEFAULT); } }
-
把數(shù)據(jù)庫中的數(shù)據(jù)添加到ES中
public void addAllEmployee() throws Exception{ // 數(shù)據(jù)庫全查 List<Employee> list = employeeService.list(); // 準(zhǔn)備請求 BulkRequest bulkRequest = new BulkRequest(); for(Employee e : list){ bulkRequest.add(new IndexRequest("employee").id(e.getId().toString()).source(JSON.toJSONString(e),XContentType.JSON)); } // 發(fā)送請求 restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT); }
-
業(yè)務(wù)中查詢ES,修改添加刪除數(shù)據(jù)庫同步ES
-
寫解析文章來源:http://www.zghlxwxcb.cn/news/detail-758498.html
// 解析對象方法 public void show(SearchResponse response){ // 解析響應(yīng) SearchHits searchHits = response.getHits(); long total = searchHits.getTotalHits().value; System.out.println("總計(jì)查詢數(shù)據(jù):"+total+"條"); SearchHit[] hits = searchHits.getHits(); for(SearchHit hit :hits){ /// 獲取文檔source String json = hit.getSourceAsString(); // 反序列化 HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class); System.out.println("hotelDoc="+hotelDoc); } }
注意:操作ES需要裝配核心對象RestHighLevelClient文章來源地址http://www.zghlxwxcb.cn/news/detail-758498.html
到了這里,關(guān)于搜索引擎ElasticSearch分布式搜索和分析引擎學(xué)習(xí),SpringBoot整合ES個(gè)人心得的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!