天天看點

ElasticSearch 的安裝和使用

ElasticSearch安裝

聲明:jdk1.8最低要求 ElasticSearch 用戶端 ,界面工具

下載下傳

官網:www.elastic.co/cn

下載下傳位址:https://www.elastic.co/cn/downloads/elasticsearch#ga-release

ElasticSearch 的安裝和使用
​ window下安裝,解壓即可
ElasticSearch 的安裝和使用

1.熟悉目錄

  • bin 可執行檔案
  • config 配置檔案
    • log4j2.properties 日志配置檔案
    • jvm.options java 虛拟機相關的配置
    • elasticsearch.yml elasticsearch 的配置檔案
  • lib 相關jar包
  • modules 功能子產品
  • plugins 插件 ik

2.啟動:通路9200

ElasticSearch 的安裝和使用
​ 可視化界面,edge浏覽器插件,elasticSearchvue,安裝即可

kibana安裝

解壓即用

漢化:找到config目錄,将kibana.yml配置檔案最後一行的 en 改為 zh-CN

ElasticSearch 的安裝和使用

ES核心概念

​ elasticSearch 是面向文檔 關系型資料庫和 elasticSearch 客觀的對比
Relational DB ElasticSearch
資料庫(database) 索引(indices)
表(table) types
行(rows) documents
字段(columns) flieds

elasticsearch(叢集)中包含多個索引(資料庫),每個索引中包含多個清單(type),每個清單中包含多個文檔(行),,每個文檔又包含多個字段(列)

實體設計:

elasticsearch在背景把每個索引劃分為多個分片,,每份分片可以在叢集的不同伺服器間遷移

邏輯設計:

一個索引類型包含多個文檔,比如說文檔一,文檔二,當我們找一篇文檔時,可以通過這樣的方式找到它: 索引->類型->文檔ID ,通過這個組合我們就能索引到某個具體的文檔,注意:Id不必是整數,實際上它是個字元串

反向索引:

ElasticSearch 的安裝和使用

如果要搜尋含有python 标簽的文章 , 那相對于查找所有原始資料而言,查找反向索引後的資料就會快的多,隻需要檢視标簽這一欄,然後擷取相關的文章id即可,完全過濾掉所有無關的資料,提高效率

IK 分詞器插件

什麼是IK分詞器

分詞,即把一段中文或者其他的語言劃分為一個個關鍵詞,我呢吧在搜尋時會把自己的資訊進行分詞,會把資料庫或者索引庫中的資料進行分詞 , 然後進行一個比對的操作,預設的中文分詞器是把每一個字作為一關鍵詞,這是不符合要求的,我們需要安裝中文分詞器ik來解決這個問題

IK提供了兩個分詞算法: ik_smart 和 ik_max_word,其中ik_smart為最少切分,ik_max_word 為最細粒度劃分

​ ik下載下傳位址

https://github.com/medcl/elasticsearch-analysis-ik/tags

注意版本對應,以為我現在使用的ES是7.15版本的,而ik 最高隻有7.14,我嘗試下能不能使用

解壓後放在插件目錄裡

ElasticSearch 的安裝和使用

然後重新開機觀察

​ 發現失敗了,無法加載插件,啟動不成功,删除的時候記得把插件欄清空,一個目錄也不要留,不然會報錯,安裝插件隻能有一個檔案夾

然後下載下傳了ES7.14.1,成功加載插件

ElasticSearch 的安裝和使用

檢視安裝的插件清單

指令

elasticsearch-plugin list

ElasticSearch 的安裝和使用

Rest風格說明

一種軟體架構風格,而不是标準,隻是提供了一組設計原則和限制條件,它主要用于用戶端和服務端互動類的軟體

ElasticSearch 的安裝和使用
​ 基礎測試

1、使用谷歌插件測試

建立 索引(資料庫)/type(表)/id(行)

ElasticSearch 的安裝和使用

檢視

ElasticSearch 的安裝和使用

2、類型:

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

3、建立規則:

ElasticSearch 的安裝和使用

4、獲得這個規則: 可以通過GET請求擷取具體資訊

ElasticSearch 的安裝和使用

5、檢視預設的資訊

ElasticSearch 的安裝和使用
ElasticSearch 的安裝和使用

如果自己的文檔字段沒有指定,那麼es就會給我們預設配置字段類型!_doc是預設的類型

​ 虛心學習,世界上大佬很多,不要認為自己有多優秀,隻是你所在的圈子讓你以為你很優秀

擴充: 通過指令檢視elasticsearch 索引情況,通過get _cat/ 可以獲得es的更多資訊

