springboot使用rest-high-level-client集成elasticsearch 7.5.1

添加pom

 <!--elasticsearch--> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.5.1</version> <exclusions> <exclusion> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> </exclusion> <exclusion> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> <version>7.5.1</version> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.5.1</version> </dependency>

yml添加配置

es: host: 192.168.1.107 port: 9200 scheme: http

初始化client

 

package com.zh.search.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ElasticConfig { @Value("${es.host}") public String host; @Value("${es.port}") public int port; @Value("${es.scheme}") public String scheme; @Bean public RestClientBuilder restClientBuilder() { return RestClient.builder(makeHttpHost()); } @Bean public RestClient restClient(){ return RestClient.builder(new HttpHost(host, port, scheme)).build(); } private HttpHost makeHttpHost() { return new HttpHost(host, port, scheme); } @Bean public RestHighLevelClient restHighLevelClient(@Autowired RestClientBuilder restClientBuilder){ return new RestHighLevelClient(restClientBuilder); } }

 

 

 

 

在resource下建立索引配置json文件,

settings.json

{ "number_of_shards": 5, "number_of_replicas": 1, "refresh_interval": "5s", "analysis": { "analyzer": { // ik細粒度 "ikSearchAnalyzer": { "type": "custom", "tokenizer": "ik_max_word", "char_filter": [ "tsconvert" ] }, // ik粗粒度分詞 "ikSmartSearchAnalyzer": { "type": "custom", "tokenizer": "ik_smart", "char_filter": [ "tsconvert" ] }, // 拼音分詞 "pinyinSimpleAnalyzer": { "tokenizer": "my_pinyin" }, // 拼音,大小寫,短語分詞 "pinyinComplexAnalyzer": { "tokenizer": "ik_smart", "filter": [ "lowercase", "pinyin_simple_filter", "edge_ngram_filter" ] }, // 大小寫轉換分詞 "lowercaseAnalyzer": { "type": "custom", "tokenizer": "keyword", "filter": "lowercase" } }, "tokenizer" : { "my_pinyin" : { "type" : "pinyin", "keep_separate_first_letter" : false, "keep_full_pinyin" : true, "keep_original" : true, "limit_first_letter_length" : 16, "lowercase" : true, "remove_duplicated_term" : true } }, "filter": { // 短語過濾 "edge_ngram_filter": { "type": "edge_ngram", "min_gram": 1, "max_gram": 50 }, // 拼音過濾 "pinyin_simple_filter": { "type": "pinyin", "first_letter": "prefix", "padding_char": " ", "limit_first_letter_length": 50, //設置first_letter結果的最大長度,默認值:16 // "keep_separate_first_letter" : false, //啓用該選項時,將保留第一個字母分開,例如:劉德華> l,d,h,默認:false,注意:查詢結果也許是太模糊,因爲長期過頻 // "keep_full_pinyin" : true, //當啓用該選項,例如:劉德華> [ liu,de,hua],默認值:true // "keep_original" : true, //啓用此選項時,也將保留原始輸入,默認值:false // "remove_duplicated_term" : true, //啓用此選項後,將刪除重複的術語以保存索引,例如:de的> de,default:false,注意:位置相關的查詢可能會受到影響 "lowercase": true //小寫非中文字母,默認值:true  } }, "char_filter": { // 簡繁體過濾 "tsconvert": { "type": "stconvert", "convert_type": "t2s" } } } }

建立索引映射文件

commodity-mapping.json

{ "properties": { "id": { "type": "integer" }, "keyword": { //text和keyword的區別text:存儲數據時候,會自動分詞,並生成索引,keyword:存儲數據時候,不會分詞創建索引 "type": "text", "analyzer": "ikSearchAnalyzer", "search_analyzer": "ikSmartSearchAnalyzer", "fields": { "pinyin": { "type": "text", "analyzer": "pinyinComplexAnalyzer", "search_analyzer": "pinyinComplexAnalyzer", "store": false, "term_vector": "with_offsets" } } }, "ownerNature": { "type": "keyword" }, "model": { "type": "keyword", //不能經過這個字段搜索 "index": false }, "weight": { "type": "integer" }, "createTime": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" } } }

採用json的方式,我以爲直觀一點spring

 

建立索引(須要注意的是,7.x後,es刪除了type,只容許存在一種type,不須要指定type的值,默認是_doc)

public void init() throws Exception { this.createIndex("commodity"); } /** * 建立索引 * @param index * @throws IOException */ public void createIndex(String index) throws IOException { //若是存在就不建立了 if(this.existsIndex(index)) { System.out.println(index+"索引庫已經存在!"); return; } // 開始建立庫 CreateIndexRequest request = new CreateIndexRequest(index); //配置文件 ClassPathResource seResource = new ClassPathResource("mapper/setting.json"); InputStream seInputStream = seResource.getInputStream(); String seJson = String.join("\n",IOUtils.readLines(seInputStream,"UTF-8")); seInputStream.close(); //映射文件 ClassPathResource mpResource = new ClassPathResource("mapper/"+index+"-mapping.json"); InputStream mpInputStream = mpResource.getInputStream(); String mpJson = String.join("\n",IOUtils.readLines(mpInputStream,"UTF-8")); mpInputStream.close(); request.settings(seJson, XContentType.JSON); request.mapping(mpJson, XContentType.JSON); //設置別名 request.alias(new Alias(index+"_alias")); CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT); boolean falg = createIndexResponse.isAcknowledged(); if(falg){ System.out.println("建立索引庫:"+index+"成功!" ); } }

判斷索引是否存在

 /** * 判斷索引是否存在 * @param index * @return * @throws IOException */ public boolean existsIndex(String index) throws IOException { GetIndexRequest getRequest = new GetIndexRequest(index); getRequest.local(false); getRequest.humanReadable(true); return restHighLevelClient.indices().exists(getRequest, RequestOptions.DEFAULT); }

 

刪除索引

 /** * 刪除索引 * @param index * @return * @throws IOException */ public boolean delIndex(String index) throws IOException { DeleteIndexRequest request = new DeleteIndexRequest(index); AcknowledgedResponse deleteIndexResponse = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT); return deleteIndexResponse.isAcknowledged(); }

 添加索引數據

 

 /** * 保存文檔 * @param kv 對應json映射裏面鍵值對,index是索引名稱 * @return * @throws IOException */ public boolean save(Kv kv) throws IOException { IndexRequest request = new IndexRequest(kv.getStr("index")) .id(kv.getStr("id")).source(kv); IndexResponse response = restHighLevelClient.index(request,RequestOptions.DEFAULT); return response.isFragment(); }

刪除索引數據

 /** * 根據id刪除文檔 * @param id * @return * @throws IOException */ public boolean delById(String id) throws IOException { DeleteRequest request = new DeleteRequest(ModuleConstants.COMMODITY.toLowerCase(),id); DeleteResponse response = restHighLevelClient.delete(request,RequestOptions.DEFAULT); return response.isFragment(); }

 

IK,拼音,短語分詞分頁搜索

 @Resource private RestHighLevelClient restHighLevelClient; @Resource private OutputChannel outputChannel; /** 分頁分詞關鍵詞查詢 * 使用QueryBuilder termQuery("key", obj) 徹底匹配 termsQuery("key", obj1, obj2..) 一次匹配多個值 matchQuery("key", Obj) 單個匹配, field不支持通配符, 前綴具高級特性 multiMatchQuery("text", "field1", "field2"..); 匹配多個字段, field有通配符忒行 matchAllQuery(); 匹配全部文件 * 組合查詢 must(QueryBuilders) : AND mustNot(QueryBuilders): NOT should: : OR percent_terms_to_match:匹配項(term)的百分比,默認是0.3 min_term_freq:一篇文檔中一個詞語至少出現次數,小於這個值的詞將被忽略,默認是2 max_query_terms:一條查詢語句中容許最多查詢詞語的個數,默認是25 stop_words:設置中止詞,匹配時會忽略中止詞 min_doc_freq:一個詞語最少在多少篇文檔中出現,小於這個值的詞會將被忽略,默認是無限制 max_doc_freq:一個詞語最多在多少篇文檔中出現,大於這個值的詞會將被忽略,默認是無限制 min_word_len:最小的詞語長度,默認是0 max_word_len:最多的詞語長度,默認無限制 boost_terms:設置詞語權重,默認是1 boost:設置查詢權重,默認是1 analyzer:設置使用的分詞器,默認是使用該字段指定的分詞器 */ @Override public Page<SearchVo> page(SearchVo searchVo){ Page<SearchVo> page = new Page(searchVo.getCurrent(),searchVo.getSize(),0); // 頁碼 try { // 構建查詢 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 索引查詢 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); //boost 設置權重 //分詞查詢 boolQueryBuilder.should(QueryBuilders.matchQuery("keyword", searchVo.getKeyword()).boost(2f)); //拼音查詢 boolQueryBuilder.should(QueryBuilders.matchPhraseQuery("keyword.pinyin", searchVo.getKeyword()).boost(2f)); //模糊查詢,不區分大小寫 // boolQueryBuilder.should(QueryBuilders.wildcardQuery("keyword", "*"+searchVo.getKeyword().toLowerCase()+"*").boost(2f)); //指定商家的性質 if(StrKit.notBlank(searchVo.getKeyword1())){ boolQueryBuilder.must(QueryBuilders.termQuery("ownerNature",searchVo.getKeyword1())); } //必須知足should其中一個條件 boolQueryBuilder.minimumShouldMatch(1); //時間範圍查詢 // boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime") // .from(DateKit.format(DateKit.getDayBegin(),"yyyy-MM-dd HH:mm:ss")) // .to(DateKit.format(DateKit.getDayBegin(),"yyyy-MM-dd HH:mm:ss")));  sourceBuilder.query(boolQueryBuilder); //設置返回的字段 // String[] includeFields = new String[] {"keyword"}; // sourceBuilder.fetchSource(includeFields,null); // 分頁設置  sourceBuilder.from(searchVo.getFrom()); sourceBuilder.size(searchVo.getSize()); // sourceBuilder.sort("id", SortOrder.ASC); // 設置排序規則 sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); SearchRequest searchRequest = new SearchRequest(searchVo.getIndex()); searchRequest.source(sourceBuilder); SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); SearchHits searchHits = response.getHits(); page.setTotal(searchHits.getTotalHits().value); List<SearchVo> list = new ArrayList<>(); for (SearchHit hit : searchHits.getHits()) { SearchVo vo = new SearchVo(); Kv kv = Kv.create().set(hit.getSourceAsMap()); vo.setId(kv.getStr("id")); vo.setKeyword(kv.getStr("keyword")); vo.setKeyword1(kv.getStr("ownerNature")); vo.setModel(kv.getStr("model")); list.add(vo); } page.setRecords(list); } catch (Exception e) { e.printStackTrace(); } //收集關鍵詞搜索記錄  searchVo.setIndex(ModuleConstants.KEYWORD.toLowerCase()); outputChannel.searchSaveOutput().send(MessageBuilder.withPayload(searchVo).build()); return page; }

 

IK,拼音,短語分詞分頁並高亮關鍵詞搜索

 @Resource private RestHighLevelClient restHighLevelClient; @Override public Page<SearchVo> pageHigh(SearchVo searchVo){ Page<SearchVo> page = new Page(searchVo.getCurrent(),searchVo.getSize(),0); // 頁碼 try { // 構建查詢 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 索引查詢 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); //boost 設置權重 //分詞查詢 boolQueryBuilder.should(QueryBuilders.matchQuery("keyword", searchVo.getKeyword()).boost(2f)); //拼音查詢 boolQueryBuilder.should(QueryBuilders.matchPhraseQuery("keyword.pinyin", searchVo.getKeyword()).boost(2f)); //模糊查詢,不區分大小寫 // boolQueryBuilder.should(QueryBuilders.wildcardQuery("keyword", "*"+searchVo.getKeyword().toLowerCase()+"*").boost(2f)); //必須知足should其中一個條件 boolQueryBuilder.minimumShouldMatch(1); //時間範圍查詢 // boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime") // .from(DateKit.format(DateKit.getDayBegin(),"yyyy-MM-dd HH:mm:ss")) // .to(DateKit.format(DateKit.getDayBegin(),"yyyy-MM-dd HH:mm:ss")));  sourceBuilder.query(boolQueryBuilder); //設置返回的字段 String[] includeFields = new String[] {"keyword"}; sourceBuilder.fetchSource(includeFields,null); // 高亮設置 List<String> highlightFieldList = new ArrayList<>(); highlightFieldList.add("keyword"); HighlightBuilder highlightBuilder = new HighlightBuilder(); for (int x = 0; x < highlightFieldList.size(); x++) { HighlightBuilder.Field field = new HighlightBuilder.Field(highlightFieldList.get(x)).preTags("<high>").postTags("</high>"); highlightBuilder.field(field); } sourceBuilder.highlighter(highlightBuilder); // 分頁設置  sourceBuilder.from(searchVo.getFrom()); sourceBuilder.size(searchVo.getSize()); // sourceBuilder.sort("id", SortOrder.ASC); // 設置排序規則 sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); //不指定索引,則搜索全部的索引 SearchRequest searchRequest = new SearchRequest(searchVo.getIndex()); searchRequest.source(sourceBuilder); SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); SearchHits searchHits = response.getHits(); page.setTotal(searchHits.getTotalHits().value); List<SearchVo> list = new ArrayList<>(); Pattern pattern = Pattern.compile("(?i)"+searchVo.getKeyword()); for (SearchHit hit : searchHits.getHits()) { SearchVo vo = new SearchVo(); Kv kv = Kv.create().set(hit.getSourceAsMap()); vo.setKeyword(kv.getStr("keyword")); //高亮字段(拼音不作高亮,拼音的高亮有問題,會將整個字符串高亮) if (!StringUtils.isEmpty(hit.getHighlightFields().get("keyword"))) { Text[] text = hit.getHighlightFields().get("keyword").getFragments(); vo.setKeyword(text[0].toString()); } //ngram短語,模糊搜索高亮,不區分大小寫直接字符串替換 String keyword = vo.getKeyword(); if(!keyword.contains("<high>")){ Matcher matcher = pattern.matcher(keyword); if(matcher.find()){ String s = matcher.group(); vo.setKeyword(keyword.replace(s,"<high>"+s+"</high>")); } } list.add(vo); } page.setRecords(list); } catch (Exception e) { e.printStackTrace(); } return page; }
相關文章
相關標籤/搜索