使用ElasticSearch 7.10.1(搜索引擎)

前言

這邊沒有提供安裝es的流程,網上能夠找一下。在個人csdn上早就有這篇文章了,我如今搬過來作了一些修改,這邊的文章較爲徹底,其中貼的代碼,大部分不是項目中的,是我練習時的代碼,少部分是貼的項目中的。若是要看此文章,仍是要建議要達到本身練習過原生語法,本身能夠搭建一個kibana去練習。新手的話,能夠去看看狂神的視頻,我的以爲能夠的。公司項目中須要用到es,當時沒用過,直接上手了es 的最新版。而後發現項目中springboot版本比較低,常常報錯,而後又小小的學習了一下,新版的es相比較舊版(目前用的包 6.4的clint)的話,有些參數必需要。其中_type 這個參數必需要的,可是我感受用處也不是很大。歡迎指定,一塊兒學習!javascript

這裏只貼了我在項目中封裝的crud,這是最開始封裝的,並無很完美,但足以拿去直接使用。後續想改,但要動不少,就暫時沒改。前端

@Slf4j
public class EsSearchUtils {
    private static RestHighLevelClient restHighLevelClient = SpringUtils.getBean(RestHighLevelClient.class);

    // 用於查詢全部根節點
    @Getter
    private static List<Integer> proTypeIdList = new ArrayList<>();

