1)搭建ES服務器(單機、集群)
2)創建映射,建立實體和索引庫的映射關系,使用spring-data-elasticsearch
//ES提供的接口,可以對索引庫進行CRUD操作;T建立了和索引庫映射關系的對象、ID為T對象中的主鍵類型
ElasticsearchRepository<T,ID>
//操作索引庫
ElasticSearchTemplate
3)索引庫維護(初始化數據導入全量索引、增量索引、索引同步、定時索引(全量索引、增量索引),手動索引)
ES支持的搜索功能:
分頁查詢、精確查詢、范圍查詢、排序、分頁、高亮、分組、正則、模糊、前后綴、一值多域、一域多值
RestHighLevelClient實現搜索
//RestHighLevelClient實現搜索功能 //3個重要查詢對象SearchRequest、SearchSourceBuilder(排序、分頁、高亮、分組)、BoolQueryBuilder @Autowired private RestHighLevelClient restHighLevelClient;//准備工作,注入RestHighLevelClient public Map search(Map<String,String> searchMap) { //1.封裝查詢請求,指定“索引庫”,“類型” SearchRequest searchRequest=new SearchRequest("sku"); searchRequest.types("doc"); //設置查詢的類型 SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder(); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//布爾查詢構建器 //1.1 關鍵字搜索 if (StringUtils.isNotEmpty(searchMap.get("keywords"))){ boolQueryBuilder.must(QueryBuilders.matchQuery("name",searchMap.get("keywords")); } //1.2 靜態過濾,key固定 if(searchMap.get("category")!=null){ boolQueryBuilder.filter(QueryBuilders.termQuery("categoryName", searchMap.get("category")); } //1.4 動態過濾,key是拼接后得到 for(String key: searchMap.keySet() ){ if( key.startsWith("spec.") ){//如果是規格參數 TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery(key+".keyword", searchMap.get(key)); boolQueryBuilder.filter(termQueryBuilder); } } //1.5 數值區間過濾 if(searchMap.get("price")!=null ){ String[] price = searchMap.get("price").split("-"); if (prices.length == 2){ boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(prices[1])); } boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(prices[0])); } searchSourceBuilder.query(boolQueryBuilder); //分頁 searchSourceBuilder.from(fromIndex);//開始索引設置 searchSourceBuilder.size(pageSize);//每頁記錄數設置 //排序 searchSourceBuilder.sort("排序的域", "順序DESC|ASC"); //高亮設置 HighlightBuilder highlightBuilder=new HighlightBuilder(); highlightBuilder.field("name").preTags("<font style='color:red'>").postTags("</font>"); searchSourceBuilder.highlighter(highlightBuilder); searchRequest.source(searchSourceBuilder); //聚合查詢(商品分類) TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("sku_category").field("categoryName"); searchSourceBuilder.aggregation(termsAggregationBuilder); //2.封裝查詢結果 Map resultMap=new HashMap(); try { SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); SearchHits searchHits = searchResponse.getHits(); long totalHits = searchHits.getTotalHits(); System.out.println("記錄數:"+totalHits); SearchHit[] hits = searchHits.getHits(); //2.1 商品列表 List<Map<String,Object>> resultList=new ArrayList<Map<String, Object>>(); for(SearchHit hit:hits){ Map<String, Object> skuMap = hit.getSourceAsMap(); //name高亮處理 Map<String, HighlightField> highlightFields = hit.getHighlightFields(); HighlightField name = highlightFields.get("name"); Text[] fragments = name.fragments(); skuMap.put("name",fragments[0].toString());//用高亮的內容替換原內容 resultList.add(skuMap); } resultMap.put("rows",resultList); //2.2 商品分類列表 Aggregations aggregations = searchResponse.getAggregations(); Map<String, Aggregation> aggregationMap = aggregations.getAsMap(); Terms terms = (Terms) aggregationMap.get("sku_category"); List<? extends Terms.Bucket> buckets = terms.getBuckets(); List<String> categoryList=new ArrayList(); for( Terms.Bucket bucket:buckets ){ categoryList.add(bucket.getKeyAsString()); } resultMap.put("categoryList",categoryList); String categoryName = "";//商品分類名稱 if (searchMap.get("category") == null) { // 如果沒有分類條件 if (categoryList.size() > 0) { categoryName = categoryList.get(0);//提取分類列表的第一個分類 } } else { categoryName = searchMap.get("category");//取出參數中的分類 } //2.3 品牌列表 if(searchMap.get("brand")==null) { List<Map> brandList = brandMapper.findListByCategoryName(categoryName);//查詢品牌列表 resultMap.put("brandList", brandList); } //2.4 規格列表 List<Map> specList = specMapper.findListByCategoryName(categoryName);//規格列表 for(Map spec:specList){ String[] options = ((String) spec.get("options")).split(",");//規格選項列表 spec.put("options",options); } resultMap.put("specList",specList); //2.5 頁碼 long totalCount = searchHits.getTotalHits(); //總記錄數 long pageCount = (totalCount%pageSize==0 )?totalCount/pageSize:(totalCount/pageSize+1);//總頁數 resultMap.put("totalPages",pageCount); } catch (IOException e) { e.printStackTrace(); } return resultMap; }
ElasticsearchTemplate實現搜索
//ElasticsearchTemplate(Sring-data-ElasticSearch)實現搜索功能 @Autowired private ElasticsearchTemplate elasticsearchTemplate;//准備工作,注入ElasticsearchTemplate //(1)構建搜索條件對象NativeSearchQueryBuilder:SearchRequest+SearchSourceBuilder NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); //(2)構建多條件拼接查詢對象BoolQueryBuilder BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //(3)往多條件拼接條件對象BoolQueryBuilder中添加條件 //boolQuery.must|should|mustNot|filter(QueryBuilders.xxxx) //xxxx表示查詢類型,例如:term、match、range(正則、模糊、前后綴) ...????...//其它條件省略 //(4)多條件查詢對象BoolQueryBuilder,放入整理查詢對象中 nativeSearchQueryBuilder.withQuery(boolQuery); //(5)使用NativeSearchQueryBuilder設置分組、分頁、排序、高亮查詢條件 //nativeSearchQueryBuilder.addAggregation|withPageable|withSort|withHighlightFields ...????... //(6)獲取查詢結果“頁面展示數據結果集--->‘高亮結果集’”、“搜索面板條件數據”、“分頁數據” AggregatedPage<SkuInfo> resultInfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class, new SearchResultMapper() { @Override public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) { //1.查詢“頁面展示數據結果集--->‘高亮結果集’” List<T> list = new ArrayList<>(); //獲取查詢命中結果數據 SearchHits hits = searchResponse.getHits(); if (hits != null){ //有查詢結果 for (SearchHit hit : hits) { //SearchHit轉換為skuinfo SkuInfo skuInfo = JSON.parseObject(hit.getSourceAsString(), SkuInfo.class); //獲取高亮數據,封裝到”頁面展示數據結果集“中 Map<String, HighlightField> highlightFields = hit.getHighlightFields(); if (highlightFields != null && highlightFields.size()>0){ //替換數據 skuInfo.setName(highlightFields.get("name").getFragments()[0].toString()); } list.add((T) skuInfo); } } return new AggregatedPageImpl<T>(list,pageable,hits.getTotalHits(),searchResponse.getAggregations()); } }); //2.“搜索面板條件數據”,分組查詢結果 //封裝品牌的分組結果 StringTerms brandTerms = (StringTerms) resultInfo.getAggregation(skuBrand); List<String> brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList()); //封裝規格分組結果 StringTerms specTerms= (StringTerms) resultInfo.getAggregation(skuSpec); List<String> specList = specTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList()); //3.“分頁數據” long total = resultInfo.getTotalElements();//總條數 int totalPages = resultInfo.getTotalPages()//總頁數 //4.查詢結果封裝 Map<String,Object> resultMap = new HashMap<>(); //總記錄數 resultMap.put("total",resultInfo.getTotalElements()); //總頁數 resultMap.put("totalPages",resultInfo.getTotalPages()); //數據集合 resultMap.put("rows",resultInfo.getContent()); //搜索面板-品牌列表 resultMap.put("brandList",brandList); //搜索面板-規格列表 resultMap.put("specList",this.formartSpec(specList)); //搜索條件數據回顯(定義在controller層進行返回)