java操作es之各种高级查询

2年前 (2022) 程序员胖胖胖虎阿
300 0 0

目录

  • 一、springboot整合es
    • 1.1 pom依赖
    • 1.2 yml配置
    • 1.3 创建索引
    • 1.4 创建映射
    • 1.5 写入数据
  • 二、Java API操作ES
    • 2.1 查询全部
    • 2.2 精准匹配
    • 2.3 全文检索 MatchQuery
    • 2.4 多字段联合搜索 MultiQuery
    • 2.5 布尔查询 BoolQuery
    • 2.6 模糊匹配WildcardQuery
    • 2.7 范围匹配RangeQuery
    • 2.8 分页查询
  • 三、 过滤
  • 四、 排序
  • 五、 高亮

一、springboot整合es

本节主要内容是使用ES客户端链接: Java High Level REST Client操作ES(推荐使用该客户端)。

1.1 pom依赖

<!-- ES 客户端 -->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.9.1</version>
</dependency>
<!-- ES 版本 -->
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.9.1</version>
</dependency>

1.2 yml配置

spring:
  elasticsearch:
    rest:
      uris: 127.0.0.1:9200
      read-timeout: 60s

1.3 创建索引

address

1.4 创建映射

put http://localhost:9200/address/_mapping
{
    "properties": {
        "name": {
            "type": "text",
            "analyzer": "ik_max_word",
            "fields": {
                "keyword": {
                    "ignore_above": 256,
                    "type": "keyword"
                }
            }
        },
        "address": {
            "type": "text"
        },
        "location": {
            "type": "keyword"
        },
        "type": {
            "type": "keyword"
        },
        "geom": {
            "type": "geo_shape"
        },
        "timestamp": {
            "type": "date",
            "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
        }
    }
}

1.5 写入数据

PUT address/_docs/1000
{
  "name": "spring开发",
  "address":"北京市朝阳区和平街",
  "type":"餐饮",
  "location":"121.392496,31.245827",
  "geom": {
    "type": "point",
    "coordinates": [121.392496,31.245827]
  },
  "timestamp":"2021-04-25 19:11:35"

}

二、Java API操作ES

2.1 查询全部

// 搜索全部记录
@Test
public void testSearchAll() throws IOException, ParseException {
    // 搜索请求对象
    SearchRequest searchRequest = new SearchRequest("address");
    // 指定类型
    searchRequest.types("_doc");
    // 搜索源构建对象
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 搜索方式
    // matchAllQuery搜索全部
    searchSourceBuilder.query(QueryBuilders.matchAllQuery());
    // 设置源字段过虑,第一个参数结果集包括哪些字段,第二个参数表示结果集不包括哪些字段
    searchSourceBuilder.fetchSource(new String[]{"name","address","location","timestamp"},new String[]{});
    // 向搜索请求对象中设置搜索源
    searchRequest.source(searchSourceBuilder);
    // 执行搜索,向ES发起http请求
    SearchResponse searchResponse = client.search(searchRequest);
    // 搜索结果
    SearchHits hits = searchResponse.getHits();
    // 匹配到的总记录数
    long totalHits = hits.getTotalHits();
    // 得到匹配度高的文档
    SearchHit[] searchHits = hits.getHits();
    // 日期格式化对象
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    for(SearchHit hit:searchHits){
        // 文档的主键
        String id = hit.getId();
        // 源文档内容
        Map<String, Object> sourceAsMap = hit.getSourceAsMap();
        String name = (String) sourceAsMap.get("name");
        // 日期
        Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp"));
        System.out.println(name);
    }
 
}

2.2 精准匹配

Term Query为精确查询,在搜索时会整体匹配关键字,不再将关键字分词
DSL:

{
    "query": {
    	"term": { // 查询的方式为 term 精确查询
    		"name": "spring" // 查询的字段为 name 关键字是 spring
    	}
    }
}

java api:

