ES 深入浅出系列(三)常用的ES检索功能梳理

在ES当中其实有非常多的查询功能,本文就来通过代码案例带大家梳理下不同的查询类型的具体含义分别是什么?

本文所选用的依赖内容如下:

xml 复制代码
 <dependencies>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>6.5.4</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>6.5.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>provided</scope>
        </dependency>
</dependencies>

Index插入操作

在进行案例讲解之前,我们首先需要创建一颗索引树,这里我们可以利用es-rest-high-level-client工具包的index函数去进行操作。

java 复制代码
      public static RestHighLevelClient getClient() {
        HttpHost httpHost = new HttpHost("这里写自己es的地址",9200);
        RestClientBuilder clientBuilder = RestClient.builder(httpHost);
        RestHighLevelClient client = new RestHighLevelClient(clientBuilder);
        return client;
    }
java 复制代码
 private RestHighLevelClient client = EsClient.getClient();
    private String index = "sms";
    private String type = "yidong";
    private ObjectMapper objectMapper = new ObjectMapper();

    @Test
    public void createEsData() throws IOException {
        Settings.Builder setting = Settings.builder()
                .put("number_of_shards", 3)
                .put("number_of_replicas", 1);
        SmsPO smsPO = new SmsPO();
        XContentBuilder mappings = JsonXContent.contentBuilder()
                .startObject()
                .startObject("properties")
                .startObject("mobile")
                .field("type", "text")
                .endObject()
                .startObject("corpName")
                .field("type", "text")
                .endObject()
                .startObject("smsContent")
                .field("type", "text")
                .endObject()
                .startObject("state")
                .field("type", "integer")
                .endObject()
                .startObject("operatorId")
                .field("type", "integer")
                .endObject()
                .startObject("province")
                .field("type", "text")
                .endObject()
                .startObject("ip")
                .field("type", "text")
                .endObject()
                .startObject("replyTotal")
                .field("type", "integer")
                .endObject()
                .startObject("fee")
                .field("type", "integer")
                .endObject()
                .startObject("createTime")
                .field("type", "date")
                .field("format", "yyyy-mm-dd")
                .endObject()
                .startObject("updateTime")
                .field("type", "date")
                .field("format", "yyyy-mm-dd")
                .endObject()
                .endObject()
                .endObject();
        CreateIndexRequest request = new CreateIndexRequest(index)
                .settings(setting)
                .mapping(type, mappings);
        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

    @Test
    public void testInsertData() throws IOException {
        for (int i = 0; i < 100; i++) {
            SmsPO smsPO = new SmsPO();
            smsPO.setId((long) i);
            smsPO.setMobile("15778293032");
            smsPO.setIp("127.0.0.1");
            smsPO.setFee(i + 500);
            smsPO.setProvince("BeiJin");
            smsPO.setOperatorId(i);
            smsPO.setCreateTime(new Date());
            smsPO.setUpdateTime(new Date());
            String json = objectMapper.writeValueAsString(smsPO);
            IndexRequest indexRequest = new IndexRequest(index, type, smsPO.getId().toString());
            indexRequest.source(json, XContentType.JSON);
            IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
            System.out.println(indexResponse.getResult().toString());
        }
    }

               

上述代码可以结合自己的实际环境去修改es的地址。当你执行完创建索引和插入数据两段函数之后,可以在kibana上看到对应的数据信息:

Term查询

下边是使用term查询的代码案例:

java 复制代码
  @Test
    public void testTermQuery() throws IOException {
        SearchRequest request = new SearchRequest(index);
        request.types(type);

        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.from(0);
        builder.size(5);
        builder.query(QueryBuilders.termQuery("province", "BeiJin"));
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response);
    }

所谓的term查询可以理解为是精确匹配查询的意思。

Match查询

来看代码案例:

java 复制代码
    @Test
    public void testMatchQuery() throws IOException {
        SearchRequest request = new SearchRequest(index);
        request.types(type);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.matchQuery("province", "BeiJin"));
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response.getHits().getHits().length);
    }
  

其底层其实就是将关键字进行分词处理,拆解为多个组成部分,然后分别调用多次term查询进行精确匹配。

MultiMatch查询

来看代码案例:

java 复制代码
    @Test
    public void testMultiMatchQuery() throws IOException {
        SearchRequest request = new SearchRequest(index);
        request.types(type);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //相当于是province和smsContent字段都会进行match匹配
        builder.query(QueryBuilders.multiMatchQuery("BeiJin", "province", "smsContent"));
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response.getHits().getHits().length);
    }

使用multiMatch其实底层就是多个关键字的match查询,很好理解。

MatchAll查询

该查询的目的就是将es中的所有数据都给检索出来的意思。相关代码如下:

java 复制代码
 @Test
    public void testMatchAllQuery() throws IOException {
        SearchRequest request = new SearchRequest(index);
        request.types(type);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //这里指定数量,如果不指定,默认最多10条
        builder.size(15);
        builder.query(QueryBuilders.matchAllQuery());
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        System.out.println(response.getHits().getHits().length);
    }
 

这里可以利用size参数去指定你所需要检索的数据量。

Id检索

来看代码案例:

java 复制代码
@Test
    public void testIdsQuery() throws IOException {
        SearchRequest request = new SearchRequest(index);
        request.types(type);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.idsQuery().addIds("2", "3", "4"));
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHit[] result = response.getHits().getHits();
        if (result.length > 0) {
            for (SearchHit documentFields : result) {
                System.out.println(documentFields.getSourceAsString());
            }
        }
    }

这个就非常容易理解了,和MySQL的in查询有点类似,只不过es规定的是对主键id进行in查询。

Prefix检索

java 复制代码
@Test
    public void testPrefixQuery() throws IOException {
        SearchRequest request = new SearchRequest(index);
        request.types(type);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.prefixQuery("province","Bei"));
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHit[] result = response.getHits().getHits();
        if (result.length > 0) {
            for (SearchHit documentFields : result) {
                System.out.println(documentFields.getSourceAsMap());
            }
        }
    }
 

前缀检索其实看名字就很好理解出来了,类似于mysql的 where key like 'test%' 这种含义。

Fuzzy查询

代码案例如下:

java 复制代码
 @Test
    public void testFuzzyQuery() throws IOException {
        SearchRequest request = new SearchRequest(index);
        request.types(type);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //及时出现了部分错别字,也是可以模糊识别的
        builder.query(QueryBuilders.fuzzyQuery("province","Beijin"));
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHit[] result = response.getHits().getHits();
        if (result.length > 0) {
            for (SearchHit documentFields : result) {
                System.out.println(documentFields.getSourceAsMap());
            }
        }
    }

Fuzzy可以说是一种更为智能的模糊查询,要比MySQL的like查询强。例如我们es中存储的数据,province均为BeiJin,但是如果你所传入的参数有一些误差,礼物Beijin,Fuzzy底层是可以自动帮你兼容的。

WildCard查询

先来看代码:

java 复制代码
      public void testWildCardQuery() throws IOException {
        SearchRequest request = new SearchRequest(index);
        request.types(type);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.wildcardQuery("ip","127*"));
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHit[] result = response.getHits().getHits();
        if (result.length > 0) {
            for (SearchHit documentFields : result) {
                System.out.println(documentFields.getSourceAsMap());
            }
        }

使用wildCard查询,是可以支持通配符功能的,也是一种比较灵活的查询方式。

Range查询

java 复制代码
 @Test
    public void testRangeQuery() throws IOException {
        SearchRequest request = new SearchRequest(index);
        request.types(type);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //及时出现了部分错别字,也是可以模糊识别的
        builder.query(QueryBuilders.rangeQuery("id").gt("95"));
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHit[] result = response.getHits().getHits();
        if (result.length > 0) {
            for (SearchHit documentFields : result) {
                System.out.println(documentFields.getSourceAsMap());
            }
        }
    }

range查询是一种范围查询的类型,假设我们的id是数字类型,使用range可以检索大于某个特定值的区间数据。

aggregation查询

使用aggregation是一种统计类的查询功能,来看下边这段求最大值和最小值的代码案例:

java 复制代码
  //获取最大值和最小值
    @Test
    public void testAggregationQuery() throws IOException {
        SearchRequest request = new SearchRequest(index);
        request.types(type);
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.aggregation(AggregationBuilders.extendedStats("agg").field("id"));
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        ExtendedStats agg = response.getAggregations().get("agg");
        System.out.println(agg.getMax());
        System.out.println(agg.getMin());
    }
   
相关推荐
程序媛小果7 分钟前
基于java+SpringBoot+Vue的旅游管理系统设计与实现
java·vue.js·spring boot
小屁孩大帅-杨一凡32 分钟前
java后端请求想接收多个对象入参的数据
java·开发语言
java1234_小锋39 分钟前
使用 RabbitMQ 有什么好处?
java·开发语言
TangKenny1 小时前
计算网络信号
java·算法·华为
肘击鸣的百k路1 小时前
Java 代理模式详解
java·开发语言·代理模式
城南vision1 小时前
Docker学习—Docker核心概念总结
java·学习·docker
wyh要好好学习1 小时前
SpringMVC快速上手
java·spring
尢词1 小时前
SpringMVC
java·spring·java-ee·tomcat·maven
Mr. zhihao1 小时前
享元模式在 JDK 中的应用解析
java·享元模式
茶馆大橘1 小时前
微服务系列五:避免雪崩问题的限流、隔离、熔断措施
java·jmeter·spring cloud·微服务·云原生·架构·sentinel