ES使用中的總結整理


最近項目中使用了ES搜索,開始時自己搭建了ES環境做測試,后面申請了公司的雲平台應用,

對接ES的過程中頗具波折,遇到了很多問題,在這里統一整理記錄下:

1,ES的9200 及 9300端口說明 

    9200作為Http協議,暴露ES RESTful接口端口號,主要用於外部通訊

    ES集群之間是通過9300進行通訊

    9300作為Tcp協議,jar之間就是通過tcp協議通訊

    對接ES請使用9200端口,9300端口不推薦使用了

 

2, master、data和client節點區別

      建議集群中設置 3台 以上的節點作為 master 節點,這些節點只負責成為主節點,維護整個集群的狀態。
  再根據數據量設置一批 data節點,這些節點只負責存儲數據,后期提供建立索引和查詢索引的服務,這樣的話如果用戶請求比較頻繁,這些節點的壓力也會比較大
  所以在集群中建議再設置一批 ingest 節點也稱之為 client 節點,這些節點只負責處理用戶請求,實現請求轉發,負載均衡等功能。

  master節點:普通服務器即可(CPU 內存 消耗一般)
  data   節點:主要消耗磁盤,內存
  client | ingest  節點:普通服務器即可(如果要進行分組聚合操作的話,建議這個節點內存也分配多一點)

 

3, 對接ES使用的jar包版本務必於ES版本一致

     對接ES時,務必要保證對接ES的jar包版本與ES版本一致,例如我用的ES版本是6.1.4,相應jar包也需要是6.1.4,pom信息如下:

     <dependency>

            <groupId>org.elasticsearch</groupId>

            <artifactId>elasticsearch</artifactId>

            <version>6.1.4</version>

        </dependency>


        <dependency>

            <groupId>org.elasticsearch.client</groupId>

            <artifactId>transport</artifactId>

            <version>6.1.4</version>

        </dependency>


        <dependency>

            <groupId>org.elasticsearch.client</groupId>

            <artifactId>elasticsearch-rest-high-level-client</artifactId>

            <version>6.1.4</version>

        </dependency>

       如果工程中也使用了netty框架,請保證使用的netty框架和對接es相關jar包中的netty包版本保持一致,

       否則在關閉client的時候,可能出現異常,例如我出現了異常“thread was not start” 之類的異常,導致整個應用掛掉。

       es的6.1.4版本相關jar包中netty版本是4.1.13.Final,項目中引用並使用了相同的jar包,如下:

       <dependency>

            <groupId>io.netty</groupId>

            <artifactId>netty-all</artifactId>

            <version>4.1.13.Final</version>

        </dependency>

 

 4,使用tcp及http方式對接es,請使用http方式對接es,tcp方式多用於es節點間通訊,不推薦做對外對接(而且在使用中感覺http方式會明顯快於tcp方式)

 4.1 tcp方式對接可以使用類 org.elasticsearch.transport.client.PreBuiltTransportClient,端口9300,可以對接master節點和client節點

      初始化方式為:

       //說明:clusterName為集群名稱,在ES6.x版本后可以不使用;client.transport.sniff表示是否嗅探(設置client.transport.sniff為true來使客戶端去嗅探整個集群的狀態,把集群中其它機器的ip地址加到客戶端中,這樣做的好處是一般你不用手動設置集群里所有集群的ip到連接客戶端,它會自動幫你添加,並且自動發現新加入集群的機器)

        Settings settings = Settings.builder().put("cluster.name",clusterName).put("client.transport.sniff", true).build();


       //esurl是es的對接信息,我這邊不同節點間使用, 分隔,例如 1.1.1.2:9300

       // getHttpHosts 用於使用ip和端口初始化一個個TransportAddress對象,最終返回一個TransportAddress 數組,

       List<String> hostNames = Arrays.asList(esurl.split(","));
       client = new PreBuiltTransportClient(settings).addTransportAddresses(getHttpHosts(hostNames));

 

 