// 搜索方式
// termQuery 精确查询
searchSourceBuilder.query(QueryBuilders.termQuery("name", "spring开发"));

2.3 全文检索 MatchQuery

MatchQuery 即全文检索,会对关键字进行分词后匹配词条。

query:搜索的关键字,对于英文关键字如果有多个单词则中间要用半角逗号分隔,而对于中文关键字中间可以用
逗号分隔也可以不用

operator:设置查询的结果取交集还是并集,并集用 or, 交集用 and
DSL:

{
    "query": {
        "match": {
            "description": {
                "query": "spring开发",
                "operator": "or"
            }
        }
    }
}

java api

// matchQuery全文检索
searchSourceBuilder.query(QueryBuilders.matchQuery("name", "Spring开发框架"));

2.4 多字段联合搜索 MultiQuery

MultiQuery可以通过 fields 属性来设置多个域联合查找。
DSL:

{
    "query": {
        "multi_match": {
            "query": "Spring开发框架",
            "minimum_should_match": "80%",
            "fields": ["name", "description"]
        }
    }
}

java api:

searchSourceBuilder.query(QueryBuilders.multiMatchQuery("Spring开发框架", "name", "address").minimumShouldMatch("80%"));

注:“spring开发框架”会被分为三个词:spring、开发、框架
设置"minimum_should_match": "80%"表示,三个词在文档的匹配占比为80%,即3*0.8=2.4,向下取整得2,表示至少有两个词在文档中要匹配成功。
提升boost:
在多域联合查询的时候,可以通过 boost 来设置某个域在计算得分时候的比重,比重越高的域当他符合条件时计算的得分越高,相应的该记录也更靠前。通过在 fields 中给相应的字段用 ^权重倍数来实现。
DSL:

"fields": ["name^10", "address"]

java链式编程:

searchSourceBuilder.query(QueryBuilders.multiMatchQuery("Spring开发框架", "name", "address").field("name", 10)); // 设置 name 10倍权重

2.5 布尔查询 BoolQuery

布尔查询对应于Lucene的BooleanQuery查询,实现将多个查询组合起来,有三个可选的参数:

must: 文档必须匹配must所包括的查询条件,相当于 “AND”
should: 文档应该匹配should所包括的查询条件其中的一个或多个,相当于 “OR”
must_not: 文档不能匹配must_not所包括的该查询条件,相当于“NOT”

DSL:

{
    "query": {
        "bool": { // 布尔查询
            "must": [ // 查询条件 must 表示数组中的查询方式所规定的条件都必须满足
                {
                    "multi_match": {
                        "query": "spring框架",
                        "minimum_should_match": "50%",
                        "fields": [
                            "name^10",
                            "description"
                        ]
                    }
                },
                {
                    "term": {
                        "type": "餐饮"
                    }
                }
            ]
        }
    }
}

java api:

// 首先构造多关键字查询条件
MultiMatchQueryBuilder matchQueryBuilder = QueryBuilders.multiMatchQuery("Spring开发框架", "name", "address").field("name", 10);
// 然后构造精确匹配查询条件
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("type", "201002");
// 组合两个条件,组合方式为 must 全满足
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(matchQueryBuilder);
boolQueryBuilder.must(termQueryBuilder);
// 将查询条件封装给查询对象
searchSourceBuilder.query(boolQueryBuilder);

2.6 模糊匹配WildcardQuery

对于es关键字或单词的查询我们可以借助QueryBuilders.wildcardQuery方法来操作,只需要指定es中对应的列和要查询的内容即可:

boolQueryBuilder.must(QueryBuilders.wildcardQuery("name", "spring"+"*"));

2.7 范围匹配RangeQuery

例如:

boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(60).lte(100));

2.8 分页查询

// 设置查询的起始位置,默认是0
sourceBuilder.from(0); 
// 设置查询结果的页大小,默认是10
sourceBuilder.size(10);

三、 过滤

