1. 程式人生 > 實用技巧 >關於ElasticSearch 搜尋引擎框架

關於ElasticSearch 搜尋引擎框架

一、ES 相關介紹

1.ES是一個使用Java語言並且基於Lucene編寫的搜尋引擎框架,提供了分散式的全文搜尋功能,還提供了一個統一的基於RESTful風格的Web介面,官方客戶端也對多種語言提供了相應的API。

2.Lucene:它本身就是一個搜尋引擎的底層。屬於Apache的一個頂級專案,和Solr一樣屬於核心搜尋庫

3.分散式:ES主要是為了突出自身的(橫向)高擴充套件能力

4.全文檢索:將一段詞語進行分詞,並且將分出的單個詞語統一的放到一個分詞庫中;在搜尋時,根據關鍵字去分詞庫中檢索,找到匹配的內容。(倒排索引)

5.RESTful風格的Web介面:操作ES很簡單,只需要傳送一個http請求,並且根據請求方式不同和攜帶引數的而不同,執行相應的功能。

6.應用廣泛:Github.com, Wiki,Goldman用ES維護日均近10TB的資料。

二、ElasticSearch和Solr之間的區別

(1).查詢效率:Solr查詢死資料(即資料不可改變,不可多或少)時,檢索速度優先於ES;若資料實時改變時,Solr的查詢效率將大幅降低,而ES檢索效率幾乎不變

(2).搭建叢集:Solr搭建基於Zookeeper來幫助管理,ES本身支援叢集的搭建,不需要第三方介入

(3).文件社群:Solr的社群開始十分火爆,但針對國內的文件並不多;在ES出現之後,ES的相關社群火爆程度直線上升,ES文件也相對更健全

(4).雲端計算和大資料:ES針對現在的主流技術(雲端計算和大資料)的支援和處理相對特別友好。

概念說明:

倒排索引:大致將ES服務分為兩塊(分詞庫和資料區),將存放的資料以一定的方式進行分詞,並且將分詞的內容存放到一個單獨的分詞庫中

<1>.當用戶查詢資料時,會先將使用者的查詢關鍵詞進行分詞

<2>.然後去分詞庫中匹配內容,最終得到資料的索引標識

<3>.根據索引標識去存放資料區拉取指定的資料

三、ES的安裝指引

1.安裝ES & Kibana (ES 的視覺化介面)

說明:具體下載安裝指南此文參考文獻:https://www.jianshu.com/p/05e203ea51af

(1).拉取ES映象

docker pull docker.elastic.co/elasticsearch/elasticsearch:7.5.0

(2).單節點執行ES

docker run -d --restart=always -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.5.0

(3.1).多節點執行ES

建立一個docker-compose.yml 檔案

version: '2.2'
services:
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.5.0
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es02,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic
  es02:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.5.0
    container_name: es02
    environment:
      - node.name=es02
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data02:/usr/share/elasticsearch/data
    networks:
      - elastic
  es03:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.5.0
    container_name: es03
    environment:
      - node.name=es03
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es02
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data03:/usr/share/elasticsearch/data
    networks:
      - elastic

volumes:
  data01:
    driver: local
  data02:
    driver: local
  data03:
    driver: local

networks:
  elastic:
    driver: bridge
  • 節點 es01 監聽 localhost:9200, es02 和 es03 類似
  • 資料卷 data01,data02,data03。可以持久化
  • 啟動:docker-compose up
  • 停止:docker-compose down
  • 停止並刪除資料卷:docker-compose down -v
  • 檢視節點是否啟動

  curl -X GET "localhost:9200/_cat/nodes?v&pretty"

(3.2)設定vm.max_map_count

  grep vm.max_map_count /etc/sysctl.conf

  vm.max_map_count=262144

 sysctl -w vm.max_map_count=262144

(4)安裝Kibana
docker pull docker.elastic.co/kibana/kibana:7.5.0

(5)設定kibana

docker run --link YOUR_ELASTICSEARCH_CONTAINER_NAME_OR_ID:elasticsearch -p 5601:5601 {docker-repo}:{version}
docker run -d --restart=always --link a72adb9bf49a:elasticsearch -p 5601:5601 docker.elastic.co/kibana/kibana:7.5.0

(6).拉取logstash映象
docker pull docker.elastic.co/logstash/logstash:7.5.0