ElasticSearch 的安裝和使用

原始的方法修改

ElasticSearch 的安裝和使用

新的方法

ElasticSearch 的安裝和使用

删除索引資料

ElasticSearch 的安裝和使用

删除索引

ElasticSearch 的安裝和使用

關于文檔的基本操作

​ 基本操作

1、添加資料

PUT /dream/user/3  ## 路徑名
{
  "name": "龍傲天",
  "age": 23,
  "desc": "永遠不要驕傲自滿",
  "tags": ["肥仔","油膩","直男"]
}

           

2、擷取資料,查詢

GET /dream/user/1   ## GET 要擷取的資料,根據資料id
GET /dream/_search?q=age:23   # 根據key進行查找,可以帶tpye也可以不帶  q代表query
# 類型為keyword不會分詞
GET /dream/_search?q=name:"沈楚幼"  #帶雙引号是精确查詢
GET /dream/_search?q=name:沈楚幼    #不帶雙引号先分詞再查詢  
           

3、更新資料

POST /dream/user/3/_update
{
	"name": "修改名字",
	"age": "修改年齡"
}
           
​ 複雜操作搜尋 select(排序,分頁,高亮,模糊查詢,精準查詢)
ElasticSearch 的安裝和使用
ElasticSearch 的安裝和使用
# 過濾出指定的字段
"_source": ["字段","字段"]
           

我們之後使用java操作es,所有的方法和對象就是這裡的key

​ sort排序
"sort": [
    {
      "字段": {
        "order": "desc" # 降序
        "order": "asc"  # 升序
      }
    }
  ],
  "from": 0, # 從第0條開始
  "size": 1, # 傳回多少條資料
           

/_search/{current}/{pagesize}

​ 布爾值查詢

must(相當于and):所有的請求都要符合

ElasticSearch 的安裝和使用

should(相當于or):滿足一個請求即可

ElasticSearch 的安裝和使用

must_not(相當于not):查詢年齡不是23歲的人

ElasticSearch 的安裝和使用

過濾filter

ElasticSearch 的安裝和使用
  • lt:less than 小于
  • lte:less than or equal to 小于等于
  • gte:greater than or equal to 大于等于
  • gt:greater than 大于
ElasticSearch 的安裝和使用
​ 精确查詢

term 查詢是直接通過反向索引指定的詞條進行精确的查詢

關于分詞:

​ term , 直接查詢精确的

​ match,會使用分詞器解析(先分析文檔,然後再通過分析的文檔進行查詢)

​ 建立規則
PUT /testdb
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "desc": {
        "type": "keyword"
      }
    }
  }
}
           

兩個類型 text 和 keyword

ElasticSearch 的安裝和使用
ElasticSearch 的安裝和使用

term :代表完全比對,也就是精确查詢,搜尋前不會再對搜尋詞進行分詞解析,直接對關鍵詞進行查找; match :代表模糊比對,搜尋前會對搜尋詞進行分詞解析,然後按分詞比對查找; 一般模糊查找的時候,多用 match ,而精确查找時可以使用 term 。

  • term查詢text字段

因為text字段會分詞,而term不分詞,是以term查詢的條件必須是text字段分詞後的某一個。

  • 成功
    ElasticSearch 的安裝和使用
  • 失敗,因為被分詞為了 學 和 無
    ElasticSearch 的安裝和使用
  • term查詢keyword字段

    term不會分詞。而keyword字段也不分詞。需要完全比對才可以。

  • 成功,錯一個字都不行
    ElasticSearch 的安裝和使用
  • 失敗
    ElasticSearch 的安裝和使用
  • match查詢text字段

match分詞,text也分詞,隻要match的分詞結果和text的分詞結果有相同的就比對。

  • match查詢keyword字段

match會被分詞,而keyword不會被分詞,match的需要跟keyword的完全比對可以。

​ 高亮
ElasticSearch 的安裝和使用

自定義高亮

ElasticSearch 的安裝和使用

內建SpringBoot

官網文檔:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.14/index.html

1、找原生的依賴

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

導入的依賴

