sprinboot 整合 elasticsearch实现各种查询:高亮查询、termQuery、rangeQuery、matchQuery、multiMatchQuery、分页查询
注意:本文使用 Springboot 2.4.3,、elasticsearchRestTemplate,elasticsearch使用的是 7.9.3
主要是学习使用 ElasticsearchRestTemplate 的 API,termQuery、matchQuery、rangeQuery、fuzzyQuery、matchAllQuery、multiMatchQuery、分页查询、高亮查询、排序等查询方式
/*** 查询所有文档* {"from":0,"size":10000,"query":{"match_all":{"boost":1.0}},"version":true}** @return*/@GetMapping("/matchAllQuery")public Object matchAllQuery() {NativeSearchQuery matchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchAllQuery()).build();SearchHits<Brand> searchHits = elasticsearchRestTemplate.search(matchQuery, Brand.class);return searchHits;}/*** 根据搜索关键字查询文档,搜索关键字不分词* {"from":0,"size":10000,"query":{"term":{"name":{"value":"小米","boost":1.0}}},"version":true}** @param keyword* @return*/@GetMapping("/termQuery")public Object termQuery(String keyword) {NativeSearchQuery termQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.termQuery("name", keyword)).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(termQuery, Brand.class);return search;}/*** 根据搜索关键字分词后的字段搜索文档* 关键字会分词,其实该方式等价于matchQuery* {* "from": 0,* "size": 10000,* "query": {* "common": {* "name": {* "query": "宇华华为",* "high_freq_operator": "OR",* "low_freq_operator": "OR",* "cutoff_frequency": 0.01,* "boost": 1.0* }* }* },* "version": true* }** @param keyword* @return*/@GetMapping("/commonTermsQuery")public Object commonTermsQuery(String keyword) {NativeSearchQuery commonTermsQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.commonTermsQuery("name", keyword)).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(commonTermsQuery, Brand.class);return search;}/*** 模糊匹配、接近匹配* 查询包含搜索关键字 分词后的字段 的数据* 如果在一个精确值的字段上使用它,例如数字、日期、布尔或者一个 not_analyzed 字 符串字段,那么它将会精确匹配给定的值:* {* "from": 0,* "size": 10000,* "query": {* "match": {* "name": {* "query": "中华华为",* "operator": "OR",* "prefix_length": 0,* "max_expansions": 50,* "fuzzy_transpositions": true,* "lenient": false,* "zero_terms_query": "NONE",* "auto_generate_synonyms_phrase_query": true,* "boost": 1.0* }* }* },* "version": true* }** @param keyword* @return*/@GetMapping("/matchQuery")public Object matchQuery(String keyword) {NativeSearchQuery matchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchQuery("name", keyword)).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(matchQuery, Brand.class);return search;}/*** 精确匹配查询,搜索关键字不分词 ,针对的是一个语句** @param keyword* @return*/@GetMapping("/matchPhraseQuery")public Object matchPhraseQuery(String keyword) {NativeSearchQuery matchPhraseQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchPhraseQuery("name", keyword)).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(matchPhraseQuery, Brand.class);return search;}/*** 这种精准查询满足的条件有点苛刻,有时我们想要包含 ""广东靓仔靓女"" 的文档也能够匹配 "广东靓女"。这时就要以用到 "slop" 参数来控制查询语句的灵活度。* slop 表示相隔多远时,还能匹配到。比如 搜索关键字为 广东靓女,设置slop为2,表示中间可以相隔为2,所以广东靓仔靓女这条数据也是满足条件的* {* "from": 0,* "size": 10000,* "query": {* "match_phrase": {* "name": {* "query": "广东靓女",* "slop": 2,* "zero_terms_query": "NONE",* "boost": 1.0* }* }* },* "version": true* }** @param keyword* @return*/@GetMapping("/matchPhraseQueryWithSlop")public Object matchPhraseQueryWithSlop(String keyword) {NativeSearchQuery matchPhraseQueryWithSlop = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchPhraseQuery("name", keyword).slop(2)).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(matchPhraseQueryWithSlop, Brand.class);return search;}/*** 跟matchPhrase作用大致相同,会先进行一次matchPhrase查询,然后根据分词后的最后一个词汇作为前缀模糊查询* 举个例子:查询列的值: this is a handsome boy ,查询关键字: this is a hand* es 先进行一次matchPhrase查询筛选出 含有this is a hand 的文档,然后进一步查询 以 hand 开头的数据,如 this is a handsome boy 会命中* {* "from": 0,* "size": 10000,* "query": {* "match_phrase_prefix": {* "name": {* "query": "宇华华为",* "slop": 0,* "max_expansions": 50,* "boost": 1.0* }* }* },* "version": true* }** @param keyword* @return*/@GetMapping("/matchPhrasePrefixQuery")public Object matchPhrasePrefixQuery(String keyword) {NativeSearchQuery matchPhrasePrefixQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchPhrasePrefixQuery("name", keyword)).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(matchPhrasePrefixQuery, Brand.class);return search;}/*** 根据搜索关键查询文档* 搜索关键字不分词,测出仅支持单个字去查询?这个的作用还有待验证** @param keyword* @return*/@GetMapping("/prefixQuery")public Object prefixQuery(String keyword) {NativeSearchQuery prefixQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.prefixQuery("name", keyword)).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(prefixQuery, Brand.class);return search;}/*** 从多个列中查询包含搜索关键字分词后的字段的数据:如中华华为分词后的字段大概有:中华、华为、华,会从name、brandName、subTile三个列搜索包含分词后的字段的数据* {* "from": 0,* "size": 10000,* "query": {* "multi_match": {* "query": "中华华为",* "fields": ["brandName^1.0", "name^1.0", "subTitle^1.0"],* "type": "best_fields",* "operator": "OR",* "slop": 0,* "prefix_length": 0,* "max_expansions": 50,* "zero_terms_query": "NONE",* "auto_generate_synonyms_phrase_query": true,* "fuzzy_transpositions": true,* "boost": 1.0* }* },* "version": true* }** @param keyword* @return*/@GetMapping("/multiMatchQuery")public Object multiMatchQuery(String keyword) {NativeSearchQuery multiMatchQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.multiMatchQuery(keyword, "name", "subTitle", "brandName")).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(multiMatchQuery, Brand.class);return search;}/*** 范围查询* {* "from": 0,* "size": 10000,* "query": {* "range": {* "id": {* "from": 100,* "to": null,* "include_lower": false,* "include_upper": true,* "boost": 1.0* }* }* },* "version": true* }** @param keyword* @return*/@GetMapping("/rangeQuery")public Object rangeQuery(String keyword) {NativeSearchQuery rangeQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.rangeQuery("id").gt(100)).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(rangeQuery, Brand.class);return search;}/*** 根据正则表达式查询** @param keyword* @return*/@GetMapping("/regexpQuery")public Object regexpQuery(String keyword) {NativeSearchQuery regexpQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.regexpQuery("name", "正则表达式")).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(regexpQuery, Brand.class);return search;}/*** 对多个查询的结果做去重合并* * {* "from": 0,* "size": 10000,* "query": {* "dis_max": {* "tie_breaker": 0.0,* "queries": [{* "match": {* "name": {* "query": "华",* "operator": "OR",* "prefix_length": 0,* "max_expansions": 50,* "fuzzy_transpositions": true,* "lenient": false,* "zero_terms_query": "NONE",* "auto_generate_synonyms_phrase_query": true,* "boost": 1.0* }* }* }, {* "term": {* "name": {* "value": "华为",* "boost": 1.0* }* }* }],* "boost": 0* }* },* "version": true* }** @param keyword* @return*/
@GetMapping("/disMaxQuery")public Object disMaxQuery(String keyword) {NativeSearchQuery disMaxQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.disMaxQuery().add(QueryBuilders.matchQuery("name", keyword)).add(QueryBuilders.termQuery("name", "华为"))).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(disMaxQuery, Brand.class);return search;}/*** 实际的搜索中,我们有时候会打错字,从而导致搜索不到。在Elasticsearch中,我们可以使用fuzziness属性来进行模糊查询,从而达到搜索有错别字的情形。* match查询具有“fuziness”属性。它可以被设置为“0”, “1”, “2”或“auto”。“auto”是推荐的选项,它会根据查询词的长度定义距离。* 简单的说,就是搜索关键有错别字,es可以会自动进行纠错,假如查询列的数据是周星驰,但用户搜索的时候输入的是周星迟,fuzzyQuery可以将正确的数据查询出来** 搜索华未会将华为的数据搜索出来* {* "from": 0,* "size": 10000,* "query": {* "fuzzy": {* "name": {* "value": "华未",* "fuzziness": "1",* "prefix_length": 0,* "max_expansions": 50,* "transpositions": true,* "boost": 1.0* }* }* },* "version": true* }* @param keyword* @return*/@GetMapping("/fuzzyQuery")public Object fuzzyQuery(String keyword) {// 默认是auto,修改为只允许修正一个错别字NativeSearchQuery fuzzyQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.fuzzyQuery("name", keyword).fuzziness(Fuzziness.ONE)).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(fuzzyQuery, Brand.class);return search;}/*** 轻量级字符串搜索,关键字会分词* @param keyword* @return*/@GetMapping("/queryStringQuery")public Object queryStringQuery(String keyword) {// 默认是auto,修改为只允许修正一个错别字NativeSearchQuery queryStringQuery = new NativeSearchQueryBuilder().withQuery(QueryBuilders.queryStringQuery(keyword).fuzziness(Fuzziness.ONE)).build();SearchHits<Brand> search = elasticsearchRestTemplate.search(queryStringQuery, Brand.class);return search;}
高亮查询
一、通过注解 + 查询方法的方式
1、定义一个查询方法,并贴上 @Highligh 注解,设置要高亮的字段即可
public interface SpuRepository extends ElasticsearchRepository<EsSpu,String> {@Highlight(fields = {@HighlightField(name = "name"),@HighlightField(name = "caption")})List<SearchHit<EsSpu>> findByNameOrCaption(String name, String caption);
}
2、controller层调用
@GetMapping("/highLightSearchMethod")public Object highLightSearchMethod(String keyword) {List<SearchHit<EsSpu>> byNameOrCaption = spuRepository.findByNameOrCaption(keyword, keyword);EsSpu content = null;for (SearchHit<EsSpu> esSpuSearchHit : byNameOrCaption) {// 得到对象content = esSpuSearchHit.getContent();// 只有一个高亮字段的情况List<String> highlightField = esSpuSearchHit.getHighlightField("name");if (highlightField.size() > 0) {content.setName(highlightField.get(0));}}return byNameOrCaption;}
3、响应结果
[{"index": "spu","id": "2511918707000","score": 9.83293,"sortValues": [],"content": {"id": "2511918707000","sn": "","name": "华为(HUAWEI) 华为nova2S 手机 银钻灰 {版本}","caption": "华为新品上市,华为nova4","introduction":"" "specItems": "","paraItems": "","saleNum": 0,"commentNum": 0,"isMarketable": "1","isEnableSpec": "1","isDelete": "0","status": "1"},"highlightFields": {"name": ["华为(HUAWEI) 华为nova2S 手机 银钻灰 {版本}"],"caption": ["华为新品上市,华为nova4"]},"innerHits": {},"nestedMetaData": null}]
二、 通过 ElasticsearchTemplate 方式
/*** 简易版高亮查询,这种方式在es 7.9.3已经过时*/@GetMapping("/hightLightSearch")public Object hightLightSearch() {// 分页PageRequest page = PageRequest.of(0, 5);// 设置高亮属性HighlightBuilder highlightBuilder = new HighlightBuilder();highlightBuilder.field("subTitle").preTags("").postTags("");NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(QueryBuilders.termQuery("subTitle", "小米")).withHighlightBuilder(highlightBuilder).withPageable(page).build();AggregatedPage<EsProduct> aggregatedPage = elasticsearchTemplate.queryForPage(query, EsProduct.class, new SearchResultMapper() {@Overridepublic <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {List<EsProduct> list = new ArrayList<>();// hits 才是真正保存用户数据的字段response.getTook();response.getSuccessfulShards();SearchHits hits = response.getHits();hits.getTotalHits();hits.getMaxScore();SearchHit[] hits1 = hits.getHits();EsProduct product = null;for (SearchHit hit : hits) {if (hits.totalHits <= 0) {return null;}// 处理每一个实体类型product = new EsProduct();// 这种方式为自己手动获取对象的每一个值product.setId(Long.valueOf(hit.getId()));product.setBrandName(String.valueOf(hit.getSourceAsMap().get("brandName")));product.setSubTitle(String.valueOf(hit.getSourceAsMap().get("subTitle")));Map<String, HighlightField> highlightFields = hit.getHighlightFields();// 获取高亮的字段String subTitle = highlightFields.get("subTitle").fragments()[0].toString();// 重新赋值product.setSubTitle(subTitle);list.add(product);}return new AggregatedPageImpl<>((List<T>) list);}/*** Map a single {@link SearchHit} to the given {@link Class type}.** @param searchHit must not be {@literal null}.* @param type must not be {@literal null}.* @return can be {@literal null}.* @since 3.2*/@Overridepublic <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {return null;}});return aggregatedPage;}
三、通过 ElasticsearchRestTemplate 方式
/*** @param keyword* @return*/@GetMapping("/highLightSearch")public Object highLightSearch(String keyword) {// 分页查询PageRequest page = PageRequest.of(0, 10);NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();// 设置高亮属性HighlightBuilder highlightBuilder = new HighlightBuilder();highlightBuilder.field("name");highlightBuilder.preTags("");highlightBuilder.postTags("");// HighlightBuilder.Field tags = new HighlightBuilder.Field(keyword).preTags("").postTags("");NativeSearchQuery searchQuery = queryBuilder.withQuery(QueryBuilders.matchQuery("name", keyword)).withPageable(page).withHighlightBuilder(highlightBuilder).build();// 第一个参数表示查询对象,第二个参数表示返回值,第三个参数表示要查询的索引SearchHits<EsSpu> searchHits = elasticsearchRestTemplate.search(searchQuery, EsSpu.class, IndexCoordinates.of("spu"));// elasticsearchRestTemplate.queryForPage()return searchHits;}
以上仅为个人学习总结,如有错误欢迎指出
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