定义过滤器查询,是在原本查询结果的基础上对数据进行筛选,因此省略了重新计算的分的步骤,效率更高。并且方便缓存。推荐尽量使用过虑器去实现查询或者过虑器和查询共同使用,过滤器在布尔查询中使用。

boolQueryBuilder.filter(QueryBuilders.termQuery("type", "餐饮"));

四、 排序

SearchSourceBuilder允许增加一或多个排序参数SortBuilder,有四个具体实现FieldSortBuilder, ScoreSortBuilder, GeoDistanceSortBuilder 和 ScriptSortBuilder。
注:支持对 keyword、date、float 等类型添加排序,text类型的字段不允许排序。

// 默认排序。根据_score倒序
sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC)); 
// 根据_id升序
sourceBuilder.sort(new FieldSortBuilder("id").order(SortOrder.ASC)); 

searchBuilder.sort("type", SortOrder.DESC);

五、 高亮

// 高亮查询
@Test
public void testHighLight() throws IOException, ParseException {
    // 搜索请求对象
    SearchRequest searchRequest = new SearchRequest("ysx_course");
    // 指定类型
    searchRequest.types("doc");
    // 搜索源构建对象
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 搜索方式
    // 首先构造多关键字查询条件
    MultiMatchQueryBuilder matchQueryBuilder = QueryBuilders.multiMatchQuery("Spring框架", "name", "address").field("name", 10);
    // 添加条件到布尔查询
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    boolQueryBuilder.must(matchQueryBuilder);
    // 将查询条件封装给查询对象
    searchSourceBuilder.query(boolQueryBuilder);
	// ***********************
    
    // 高亮查询
    HighlightBuilder highlightBuilder = new HighlightBuilder();
    highlightBuilder.preTags("<em>"); // 高亮前缀
    highlightBuilder.postTags("</em>"); // 高亮后缀
    highlightBuilder.fields().add(new HighlightBuilder.Field("name")); // 高亮字段
    // 添加高亮查询条件到搜索源
    searchSourceBuilder.highlighter(highlightBuilder);
    
	// ***********************
    
    // 设置源字段过虑,第一个参数结果集包括哪些字段,第二个参数表示结果集不包括哪些字段
    searchSourceBuilder.fetchSource(new String[]{"name","address","timestamp"},new String[]{});
    // 向搜索请求对象中设置搜索源
    searchRequest.source(searchSourceBuilder);
    // 执行搜索,向ES发起http请求
    SearchResponse searchResponse = client.search(searchRequest);
    // 搜索结果
    SearchHits hits = searchResponse.getHits();
    // 匹配到的总记录数
    long totalHits = hits.getTotalHits();
    // 得到匹配度高的文档
    SearchHit[] searchHits = hits.getHits();
    // 日期格式化对象
    soutData(searchHits);
}

根据查询结果的数据结构来获取高亮的数据,替换原有的数据:

private void soutData(SearchHit[] searchHits) throws ParseException {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    for (SearchHit hit : searchHits) {
        // 文档的主键
        String id = hit.getId();
        // 源文档内容
        Map<String, Object> sourceAsMap = hit.getSourceAsMap();
        String name = (String) sourceAsMap.get("name");
 
        // 获取高亮查询的内容。如果存在,则替换原来的name
        Map<String, HighlightField> highlightFields = hit.getHighlightFields();
        if( highlightFields != null ){
            HighlightField nameField = highlightFields.get("name");
            if(nameField!=null){
                Text[] fragments = nameField.getFragments();
                StringBuffer stringBuffer = new StringBuffer();
                for (Text str : fragments) {
                    stringBuffer.append(str.string());
                }
                name = stringBuffer.toString();
            }
        }

        String type= (String) sourceAsMap.get("type");
        // 日期
        Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp"));
        System.out.println(name);
    }
}

版权声明:程序员胖胖胖虎阿 发表于 2022年10月27日 下午11:00。
转载请注明:java操作es之各种高级查询 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...