<properties>
    <java.version>1.8</java.version>
    <repackage.classifier/>
    <spring-native.version>0.10.3</spring-native.version>
    <elasticsearch.version>7.14.1</elasticsearch.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>

    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.experimental</groupId>
        <artifactId>spring-native</artifactId>
        <version>${spring-native.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
           

2、找對象

ElasticSearch 的安裝和使用

3、分析這個類中的方法

​ 配置基本的項目

問題:一定要保證我們導入的依賴和我們自己的es版本一緻

ElasticSearch 的安裝和使用

更改版本

ElasticSearch 的安裝和使用
​ 進行測試
  • 配置
    import org.apache.http.HttpHost;
    import org.elasticsearch.client.RestClient;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * elasticSearch 用戶端配置檔案
     * @author YuanZhan
     * @date 2021/9/24 20:42
     */
    @Configuration
    public class ElasticSearchClientConfig {
        /**
         * 注入bean,托管給spring,id為restHighLevelClient
         * @return RestHighLevelClient
         */
        @Bean
        public RestHighLevelClient restHighLevelClient(){
            RestHighLevelClient client = new RestHighLevelClient(
                    RestClient.builder(
                            new HttpHost("localhost", 9200, "http")));
            return client;
        }
    }
               
  • 測試
  1. 建立索引
  2. 判斷索引是否存在
  3. 建立文檔
  4. crud文檔
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mryuan.pojo.User;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.ArrayList;

/**
 * es7.14.1  進階用戶端測試API
 */
@SpringBootTest
class Demo01EsApiApplicationTests {
    /**
     * @Autowired 通過byType 進行裝配,
     * 如果有兩個相同類型的bean,需要用用 @Qualifier 指定bean的id
     * @Resource 通過byName 進行裝配,全局唯一
     */
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    //測試索引的建立    索引名稱不能包含大寫名稱
    @Test
    void testCreateIndex() throws IOException {
        // 1. 建立索引請求 , 此處導入的是client下的包
        CreateIndexRequest request = new CreateIndexRequest("mryuan_index");

        // 2. 用戶端執行請求 IndicesClient,請求後獲得響應
        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);

        System.out.println(createIndexResponse);
    }

    // 測試擷取索引, 判斷是否存在
    @Test
    void testGetIndex() throws IOException {
        // 1. 擷取索引的請求
        GetIndexRequest request = new GetIndexRequest("mryuan_index");
        // 2. 判斷是否存在
        boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }
    // 測試删除索引
    @Test
    void testDeleteIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("mryuan_index");
        AcknowledgedResponse delete = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
        // 是否删除成功
        System.out.println(delete.isAcknowledged());
    }

    // 測試建立文檔
    @Test
    void  testCreateDocument() throws IOException {
        User user = new User("張三", 5);
        // 擷取索引請求
        IndexRequest request = new IndexRequest("mryuan_index");
        request.id("1")
               .timeout(TimeValue.timeValueSeconds(1))
                .timeout("1s");
        //将我們的資料放入請求  json   writeValueAsString  轉為json字元串
        ObjectMapper mapper = new ObjectMapper();
        request.source(mapper.writeValueAsString(user), XContentType.JSON);

        //用戶端發送請求 ,擷取響應的結果
        IndexResponse indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);
        System.out.println(indexResponse.toString());
        System.out.println(indexResponse.status());  // 對應我們指令傳回的狀态  CREATED

    }
    // 測試文檔擷取  , 判斷是否存在 get /index/_doc/1
    @Test
    void testIsExist() throws IOException {
        // 得到請求
        GetRequest request = new GetRequest("mryuan_index", "1");
        boolean exists = restHighLevelClient.exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }

    //擷取文檔的資訊
    @Test
    void testGetInfo() throws IOException {
        // 得到請求
        GetRequest request = new GetRequest("mryuan_index", "1");
        GetResponse getResponse = restHighLevelClient.get(request, RequestOptions.DEFAULT);
        System.out.println(getResponse);
        System.out.println(getResponse.getSourceAsString());
        System.out.println(getResponse.getSource());
        System.out.println(getResponse.getType());
    }
    //更新文檔資訊
    @Test
    void  testUpdateDoc() throws IOException {
        UpdateRequest request = new UpdateRequest("mryuan_index", "1");
        User user = new User("MR.yuan", 20);
        request.doc(new ObjectMapper().writeValueAsString(user),XContentType.JSON);
        UpdateResponse update = restHighLevelClient.update(request, RequestOptions.DEFAULT);
        System.out.println(update.status());
    }
    // 删除文檔資訊
    @Test
    void testDelDoc() throws IOException{
        DeleteRequest request = new DeleteRequest("mryuan_index", "1");
        DeleteResponse delete = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        System.out.println(delete.status());
    }
    // 批量插入資料
    @Test
    void testBulkRequest() throws IOException {
        // Bulk  大部分
        BulkRequest request = new BulkRequest();
        request.timeout("30s");
        ArrayList<User> users = new ArrayList<>();
        users.add(new User("yuan1",21));
        users.add(new User("yuan2",22));
        users.add(new User("yuan3",23));
        users.add(new User("yuan4",24));
        users.add(new User("yuan5",25));
        users.add(new User("yuan6",26));
        //批處理請求
        for (int i = 0; i < users.size(); i++) {
            request.add(new IndexRequest("mryuan_index")
                    .id(""+i+1)  //不設定id 會預設生成随機id
                    .source(new ObjectMapper().writeValueAsString(users.get(i)),XContentType.JSON));
        }
        BulkResponse bulk = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
        System.out.println(bulk.status());  //狀态
        System.out.println(bulk.hasFailures());  // 是否失敗,結果為false代表成功

    }
    // 查詢
    @Test
    void testSearch() throws IOException {
        SearchRequest request = new SearchRequest("mryuan_index");
        //建構搜尋條件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //建構高亮
        sourceBuilder.highlighter();
        //查詢條件  我們可以使用 QueryBuilders 工具來實作
        //QueryBuilders.termQuery  精确查詢
        //QueryBuilders.matchAllQuery 查詢所有

        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "yuan1");
      //  MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        sourceBuilder.query(termQueryBuilder);
        request.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        System.out.println(new ObjectMapper().writeValueAsString(search.getHits()));
        System.out.println("====================================");
        for (SearchHit documentFields : search.getHits().getHits()){
            System.out.println(documentFields.getSourceAsMap());
        }


    }

}
           