4.2 http方式對接可以使用類 org.elasticsearch.client.RestHighLevelClient,端口9200,只可以對接client節點

     初始化方式如下:

      // esurl是es的對接信息,我這邊不同節點間使用, 分隔,例如 1.1.1.2:9300

      // getHttpHosts 用於使用ip和端口初始化一個個HttpHost對象,最終返回一個HttpHost數組,

     RestClientBuilder clientBuilder = RestClient.builder(getHttpHosts(esurl));

     RestHighLevelClient client = new RestHighLevelClient(clientBuilder);


     但是很多情況下http方式對接es需要輸入鑒權信息(用戶名及密碼),此時的對接方式如下:

     (此處摘錄自這里:https://msd.misuland.com/pd/3255817963235711680)

     // esname為用戶名, espassword為密碼

      String auth = Base64.encodeBase64String((esname + ":" + espassword).getBytes());

      RestClientBuilder clientBuilder = RestClient.builder(getHttpHosts(esurl));

      clientBuilder.setDefaultHeaders(new BasicHeader[] { new BasicHeader("Authorization", "Basic " + auth) });

      RestHighLevelClient client = new RestHighLevelClient(clientBuilder);


 5,es查詢

      需要先構建SearchSourceBuilder,然后通過client查詢結果SearchResponse,然后在通過SearchResponse獲取查詢返回值,直接上代碼如下:

        // 構建查詢請求對象

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();

        // 設置查詢條件

        queryBuilder.must(QueryBuilders.matchPhrasePrefixQuery("id", id));

        sourceBuilder.query(queryBuilder);

        // 設置排序依據,及排序方式

        sourceBuilder.sort("timestamp", SortOrder.DESC);

        // 設置起始頁及每頁大小

        sourceBuilder.from(page);
        sourceBuilder.size(size);
         // 設置查詢索引信息及類型
        SearchRequest request = new SearchRequest(INDEX_NAME);
        request.types(INDEX_TYPE);
        request.source(sourceBuilder);

       .....

        // 查詢,我這邊使用的是http方式,如果使用tcp方式請使用如下語句response = client.search(request).get(); (將其轉換為一個同步操作)

        response = client.search(request);

        if (response == null || response.getHits().getTotalHits() == 0) {

             LOGGER.error("ES查詢返回空");

        }


        // 將數據轉換為結果對象,直接將結果json字符串序列化為目標對象

       SearchHit[] hits = response.getHits().getHits();

       for (SearchHit sh : hits) {

            Info info = new Info();

            try {             

                 info= JSON.parseObject(sh.getSourceAsString(), Info.class);

            } catch (Exception e) {

                 LOGGER.error("ES結果序列化失敗:{}", sh.getSourceAsString(), e);

                 continue;

            }

            list.add(info);

        }


6,ES檢索語法

    在上面構建ES查詢請求時,我們使用一些檢索語法,用於構建查詢條件, 例如

    queryBuilder.must(QueryBuilders.matchPhrasePrefixQuery("id", id)); 這句里面的must和matchPhrasePrefixQuery即為一些檢索語法,

    這些語法很容易找到大量介紹,這里記錄一些我感覺很不錯的文章地址:

     ES 高級檢索語法:https://www.cnblogs.com/shoufeng/p/11103913.html

    es 的常用查詢語法 : https://blog.csdn.net/qingmoruoxi/article/details/77221602

    Es學習系列之一: 常見的查詢場景總結 : http://tech.dianwoda.com/2017/09/22/esxue-xi-xi-lie-zhi-chang-jian-de-cha-xun-chang-jing-zong-jie/


 

 7, ES提示某個字段不可用於排序

     此時需要修改該字段配置,使其可以排序,主要是設置fielddata屬性為true,例如

     設置time為索引可以排序字段,需要發送http請求,linux環境可以使用curl工具
     url:    ip:9200/index/_mapping/type      使用POST方法, index為索引,type為索引中數據的類型
     內容: {"properties":{"time":{"type":"text","fielddata":true}}}

     可以查看該連接, es fielddata理解 : https://www.cnblogs.com/chenmz1995/p/10198967.html


 

8,ES查詢報錯page+size > 10000

     ES默認的結果集窗口大小為10000,很多時候是不夠用的,這時候需要放大這個數值,

     設置結果窗口最大值為10000000,默認為10000某些時候太小了, 需要發送http請求,linux環境可以使用curl工具

 

     url:   ip:9200/index/_settings    使用PUT方法

     內容:{ "index" : { "max_result_window" : 10000000}}
     使用linux curl工具
     linux執行后面的命令: curl   -XPUT   http://ip:9200/index/_settings -d '{ "index" : { "max_result_window" : 100000000}}'

 

9,es中單個中文字查詢成功,但是中文詞組查詢不成功;英文單詞查詢成功,但是包含特殊字符時查詢失敗,

    這個是ES的默認分詞器及我們使用的檢索語法造成的,

    查詢單個中文能查詢出來,這里采用的是ES標准分詞器,將內容分成了一個一個的字,查詢單個中文能查詢出來,

    搜索詞組之類的等查詢不出來,因為采用的是精確查找,比如term查詢,那么相當於去找內容里是否存在“端口”這個詞,但是由於系統的默認分詞器的內容已經變成了“端”和“口”,在這種情況之下,單個字查詢可以查到的,
    想要查詢到也有辦法的,采用matchparse查詢(查詢分詞),例如我如下使用的這樣:

 

    queryBuilder.must(QueryBuilders.matchPhrasePrefixQuery("content", "端口"));
    具體也可以查看如下兩個鏈接,解釋的比較清楚

 

    es中文查詢不成功(注意看下面的回答): https://elasticsearch.cn/question/2337

    Es學習系列之一: 常見的查詢場景總結(第2節) : http://tech.dianwoda.com/2017/09/22/esxue-xi-xi-lie-zhi-chang-jian-de-cha-xun-chang-jing-zong-jie/

 

    記錄下遇到的ES相關問題,在安裝及部署時內容相對簡單, 不在多余敘述,

    安裝參考鏈接:  https://blog.csdn.net/weixin_38040473/article/details/81082968

 

10,ES使用delete_by_query刪除數據

_delete_by_query會刪除所有query語句匹配上的文檔,用法如下:

 

curl -X POST "localhost:9200/twitter/_delete_by_query" -H 'Content-Type: application/json' -d' { "query": { "match": { "name": "測試刪除" } } } ' 

查詢必須是有效的鍵值對

 

摘錄自:https://www.cnblogs.com/wangmo/p/11008928.html
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM