Spring Boot整合elasticsearch實現全文檢索


1.引入

1.1 Luence

Lucene是一個開放源代碼的全文檢索引擎工具包,但它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎,部分文本分析引擎(英文與德文兩種西方語言)。Lucene的目的是爲軟件開發人員提供一個簡單易用的工具包,以方便的在目標系統中實現全文檢索的功能,或者是以此爲基礎建立起完整的全文檢索引擎。

1.2 Solr

Solr是一個基於Luence的企業級全文搜索服務器,它童工了比Luence更加豐富的查詢語言,同時實現了可配置、可擴展,同時對索引和搜索性能進行了優化。Solr可以獨立運行,運行在Jetty、Tomcat等這些Servlet容器中。

Solr 索引的實現方法是用 POST方法向 Solr 服務器發送一個描述 Field 及其內容的 XML 文檔,Solr根據xml文檔添加、刪除、更新索引。Solr 搜索只需要使用提供的Web-service的API接口,來發送 HTTP GET 請求,然後對返回XML、json等格式的查詢結果進行解析,組織頁面佈局。

1.3 ElasticSearch

Elasticsearch是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java語言開發的,並作爲Apache許可條款下的開放源碼發佈,是一種流行的企業級搜索引擎。Elasticsearch用於雲計算中,能夠達到實時搜索,穩定,可靠,快速,安裝使用方便。官方客戶端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和許多其他語言中都是可用的。根據DB-Engines的排名顯示,Elasticsearch是最受歡迎的企業搜索引擎,其次是Apache Solr,也是基於Lucene

source: 百度百科


2. ElasticSearch安裝

2.1 雲服務器安裝

2.1.1. docker安裝
  • 搜索鏡像:如果docker search elasticsearch,或者到docker hub中進行搜索
    在這裏插入圖片描述

    如果不指定版本可能會無法進行安裝,因此,最好指定安裝的版本號。

  • 拉取鏡像

    docker pull elasticsearch:7.8.0
    
  • 運行鏡像並進行端口映射

    [root@izbp15ffbqqbe97j9dcf5dz ~]# docker images
    REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
    docker.io/elasticsearch   7.8.0               121454ddad72        6 days ago          810 MB
    [root@izbp15ffbqqbe97j9dcf5dz ~]# docker run -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -e "discovery.type=single-node" -d -p 9200:9200 -p 9300:9300 --name ES01 121454ddad72
    

    NOTE:

    • -e ES_JAVA_OPTS="-Xms512m -Xmx512m":只用指定啓動elasticsearch所需的內存大小,elasticsearch默認使用內存大小爲2G,,如果不夠則無法正常啓動。因爲我的雲服務器只有2G的內存,因此,這裏最大可用內存和最小可用內存都爲512m
    • -e "discovery.type=single-node":單節點安裝要加上,否則會報ERROR: [1] bootstrap checks failed
    • -p 9200:9200 -p 9300:9300:進行端口映射,便於遠程訪問
  • 查看是否正常運行,可以看到正常運行中

    [root@izbp15ffbqqbe97j9dcf5dz ~]# docker ps 
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                                                        NAMES
    200c0b2c5735        121454ddad72        "/tini -- /usr/loc..."   11 minutes ago      Up 10 minutes       0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp                                               ES01
    afc7a1ab33ce        95bc78c8d15d        "docker-entrypoint..."   5 hours ago         Up 5 hours          4369/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp, 15671/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp   rabbitmq
    25bd2268623c        redis               "docker-entrypoint..."   22 hours ago        Up 22 hours         0.0.0.0:6379->6379/tcp                                                                       redis
    53b9351e2a7f        mysql               "docker-entrypoint..."   29 hours ago        Up 29 hours         0.0.0.0:3306->3306/tcp, 33060/tcp                                                            wizardly_cori
    [root@izbp15ffbqqbe97j9dcf5dz ~]# 
    
2.1.2 配置安全規則

登錄雲服務器,選擇左側的安全組中的配置規則,手動添加訪問規則:
在這裏插入圖片描述

2.1.3 遠程訪問

使用ip:9200請求訪問elasticsearch,如果瀏覽器輸出如下信息,表示設置成功。

{
  "name" : "200c0b2c5735",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "Ef-bRe0lS8Sgg6s7T4y29g",
  "version" : {
    "number" : "7.8.0",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "757314695644ea9a1dc2fecd26d1a43856725e65",
    "build_date" : "2020-06-14T19:35:50.234439Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

2.2 windows安裝

2.2.1 elasticsearch安裝

首先到elasticsearch官網下載所需的壓縮包
在這裏插入圖片描述

下載結束後解壓即可用。找到bin目錄下的elasticsearch.bat,雙擊即可在後臺運行elasticsearch服務。接着在瀏覽器中輸入localhost:9200,如果能看到如下信息,說明elasticsearch正常啓動

{
  "name" : "DESKTOP-5UNDPP9",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "BmT8EaJsRZKDAfj34tmJ2A",
  "version" : {
    "number" : "7.6.1",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "aa751e09be0a5072e8570670309b1f12348f023b",
    "build_date" : "2020-02-29T00:15:25.529771Z",
    "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"
}

NOTE:

  • 安裝elasticsearch確保JDK已正確安裝

  • elasticsearch啓動時默認佔用內存大小爲1G,如果想降低所佔內存可到解壓目錄下的config/jvm.options修改其中的-Xms-Xmx參數,如:

    -Xms512m
    -Xmx1512m
    
2.2.2 head插件安裝

安裝前請確保Nodejs環境已安裝~

首先到elasticsearch-head中下載code的壓縮包,下載完畢後解壓,併到命令行窗口切換到解壓目錄。運行npm install安裝插件,最後使用npm run start命令啓動插件。

爲了連接前面安裝的elasticsearch,還需要解決跨域問題。在elasticsearch的解壓目錄下找到config/elasticsearch.yml文件,添加如下設置,並使用UTF-8格式保存。不然可能會出現閃退問題:

http.cors.enabled: true
http.cors.allow-origin: "*"

在瀏覽器中輸入localhost:9100訪問會看到如下頁面,表示啓動成功。
在這裏插入圖片描述

在Connect左側的地址欄中輸入http://127.0.0.1:9200/便可連接上elasticsearch。

我使用http://localhost:9200/無法連接成功,不知道爲什麼~

在這裏插入圖片描述

2.2.3 安裝ElasticHD

elasticsearch-head實在是不符合現代審美,所以可以選擇安裝ElasticHD,它是一個Elasticsearch 可視化DashBoard, 支持Es監控、實時搜索,Index template快捷替換修改,索引列表信息查看, SQL converts to DSL等。

這裏同樣只介紹通過雲服務器的docker安裝,首先到docker hub上搜索鏡像
在這裏插入圖片描述
通過docker pull containerize/elastichd命令拉取鏡像:

root@izbp15ffbqqbe97j9dcf5dz ~]# docker pull containerize/elastichd
Using default tag: latest
Trying to pull repository docker.io/containerize/elastichd ... 
latest: Pulling from docker.io/containerize/elastichd
43d680a959df: Pull complete 
de979aec8d7a: Pull complete 
1216b09132aa: Pull complete 
Digest: sha256:2b20e180418f3b6d0d37f2be4485244960131a9d6ce1d51ab6afbc6f40685e20
Status: Downloaded newer image for docker.io/containerize/elastichd:latest

通過docker ps查看正在運行的elasticsearch服務的名字,我這裏是ES01。然後使用docker run -p 9800:9800 -d --link ES01:demo containerize/elastichd命令安裝,最後使用docker ps查看是否啓動成功。

[root@izbp15ffbqqbe97j9dcf5dz ~]# docker run -p 9800:9800 -d --link ES01:demo containerize/elastichd
427bdf04b78c49794fc65106074476751d58e939bb43a448785354307e855412
[root@izbp15ffbqqbe97j9dcf5dz ~]# docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                                                                                        NAMES
427bdf04b78c        containerize/elastichd   "ElasticHD"              4 seconds ago       Up 3 seconds        0.0.0.0:9800->9800/tcp                                                                       clever_heisenberg
5c09fb35ce4f        e2a76963bc18             "/bin/sh -c 'node_..."   4 minutes ago       Up 4 minutes        0.0.0.0:9100->9100/tcp                                                                       ES-Head
200c0b2c5735        121454ddad72             "/tini -- /usr/loc..."   42 hours ago        Up 42 hours         0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp                                               ES01
afc7a1ab33ce        95bc78c8d15d             "docker-entrypoint..."   47 hours ago        Up 47 hours         4369/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp, 15671/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp   rabbitmq
25bd2268623c        redis                    "docker-entrypoint..."   2 days ago          Up 2 days           0.0.0.0:6379->6379/tcp                                                                       redis
53b9351e2a7f        mysql                    "docker-entrypoint..."   2 days ago          Up 2 days           0.0.0.0:3306->3306/tcp, 33060/tcp                                                            wizardly_cori

此外,爲了實現遠程訪問,還需要在服務器安全組添加安全規則
在這裏插入圖片描述
配置結束後在瀏覽器輸入http://ip:9800/,如果訪問成功會看到如下dashboard,並且可以在地址欄中輸入http://ip:9200/來連接elasticsearch服務。
在這裏插入圖片描述

2.2.4安裝kibana

Kibana是一個針對Elasticsearch的開源分析及可視化平臺,用來搜索、查看交互存儲在Elasticsearch索引中的數據。使用Kibana,可以通過各種圖表進行高級數據分析及展示。Kibana讓海量數據更容易理解。它操作簡單,基於瀏覽器的用戶界面可以快速創建儀表板(dashboard)實時顯示Elasticsearch查詢動態。設置Kibana非常簡單。無需編碼或者額外的基礎架構,幾分鐘內就可以完成Kibana安裝並啓動Elasticsearch索引監測。

首先同樣需要elasticsearch官網下載Kibana的壓縮包,下載結束後解壓即可用。雙擊運行bin/Kbina.bat即可啓動服務,在瀏覽器中輸入localhost:5601可看到如下界面,說明啓動成功。
在這裏插入圖片描述


3. Spring Boot整合ElasticSearch

3.1 環境搭建

Spring Boot整合elastissearch首先需要引入其依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.8.0</version>
</dependency>

由於Spring Boot自動引入的elasticsearch版本太低,因此,還需要更改elasticsearch的版本,使其和本地安裝的版本一致:

<elasticsearch.version>7.8.0</elasticsearch.version>

elasticsearch針對於Java提供了兩個版本的客戶端來使用它,分別是低版本的RestClient和高版本的RestHighLevelClient,這裏演示使用RestHighLevelClient。

RestClient官方文檔

RestHighLevelClient官方文檔

最後在Ioc容器中注入RestHighLevelClient,方便後續的使用。

@Configuration
public class ElasticSearchConfig {

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

3.2 索引操作

添加索引:

@Test
public void testCreateIndex() throws IOException {
    // 創建索引請求
    CreateIndexRequest request = new CreateIndexRequest("test.index");
    // 客戶端執行請求IndicesClient,請求獲得響應
    CreateIndexResponse createIndexResponse = restHighLevelClient.indices().
        create(request, RequestOptions.DEFAULT);
    System.out.println(createIndexResponse);
    // org.elasticsearch.client.indices.CreateIndexResponse@274eb315
}

執行單元測試,查看elasticsearch發現test.index已經添加成功。
在這裏插入圖片描述

查詢索引是否存在:

@Test
public void testIndexExist() throws IOException {
    GetIndexRequest request = new GetIndexRequest("test.index");
    boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
    System.out.println(exists); // true
}

執行單元測試,控制檯輸出true,表示之前添加的test.index確實存在。

刪除索引

@Test
public void testIndexDelete() throws IOException {
    DeleteIndexRequest request = new DeleteIndexRequest("test.index");
    AcknowledgedResponse delete = restHighLevelClient.indices().delete(request,
                                                                       RequestOptions.DEFAULT);
    System.out.println(delete.isAcknowledged());  // true
}

執行單元測試,查看elasticsearch發現test.index已經被刪除。
在這裏插入圖片描述

3.3 文檔操作

添加文檔

@Test
public void testAddDoc() throws IOException {
    Person person = Person.builder().name("kobe").age(18).build();
    // 創建請求
    IndexRequest request = new IndexRequest("test.index");
    request.id("1");
    request.timeout(TimeValue.timeValueMinutes(1));
    request.timeout("1s");

    // 將數據放入請求
    request.source(JSON.toJSONString(person), XContentType.JSON);

    // 客戶端發送請求 , 獲取響應的結果
    IndexResponse indexResponse = restHighLevelClient.index(request,
                                                            RequestOptions.DEFAULT);
    System.out.println(indexResponse.toString());
    System.out.println(indexResponse.status());
}

​ 執行單元測試,控制檯輸出:

IndexResponse[index=test.index,type=_doc,id=1,version=2,result=updated,seqNo=1,primaryTerm=1,shards={"total":2,"successful":1,"failed":0}]
OK

同時查看elasticsearch,發現確實添加成功。
在這裏插入圖片描述

判斷文檔是否存在

@Test
public void testFetDoc() throws IOException {
    GetRequest getRequest = new GetRequest("test.index", "1");

    getRequest.fetchSourceContext(new FetchSourceContext(false));
    getRequest.storedFields("_none_");
    boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
    System.out.println(exists);  // true
}

執行單元測試,控制檯輸出true,表示之前添加的索引是存在的。

獲取文檔信息:

void testGetDocInfo() throws IOException {
    GetRequest getRequest = new GetRequest("test.index", "1");
    GetResponse getResponse = restHighLevelClient.get(getRequest,
                                                      RequestOptions.DEFAULT);
    System.out.println(getResponse.getSourceAsString());
    System.out.println(getResponse);
}

執行單元測試,控制檯輸出:

{"age":18,"name":"kobe"}
{"_index":"test.index","_type":"_doc","_id":"1","_version":2,"_seq_no":1,
 "_primary_term":1,"found":true,"_source":{"age":18,"name":"kobe"}}

更新文檔:

@Test
void testUpdateRequest() throws IOException {
    UpdateRequest updateRequest = new UpdateRequest("test.index","1");
    updateRequest.timeout("1s");
    Person person = Person.builder().name("James").age(34).build();
    updateRequest.doc(JSON.toJSONString(person),XContentType.JSON);
    UpdateResponse updateResponse = restHighLevelClient.update(updateRequest,
                                                              RequestOptions.DEFAULT);
    System.out.println(updateResponse.status());
}

執行單元測試,觀察elasticsearch中文檔的情況,發現更新成功。
在這裏插入圖片描述

刪除文檔

@Test
void testDeleteRequest() throws IOException {
    DeleteRequest request = new DeleteRequest("test.index","1");
    request.timeout("1s");
    DeleteResponse deleteResponse = restHighLevelClient.delete(request,
                                                               RequestOptions.DEFAULT);
    System.out.println(deleteResponse.status());
}

執行單元測試後,觀察elasticsearch中索引的情況,發現此時test.index已經不在了,刪除操作執行成功。
在這裏插入圖片描述

3.4 批量操作

3.4.1 批量添加
@Test
public void testBulkRequest() throws IOException{
    BulkRequest bulkRequest = new BulkRequest();
    bulkRequest.timeout("1s");

    List<Person> list = new ArrayList<>();
    Collections.addAll(list, new Person("Kobe", 18),
                       new Person("James", 34),
                       new Person("Ball", 24));

    for (int i = 0; i < list.size(); i++) {
        bulkRequest.add(new IndexRequest("test.index").id(" " + i + 1)
                        .source(JSON.toJSONString(list.get(i)),XContentType.JSON));
    }

    BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
    System.out.println(bulkResponse.hasFailures());
}

執行單元測試,查看elasticsearch可以看到所有的文檔均添加到了test.index中。
在這裏插入圖片描述

3.4.2 批量查詢
@Test
void testSearch() throws IOException {
    SearchRequest searchRequest = new SearchRequest("test.index");
    // 構建搜索條件
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.highlighter();
    // 查詢條件,我們可以使用 QueryBuilders 工具來實現
    // QueryBuilders.termQuery 精確
    // QueryBuilders.matchAllQuery() 匹配所有
    TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("age", "18");
    //        // MatchAllQueryBuilder matchAllQueryBuilder =
    //        QueryBuilders.matchAllQuery();
    sourceBuilder.query(termQueryBuilder);
    sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
    searchRequest.source(sourceBuilder);
    SearchResponse searchResponse = restHighLevelClient.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());
    }

執行單元測試,控制檯輸出

{"fragment":true,"hits":[{"fields":{},"fragment":false,"highlightFields":{},
                          "id":" 01","matchedQueries":[],"primaryTerm":0,"rawSortValues":[],
                          "score":1.0,"seqNo":-2,"sortValues":[],"sourceAsMap":{"name":"Kobe","age":18},
                          "sourceAsString":"{\"age\":18,\"name\":\"Kobe\"}",
                          "sourceRef":{"fragment":true},"type":"_doc","version":-1}],
 "maxScore":1.0,"totalHits":{"relation":"EQUAL_TO","value":1}}

=================================

{name=Kobe, age=18}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章