    /** * es添加的方法 * * @return */
    public static <T> boolean add(String indexName, T entity) {
        IndexRequest indexRequest = new IndexRequest(indexName);
        indexRequest.type("_doc");
        indexRequest.source(JSON.toJSONString(entity), XContentType.JSON);
        // indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
        // indexRequest.setRefreshPolicy("1s");
        // WriteRequest.RefreshPolicy refreshPolicy = indexRequest.getRefreshPolicy();
        // String value = refreshPolicy.getValue();
        // System.out.println("添加是否開啓了不延遲:"+value);
        try {
            restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /** * es更新的方法 * * @return */
    public static <T> boolean update(String indexName, T entity, String _id) {
        UpdateRequest updateRequest = new UpdateRequest(indexName, "_doc", _id);
        updateRequest.doc(JSON.toJSONString(entity), XContentType.JSON);
        // updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
        try {
            restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /** * es刪除的方法 * * @return */
    public static boolean delete(String indexName, String _id) {
        DeleteRequest deleteRequest = new DeleteRequest(indexName, "_doc", _id);
        // deleteRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
        try {
            restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /** * 封裝es查詢 操做 * * @param queryBuilder * @param searchRequest * @param sortName 須要排序的字段名 默認降序 * @param page 第幾頁 * @param pageSize 每頁的條數 */
    public static List<Map<String, Object>> searchList(QueryBuilder queryBuilder, String[] searchArray, SearchRequest searchRequest, String sortName, Integer page, Integer pageSize) {
        //構建構造者
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.timeout(TimeValue.timeValueMillis(2000));
        // 限制字段(前者是你想要什麼字段,後者是排除什麼字段)
        if (null != searchArray) {
            // searchSourceBuilder.fetchSource(searchArray, new String[]{});
            searchSourceBuilder.fetchSource(searchArray, null);
        }
        // 分頁條件
        if (!"".equals(page) && null != page) {
            if (page < 0) {
                page = 0;
            }
            searchSourceBuilder.from(page);
        }
        // 分頁條件
        if (!"".equals(pageSize) && null != pageSize) {
            if (pageSize <= 0) {
                pageSize = 1;
            }
            searchSourceBuilder.size(pageSize);
        } else {
            // 目前設置1萬條
            searchSourceBuilder.size(10000);
        }
        // 排序條件
        if (!"".equals(sortName) && null != sortName) {
            searchSourceBuilder.sort(sortName, SortOrder.DESC);
        }
        // 查詢條件
        if (null != queryBuilder) {
            searchSourceBuilder.query(queryBuilder);
        }
        //這裏是針對關鍵字高亮。其實就是將前端代碼放在了這裏
        //searchSourceBuilder.highlighter().preTags("<p class='one' style='color:red'>").postTags("</p>").field("content"); 
        SearchRequest source = searchRequest.source(searchSourceBuilder);
        SearchResponse search = null;
        try {
            search = restHighLevelClient.search(source, RequestOptions.DEFAULT);
        } catch (Exception e) {
            e.printStackTrace();
            search = null;
            log.info("============查詢出現異常=========");
        }
        List<Map<String, Object>> list = new ArrayList<>();
        if (null != search) {
            for (SearchHit hit : search.getHits().getHits()) {
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                sourceAsMap.put("_id", hit.getId());
                sourceAsMap.put("_score", hit.getScore());
                list.add(sourceAsMap);
            }
        }
        return list;
    }
}
複製代碼

1、索引的操做

直接上手api吧,ElasticSearchCommon 是本身將全部的索引名字封裝出來的,這裏是只須要一個字符串的! 提早準備的話:導入springboot封裝事後的es(也能夠不用這樣)依賴。而後寫一下配置類,配置類我貼出來,再注入一下java

依賴spring

<!--    elasticsearchs    -->
        <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> </dependency>
複製代碼

配置類sql

@Configuration
public class ElasticSearchConfig {
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost(ip,端口,"http")
                )
        );
        return client;
    }
}
複製代碼

哪些地方要使用就把RestHighLevelClient注入過來api

@Autowired
    // 1.指定方法名
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient restHighLevelClient;

複製代碼

1.新增索引

// 建立索引請求
        CreateIndexRequest createIndex = new CreateIndexRequest(ElasticSearchCommon.LG_SESSION);
        // 客戶端執行請求
        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndex, RequestOptions.DEFAULT);
複製代碼

2.刪除索引

DeleteIndexRequest deletRequest = new DeleteIndexRequest(ElasticSearchCommon.LG_SESSION);
        AcknowledgedResponse delete = restHighLevelClient.indices().delete(deletRequest, RequestOptions.DEFAULT);
複製代碼

3.查詢索引

GetIndexRequest getIndexRequest = new GetIndexRequest(ElasticSearchCommon.LG_SESSION);
        boolean exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
複製代碼

2、文檔操做(重點是查詢吧)

2.1新增文檔

2.1.1 單獨添加

IndexRequest indexRequest = new IndexRequest(ElasticSearchCommon.LG_SESSION);
        // 版本低一點的話須要加上type類型
        indexRequest.type("本身定義的類型");
        SessionEntity sessionEntity = new SessionEntity();
        sessionEntity.setId(1);
        sessionEntity.setConversationTime(getNowTime());
        sessionEntity.setMsgState(1);
        sessionEntity.setAddrImages("/addr/images");
        sessionEntity.setVipId("VIP545465");
        sessionEntity.setCustomerServerName("弟弟1號");
        IndexRequest source = indexRequest.source(JSON.toJSONString(sessionEntity), XContentType.JSON);
        IndexResponse index = restHighLevelClient.index(source, RequestOptions.DEFAULT);
        System.out.println("預留內容添加狀態:"+index.status());
複製代碼

2.1.2 批量添加

// 建立請求
        BulkRequest bulkRequest = new BulkRequest(ElasticSearchCommon.LG_SESSION);
        // 建立批量數據
        List<ProblemTypeEntity> list = new ArrayList<ProblemTypeEntity>();
        list.add(new ProblemTypeEntity(1,"111"));
        list.add(new ProblemTypeEntity(2,"222"));
        list.add(new ProblemTypeEntity(3,"333"));
        list.add(new ProblemTypeEntity(4,"444"));
        list.add(new ProblemTypeEntity(5,"555"));
        list.add(new ProblemTypeEntity(6,"666"));
        list.add(new ProblemTypeEntity(7,"777"));
        list.add(new ProblemTypeEntity(8,"888"));
        // 循環添加
        for (int i = 0;i<list.size();i++){
            bulkRequest.add(
                    new IndexRequest(ElasticSearchCommon.LG_SESSION)
							//.id(""+(i+1)) // 設置es 當中_id,不設置的話是一串字符
                            .source(JSON.toJSONString(list.get(i)),XContentType.JSON)
            );
        }

        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println("循環添加的數據狀態:"+bulk.status());

複製代碼

2.2刪除文檔

7.10版能夠這樣寫,根據其餘字段條件去查詢刪除,較新版本的刪除這我以爲是最方便的springboot

DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(ElasticSearchCommon.LG_PROBLEM);
        DeleteByQueryRequest deleteByQueryRequest1 = deleteByQueryRequest.setQuery(QueryBuilders.termQuery("id", 12));
        BulkByScrollResponse bulkByScrollResponse = restHighLevelClient.deleteByQuery(deleteByQueryRequest1, RequestOptions.DEFAULT); 
        System.out.println("刪除了幾條:"+bulkByScrollResponse.getStatus().getDeleted());
複製代碼

老一點的版本,就必須帶上_type,我全部的都叫_type,目前沒感受到用處,目前探索到,刪除只能更具_id 去查詢markdown

DeleteRequest deleteRequest = new DeleteRequest(ElasticSearchCommon.LG_PROBLEM,"_doc","_id的值");
DeleteResponse delete = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
複製代碼

2.3更改文檔

//第一種寫法
        // 建立請求
        UpdateRequest updateRequest = new UpdateRequest(ElasticSearchCommon.LG_SESSION,"這裏就是_id了");
        // 建立須要更改的數據
        UserEntity userEntity = new UserEntity("更改後的數據",28, CommonUtils.getTimeFormat());
        // 修改的數據放入請求中
        updateRequest.doc(JSON.toJSONString(userEntity),XContentType.JSON);
        // 客戶端發送請求
        UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        // 打印狀態
        System.out.println("更新狀態:"+update.status());
複製代碼

2.4查詢文檔(重點)

你要去了解QueryBuilders裏面的一些方法。session

*QueryBuilders.termQuery("key", obj) 徹底匹配,輸入的查詢內容是什麼,就會按照什麼去查詢,並不會解析查詢內容,對它分詞。
 *QueryBuilders.termsQuery("key", obj1, obj2..)   一次匹配多個值
 *QueryBuilders. matchQuery("key", Obj) 單個匹配,match查詢,會將搜索詞分詞,再與目標查詢字段進行匹配,若分詞中的任意一個詞與目標字段匹配上,則可查詢到。
 *QueryBuilders. multiMatchQuery("text", "field1", "field2"..);  匹配多個字段, field有通配符忒行
 *QueryBuilders. matchAllQuery();         匹配全部文件
 *QueryBuilders.matchPhraseQuery(「supplierName」,param);默認使用 match_phrase 時會精確匹配查詢的短語,須要所有單詞和順序要徹底同樣,標點符號除外
 *QueryBuilders.wildcardQuery(「supplierName」,"*"+param+"*") ;條件wildcard不分詞查詢,加*(至關於sql中的%)表示模糊查詢,加keyword表示查不分詞數據 
複製代碼

2.4.1

builderList 我本身寫的操做es庫的一個方法;這裏和上面在項目中使用的封裝大體同樣,這裏名字換了一下,這個就作參考就好了,要在項目中使用的話,就用上面的 隨機一個方法:elasticsearch

SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.LG_PROBLEM);
        MatchQueryBuilder should = QueryBuilders.matchQuery("content", content).operator(Operator.OR);
        List<Map<String, Object>> list = builderList(should, searchRequest,null,0,5);
        HashMap<String,Object> hashMap = new HashMap<String, Object>();
        // 分詞未搜到則 返回熱度最高的5個數據
        if (list.size() <= 0){
            List<Map<String, Object>> heatList = MostHeat();
            hashMap.put("heat","未查詢到關鍵詞,返回熱度最高的五個問題!");
            heatList.add(0,hashMap);
            return heatList;
        }
複製代碼

builderList方法:封裝的查詢 //構建構造者

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.timeout(TimeValue.timeValueMillis(1));
        // 分頁條件
        if (!"".equals(page) && null != page){
            if (page < 0 ){
                page = 0;
            }
            searchSourceBuilder.from(page);
        }
        // 分頁條件
        if (!"".equals(pageSize) && null != pageSize){
            if (pageSize <= 0 ){
                pageSize = 1;
            }
            searchSourceBuilder.size(pageSize);
        }
        // 排序條件
        if (!"".equals(sortName) && null != sortName){
            searchSourceBuilder.sort(sortName, SortOrder.DESC);
        }
        // 查詢條件
        if (null != queryBuilder ){
            searchSourceBuilder.query(queryBuilder);
        }
        //searchSourceBuilder.highlighter().preTags("<p class='one' style='color:red'>").postTags("</p>").field("content");
        SearchRequest source = searchRequest.source(searchSourceBuilder);
        SearchResponse search = restHighLevelClient.search(source, RequestOptions.DEFAULT);
        List<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : search.getHits().getHits()) {
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            sourceAsMap.put("_id",hit.getId());
            //sourceAsMap.remove("addrImages");
            list.add(sourceAsMap);
        }