實戰

爬蟲

import com.mryuan.pojo.Context;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * @author YuanZhan
 * @date 2021/9/25 16:52
 */
@Component
public class HtmlParseUtil {

    public  List<Context> parseJD(String keywords) throws Exception{
        // https://search.jd.com/Search?keyword=java

        String url = "https://search.jd.com/Search?keyword="+keywords+"&enc=utf-8";
        // 解析網頁 。(Jsoup 傳回的Document 就是浏覽器的Document 對象)
        Document document = Jsoup.parse(new URL(url), 30000);
        // 可以使用所有的js方法
        Element element = document.getElementById("J_goodsList");
        Elements elements = element.getElementsByTag("li");
        ArrayList<Context> goodsList = new ArrayList<>();
        // 擷取元素中的内容,這裡的el 就是每一個li标簽
        for (Element el : elements) {
            String img = el.getElementsByTag("img").eq(0).attr("data-lazy-img");
            String price = el.getElementsByClass("p-price").eq(0).text();
            String name = el.getElementsByClass("p-name").eq(0).text();
            if (img!=null&& price!=null && name!=null){
                goodsList.add(new Context(name,img,price));

            }

        }
        return goodsList;
    }
}
           
package com.mryuan.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mryuan.pojo.Context;
import com.mryuan.util.HtmlParseUtil;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author YuanZhan
 * @date 2021/9/25 17:51
 */
@Service
public class ContentService {
    @Autowired
    private HtmlParseUtil htmlParseUtil;
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    public static void main(String[] args) throws Exception {
        new ContentService().parseContext("java");
    }
    // 1、解析的資料放入 es 索引中
    public boolean parseContext(String keywords) throws Exception {
        List<Context> list = htmlParseUtil.parseJD(keywords);
        BulkRequest bulkRequest = new BulkRequest();
        ObjectMapper mapper = new ObjectMapper();
        for (int i = 0; i <list.size(); i++) {
            bulkRequest.add(new IndexRequest("jd_goodslist")
                    .id(""+i+1).source(mapper.writeValueAsString(list.get(i)), XContentType.JSON));
        }
        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        return !bulk.hasFailures();
    }

    // 2、擷取這些資料實作搜尋功能
    public List<Map<String,Object>> searchPage(String keywords,int pageNo, int pageSize) throws IOException {
        if ((pageNo<=1)){
            pageNo = 1;
        }
        //條件搜尋
        SearchRequest searchRequest = new SearchRequest("jd_goodslist");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 分頁
        sourceBuilder.from(pageNo);
        sourceBuilder.size(pageSize);

        //精準比對
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keywords);
        sourceBuilder.query(termQueryBuilder);

        // 執行搜尋
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //解析結果
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            list.add(hit.getSourceAsMap());
        }
        return list;
    }
}
           
@RestController
public class ContentController {
    @Autowired
    private ContentService contentService;
    @GetMapping("/search/{keywords}/{pageNo}/{pageSize}")
    public List<Map<String,Object>> search(@PathVariable("keywords") String keywords,
                                           @PathVariable("pageNo")      int pageNo,
                                           @PathVariable("pageSize")    int pageSize) throws IOException {
        return contentService.searchPage(keywords, pageNo, pageSize);

    }
}