(7).安裝elasticsearch外掛監控管理
docker pull mobz/elasticsearch-head:5
docker run -d -p 9100:9100 docker.io/mobz/elasticsearch-head:5
(8).安裝ik分詞器
從github專案中查詢ik分詞器:
https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.5.0/elasticsearch-analysis-ik-7.5.0.zip
<1>.先通過docker進入到es容器內部:docker exec -it 容器id bash
<2>.容器內部切換目錄並執行安裝:cd bin/
elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.5.0/elasticsearch-analysis-ik-7.5.0.zip
<3>.說明:國內網站下載比較慢,下載安裝的kibana和ik分詞器的版本都要和elasticsearch保持一致。

(9).重啟ES
通過執行docker命令重啟es: docker restart
容器id

具體實現效果如下所示:

四、ES的資料結構

1.ES服務和MySQL資料庫之間的比較:
ES服務:會搭建叢集,可以建立多個索引,每個索引可以被分成5片儲存,且每個分片都會存在至少一個備份分片;
備份分片預設不會幫助檢索資料,只有當ES檢索壓力特別大的情況下,備份分片才會幫助檢索資料;
備份分片必須存放在不同的伺服器中;
對索引進行分片,可以提高檢索資料的效率,儲存資料容量得到提升。
ES 5.x版本中,一個索引index可以建立多個type;
ES 6.x版本中,一個索引index可以建立一個type;
ES 7.x版本中,一個索引index沒有type。

ES 服務的index類似於MySQL的資料庫;
ES 服務的type類似於MySQL的table;
ES 服務的document類似於MySQL的一行資料存在多個列。

2.常見資料型別
字串型別 :
  text:一般被用於全文檢索,將當前Field進行分詞
  keyword:意旨關鍵字,當前Field不會被分詞
數值型別:
  long
  integer
  short
  byte
  double
  float
  half_float:表示精度比float小一半
  scaled_float:根據一個long和scaled來表達一個浮點型 (例如:long-345 scaled-100 即表示3.45)
時間型別:date (針對時間型別指定具體的格式)
布林型別:boolean
二進位制型別:binary (暫時支援64位編碼字符集)
範圍型別:long_range (賦值時,無序指定具體內容,只需要儲存一個範圍即可)
經緯度型別:geo_point (用來儲存經緯度)
ip型別:可以儲存ipv4或ipv6
如果對其他資料型別感興趣,可以參考如下官網進行學習
具體參考文獻:https://www.elastic.co/guide/en/elasticsearch/reference/7.5/mapping.html#field-datatypes

五、操作ES的RESTful語法

1.GET請求

(1).查詢索引資訊:http://ip:port/index

(2).查詢指定文件資訊:http://ip/port/index/type/doc_id

2.POST請求

(1).查詢指定文件 (可在請求體中新增json字串代替查詢條件):http://ip:port/index/type/_search

(2).查詢指定文件 (可在請求體中指定json字串代替修改條件):http://ip/port/index/type/doc_id/_update

3.PUT請求

(1).建立索引 (需要在請求體中指定索引資訊):http://ip:port/index

(2).建立索引時,指定索引文件儲存的屬性資訊:http://ip/port/index/type/_mappings

4.DELETE請求

(1).刪除索引 (需要在請求體中指定索引資訊):http://ip:port/index

(2).刪除指定文件資訊:http://ip/port/index/type/doc_id


五、Java連線ES
1.建立Maven工程
2.匯入依賴:

(1).elasticsearch
(2).elasticsearch 高階API
(3).junit
(4).lombok
 <dependencies>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.5.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
        </dependency>
 </dependencies>
3.建立測試類,連線es
public class ESClient {
    public static RestHighLevelClient getClient(){
        //建立HttpHost物件
        HttpHost host = new HttpHost("192.168.99.100",9200);
        //建立 RestClientBuilder
        RestClientBuilder builder = RestClient.builder(host);
        //建立 RestHighLevelClient
        RestHighLevelClient client = new RestHighLevelClient(builder);
        return client;
    }
}

六、Java操作ES索引

/**
 * @ClassName Demo2
 * @Description Java建立ES索引方式
 * @Author AlexChen
 * @Date 2020/8/23 17:17
 * @Version 5.20
 * @WebSite www.codeboy.top
 **/
public class Demo2 {

    RestHighLevelClient client = ESClient.getClient();

    String index = "person";
    String type = "man";