複製代碼

3、附帶上kibana 中間的一些語法,能夠根據這個去嘗試一下其餘Java查詢方法

3.1多條件查詢

customerName.keyword 表明不分詞搜索,總體搜索,徹底匹配 query.term,以前網上也是說不分詞搜索,歡迎大佬指定

在這裏插入圖片描述

3.2must(必須),must_not(沒必要須),shuold(至關於or)

在這裏插入圖片描述

3.3過濾條件(gte,gt,lte,lt相信大家都知道)

在這裏插入圖片描述

3.4限制搜索條件(這裏表示從第0條開始查詢5條)、sort(numbers是字段,order不要變,desc降序,asc升序)排序

在這裏插入圖片描述

3.5高亮顯示(其實就是放了前端代碼過來)注意一下hightlight的用法,目前項目中還沒用到,大家能夠去探索

在這裏插入圖片描述

3、總結與注意

仍是得本身去摸索着玩吧,這樣踩幾個坑就知道了,後續會更新其餘的。最重要就多在查詢上面花點心思,還有不少查詢未摸索到。這裏沒寫到ik,但項目中是使用到了的。es注意的地方,他的全部增刪改都不是及時的去刷新索引中的信息的,網上有不少說在3s 有的說在1s,我這邊感受大體是1s。能夠經過參數去把延遲刷新去除,若是頻繁的操做容易破壞索引和其餘緣由,暫時還不太清楚。

相關文章
相關標籤/搜索