ElasticSearch Query DSL之term-level queries

本文详细介绍了Elasticsearch中的term-level查询,包括termquery、termsquery、terms_setquery、rangequery、existsquery等,强调了它们在结构化数据查询中的应用和注意事项,如字段类型限制、查询原理和性能优化。示例代码和数据演示了各种查询的用法,帮助读者理解如何在实际场景中正确使用这些查询。

概述

注:

  1. 本篇博客的内容参考自 es 7.x版本的官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.x/term-level-queries.html
  2. 博客中的所有代码示例,都已经在7.1.1版本的es集群中验证通过

term-level查询,通常使用在结构化数据的查询中,是用于精确值查找的。

所谓的结构化数据,指的是比如数值(short、integer、long、float、double等8种类型)、日期(date)、keyword、boolean、ip等类型。

跟全文检索不一样的是,term-level查询不会对输入进行分词,相反的,它会直接将输入作为精确值,去做精确匹配查找

term-level查询有如下几种类型:

  1. term query

    term query 查找 指定字段中包含了某个精确值的文档,类似于java中xxSet.contains(“xxx”)。

  2. terms query

    查找指定字段中包含 查询词根集合中 的任意一个精确值的文档。类似于java中的xxSet.contains(“xxx_1”) or xxSet.contains(“xxx_2”)。

  3. terms_set query

    查找与一个或多个指定词根相匹配的文档,而匹配的项的数量则可以由参数来指定。

  4. range query

    范围查询
    类似于如下sql

    select * from tb where price >= 10 and price < 20
    
  5. exists query

    返回在原始字段中至少有一个非空值的文档
    类似于如下sql

    select * from tb where dept_id is null
    或者
    select * from tb where dept_id is not null
    
  6. prefix query

    前缀查询
    类似于如下sql

    select * from tb where name like '苏%'
    
  7. wildcard query

    通配符查询

  8. fuzzy query

    模糊查询

  9. regexp query

    正则表达式查询

  10. type query

    指定类型查询

  11. ids query

    ids数组查询。

通俗易懂的说,上面的11中查询类型,也就是接下来要详细讲解的东西,对比到sql上,其实就是教大家在查询的时候如何去写where条件的,而且是:在面对各种数据类型的字段、或者是特定某类查询的时候,该如何正确的书写where条件。并且,本篇博客所讲的,还是where条件的最小单元——也就说,举个例子,当我们讲解到term query的时候,我们只会讲到如何去查询dept = “IT”,而不会讲到复合查询dept = “IT” or dept = “BIGDATA”


样例数据

在开始之前,为了后面的测试方便,这里我统一设置了一个名为idx-susu-test-term-query的索引,使用手动设置mappings的方式,尽可能多的插入了不同类型的字段,并且也插入了尽可能多情形的数据。

# 1.为了防止index已存在,先删除一下
DELETE idx-susu-test-term-query