    @Test
    public void createIndex() throws IOException {
       //1.準備關於索引的settings
        Settings.Builder settings = Settings.builder()
                .put("number_of_shards",3)
                .put("number_of_replicas",1);
      //2.準備關於索引的結構
        XContentBuilder mappings = JsonXContent.contentBuilder()
                .startObject()
                    .startObject("properties")
                        .startObject("name")
                            .field("type","text")
                        .endObject()
                        .startObject("age")
                            .field("type","integer")
                        .endObject()
                        .startObject("birthday")
                            .field("type","date")
                            .field("format","yyyy-MM-dd")
                        .endObject()
                    .endObject()
                .endObject();

        //3.將settings 和 mappings 封裝到一個Request物件
        CreateIndexRequest request = new CreateIndexRequest(index)
                .settings(settings)
                .mapping(mappings);

        //4.通過client物件去連線ES並執行建立索引
        CreateIndexResponse resp = client.indices().create(request, RequestOptions.DEFAULT);
        //輸入resp
        System.out.println("resp>>>"+resp.toString());
    }
}
public class Demo3 {
    String index = "person";
    RestHighLevelClient client = ESClient.getClient();
    /**
     * 判斷ES指定索引是否存在
     */
    @Test
    public void exists() throws IOException {
        //1.準備request 物件
        GetIndexRequest request = new GetIndexRequest();
        request.indices(index);
        //2.通過client操作
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        //3.輸出結果
        System.out.println("返回值:"+exists);
    }
    /**
     * 刪除ES指定索引
     */
    @Test
    public void delete() throws IOException {
        //1.準備request 物件
        DeleteIndexRequest request = new DeleteIndexRequest();
        request.indices(index);
        //2.通過client操作
        AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
        //3.輸出結果
        System.out.println("返回值:"+response.isAcknowledged());
    }
}
七、Java操作文件
/**
 * @ClassName TestDoc
 * @Description Java操作文件
 * @Author AlexChen
 * @Date 2020/8/23 18:30
 * @Version 5.20
 * @WebSite www.codeboy.top
 **/
public class TestDoc {

    String index = "person";
    String type = "man";
    ObjectMapper mapper = new ObjectMapper();
    RestHighLevelClient client = ESClient.getClient();

    /**
     * 建立一個文件
     */
   @Test
   public void createPerson() throws IOException {
       //1.建立一個Json資料
       Person person = new Person(1,"張三",23,new Date());
       String json = mapper.writeValueAsString(person);
       //2.準備一個request物件
       IndexRequest request =  new IndexRequest(index,type,person.getId().toString());
       request.source(json, XContentType.JSON);
        //3.通過client物件執行新增操作
       IndexResponse resp = client.index(request, RequestOptions.DEFAULT);
       //4.輸出返回結果
       System.out.println(resp.getResult().toString());
   }

    /**
     * 更新一個文件
     */
    @Test
    public void updateDoc() throws IOException {
        //1.建立一個Map物件,指定需要修改的內容
        Map<String, Object> doc = new HashMap<String, Object>();
        doc.put("name","埃裡克森");
        String docId = "1";
        //2.建立request物件,封裝資料
        UpdateRequest request = new UpdateRequest(index,type,docId);
        request.doc(doc);
        //3.通過client物件執行
        UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
        //4.輸出返回結果
        System.out.println(update.getGetResult().toString());
    }


    /**
     * 刪除一個文件
     */
    @Test
    public void deleteDoc() throws IOException {
        //1.封裝request物件,封裝資料
        DeleteRequest request = new DeleteRequest(index,type,"1");
        //2.通過client物件執行
        DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
        //3.輸出返回結果
        System.out.println(response.getResult().toString());
    }

    /**
     * 批量新增文件
     */
    @Test
    public void batchCreateDoc() throws IOException {
        //1.準備多個json資料
        Person p1 = new Person(1,"張三",23,new Date());
        Person p2 = new Person(2,"李四",24,new Date());
        Person p3 = new Person(3,"王五",25,new Date());

        String json1 = mapper.writeValueAsString(p1);
        String json2 = mapper.writeValueAsString(p2);
        String json3 = mapper.writeValueAsString(p3);
        //2.建立request物件,將準備好的資料封裝進去

        BulkRequest request = new BulkRequest();
        request.add(new IndexRequest(index,type,p1.getId().toString()).source(json1,XContentType.JSON));
        request.add(new IndexRequest(index,type,p2.getId().toString()).source(json2,XContentType.JSON));
        request.add(new IndexRequest(index,type,p3.getId().toString()).source(json3,XContentType.JSON));
        //3.通過client執行
        BulkResponse bulk = client.bulk(request, RequestOptions.DEFAULT);
        //4.輸出返回結果
        System.out.println(bulk.toString());
    }

    /**
     * 批量刪除文件
     */
    @Test
    public void batchDeleteDoc() throws IOException {
        //1.封裝request物件
        BulkRequest request = new BulkRequest();
        request.add(new DeleteRequest(index,type,"1"));
        request.add(new DeleteRequest(index,type,"2"));
        request.add(new DeleteRequest(index,type,"3"));
        //2.通過client執行
        BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
        //3.輸出返回結果
        System.out.println(response);
    }
}