# 2.手动设置index的mapping
PUT idx-susu-test-term-query/
{
   
   
  "mappings": {
   
   
    "properties": {
   
   
      "id": {
   
   
        "type": "long"
      },
      "birth": {
   
   
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
      },
      "salary": {
   
   
        "type": "float"
      },
      "detp": {
   
   
        "type": "keyword"
      },
      "skill": {
   
   
        "type": "keyword"
      },
      "skill_count": {
   
   
        "type": "short"
      },
      "skill_required_matches": {
   
   
        "type": "integer"
      },
      "addr": {
   
   
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "isBoss": {
   
   
        "type": "boolean"
      }
    }
  }
}


# 3.批量插入数据,同时刷新index
POST idx-susu-test-term-query/_bulk?refresh=true
{
   
    "index": {
   
    "_id": "1"              }}
{
   
    "id": 1, "birth": "1980-01-01 00:00:00", "salary": 40000, "dept": "BIGDATA", "skill": ["HADOOP", "JAVA", "PYTHON"],  "skill_count": 3, "skill_required_matches": 2, "addr": "北京昌平区", "isBoss": false}
{
   
    "index": {
   
    "_id": "2"              }}
{
   
    "id": 2, "birth": "1985-02-01 10:20:00", "salary": 35000, "dept": "BIGDATA", "skill": ["JAVA", "PYTHON"],            "skill_count": 2, "skill_required_matches": 2, "addr": "北京海淀区", "isBoss": false}
{
   
    "index": {
   
    "_id": "3"              }}
{
   
    "id": 3, "birth": "1989-11-01 05:00:10", "salary": 50000, "dept": "SALE",    "skill": ["PPT", "EXCEL"],              "skill_count": 2, "skill_required_matches": 1,  "addr": "北京朝阳区", "isBoss": false}
{
   
    "index": {
   
    "_id": "4"              }}
{
   
    "id": 4, "birth": "1990-01-01 11:11:11", "salary": 40000, "dept": "IT",       "skill": ["HADOOP", "PHP", "C++"],     "skill_count": 3, "skill_required_matches": 3,  "addr": "北京昌平区", "isBoss": false}
{
   
    "index": {
   
    "_id": "5"              }}
{
   
    "id": 5, "birth": "1991-06-01 12:12:12", "salary": 30000, "dept": "IT",       "skill": ["HADOOP", "JAVA", "C++"],    "skill_count": 3, "skill_required_matches": 4,  "addr": "北京昌平区", "isBoss": false}
{
   
    "index": {
   
    "_id": "6"              }}
{
   
    "id": 6, "birth": "2001-03-01 13:13:13", "salary": 40000, "dept": "IT",       "skill": null,                         "skill_count": 0, "skill_required_matches": 0,  "addr": "北京昌平区", "isBoss": false}
{
   
    "index": {
   
    "_id": "7"              }}
{
   
    "id": 7, "birth": "1995-09-01 16:16:16", "salary": 20000, "dept": "UI",       "skill": [null, "EXCEL"],          
<think>我们被要求使用Java编写Elasticsearch 8.15的DSL查询示例。根据引用[2],DSL查询是使用Elasticsearch的查询语言构建查询的方式。在Java中,我们可以使用Elasticsearch Java客户端来构建和执行查询。 步骤: 1. 引入Elasticsearch Java客户端依赖(假设使用Maven)。 2. 创建Elasticsearch客户端。 3. 构建查询请求,其中包含DSL查询。 4. 执行查询并处理结果。 注意:Elasticsearch 8.15的Java客户端使用高级REST客户端(High Level REST Client)已被弃用,推荐使用新的Java API客户端(基于Java Client API)。因此,我们将使用新的Java API客户端。 示例代码将包括: - 创建客户端 - 构建一个match查询(对查询文本分词后匹配) - 构建一个term查询(精确匹配,不分词) - 执行查询并打印结果 请确保您的环境中已经正确配置Elasticsearch 8.15,并且Java版本兼容(通常需要Java 11或更高版本)。 以下是完整示例代码:</think>### Elasticsearch 8.15 Java DSL 查询完整代码示例 以下是使用 Java 客户端在 Elasticsearch 8.15 中执行 DSL 查询的完整示例,包含常见查询类型和详细注释: ```java import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.elasticsearch._types.query_dsl.*; import co.elastic.clients.elasticsearch.core.SearchResponse; import co.elastic.clients.elasticsearch.core.search.Hit; import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.transport.ElasticsearchTransport; import co.elastic.clients.transport.rest_client.RestClientTransport; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import java.io.IOException; public class ElasticsearchDSLExample { public static void main(String[] args) throws IOException { // 1. 创建客户端连接 RestClient restClient = RestClient.builder( new HttpHost("localhost", 9200) ).build(); ElasticsearchTransport transport = new RestClientTransport( restClient, new JacksonJsonpMapper() ); ElasticsearchClient client = new ElasticsearchClient(transport); // 2. 执行各种DSL查询 executeMatchQuery(client); // 分词查询 executeTermQuery(client); // 精确查询 executePrefixQuery(client); // 前缀查询 executeWildcardQuery(client); // 通配符查询 executeBoolQuery(client); // 布尔组合查询 // 关闭连接 transport.close(); restClient.close(); } // Match查询(会对查询文本分词) private static void executeMatchQuery(ElasticsearchClient client) throws IOException { SearchResponse<Object> response = client.search(s -> s .index("products") // 索引名称 .query(q -> q .match(m -> m // Match查询 .field("name") // 字段名 .query("手机") // 查询词 ) ), Object.class ); System.out.println("\n=== Match查询结果 ==="); printResults(response); } // Term查询(精确匹配,不分词) private static void executeTermQuery(ElasticsearchClient client) throws IOException { SearchResponse<Object> response = client.search(s -> s .index("products") .query(q -> q .term(t -> t // Term查询 .field("sku") // 精确字段 .value(v -> v.stringValue("SKU12345")) ) ), Object.class ); System.out.println("\n=== Term查询结果 ==="); printResults(response); } // Prefix前缀查询(引用[1]) private static void executePrefixQuery(ElasticsearchClient client) throws IOException { SearchResponse<Object> response = client.search(s -> s .index("logs") .query(q -> q .prefix(p -> p // Prefix查询 .field("message.keyword") .value("ERR-") ) ), Object.class ); System.out.println("\n=== Prefix查询结果 ==="); printResults(response); } // Wildcard通配符查询(引用[1]) private static void executeWildcardQuery(ElasticsearchClient client) throws IOException { SearchResponse<Object> response = client.search(s -> s .index("logs") .query(q -> q .wildcard(w -> w // Wildcard查询 .field("message.keyword") .value("TIMEOUT_*") ) ), Object.class ); System.out.println("\n=== Wildcard查询结果 ==="); printResults(response); } // Bool组合查询(引用[2]) private static void executeBoolQuery(ElasticsearchClient client) throws IOException { SearchResponse<Object> response = client.search(s -> s .index("products") .query(q -> q .bool(b -> b // Bool查询 .must(m -> m // 必须满足 .range(r -> r .field("price") .gte(JsonData.of(1000)) ) ) .filter(f -> f // 过滤条件 .term(t -> t .field("category") .value("电子产品") ) ) .should(sh -> sh // 应该满足(加分项) .match(m -> m .field("tags") .query("新品") ) ) ) ), Object.class ); System.out.println("\n=== Bool组合查询结果 ==="); printResults(response); } // 打印查询结果 private static void printResults(SearchResponse<Object> response) { for (Hit<Object> hit : response.hits().hits()) { System.out.println("文档ID: " + hit.id() + ", 分数: " + hit.score()); System.out.println("源数据: " + hit.source()); System.out.println("------------------------"); } } } ``` #### 关键配置说明: 1. **依赖配置**(Maven): ```xml <dependency> <groupId>co.elastic.clients</groupId> <artifactId>elasticsearch-java</artifactId> <version>8.15.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.0</version> </dependency> ``` 2. **安全认证**(如果启用): ```java RestClient restClient = RestClient.builder( new HttpHost("localhost", 9200) ).setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider( new BasicCredentialsProvider() {{ setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("user", "password")); }} ) ).build(); ``` 3. **查询类型说明**: - **Match查询**:对文本分词后匹配(如搜索"手机"会匹配"智能手机") - **Term查询**:精确匹配未分词的字段(如SKU编码) - **Prefix/Wildcard查询**:用于日志或编码查询(引用[1])[^1] - **Bool查询**:组合多个条件的复合查询(引用[2])[^2] #### 最佳实践建议: 1. 对精确值字段(如ID、状态码)使用`.keyword`子字段 2. 生产环境需添加异常处理和连接池配置 3. 使用`Explain API`分析查询评分逻辑 4. 对高频查询使用`Prepared Queries`缓存 > 注意:Elasticsearch 8.x 默认启用安全认证,需在`elasticsearch.yml`中配置或禁用安全特性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值