Elasticsearch基础操作演示总结

一、索引操作

(一)创建索引

创建Elasticsearch(ES)索引是在ES中存储和管理数据的重要操作之一。索引是用于组织和检索文档的结构化数据存储。

当创建Elasticsearch索引时,通常需要同时指定索引的设置(Settings)和映射(Mappings)。以下是一个包括索引的设置和映射的示例:

PUT /my_index
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1
  },
  "mappings": {
    "properties": {
      "field1": {
        "type": "text",
        "analyzer": "standard"
      },
      "field2": {
        "type": "keyword"
      },
      "field3": {
        "type": "integer"
      },
      "field4": {
        "type": "date",
        "format": "yyyy-MM-dd"
      }
    }
  }
}

在这个示例中:

  • settings 部分包括索引的配置设置。例如,它指定了索引将被分成5个主分片(number_of_shards),并包含1个副本(number_of_replicas)。您可以根据需求自定义这些设置。

  • mappings 部分用于定义索引中的字段映射。每个字段都包括字段名、数据类型(例如,textkeywordintegerdate等)以及可选的属性(例如,分析器、日期格式等)。

这个示例通过DSL告诉Elasticsearch如何创建索引、如何配置索引的主分片和副本,以及如何映射字段以便正确存储和检索文档数据。在创建索引后,可以将文档添加到索引中,并使用查询DSL执行各种查询操作。

假设您正在构建一个电子商务网站,需要存储和检索产品信息。可以定义产品索引的映射,包括产品名称、描述、价格等字段的数据类型和属性。

DSL示例

PUT /products
{
  "mappings": {
    "properties": {
      "product_name": {
        "type": "text",
        "analyzer": "standard"
      },
      "description": {
        "type": "text",
        "analyzer": "english"
      },
      "price": {
        "type": "float"
      },
      "category": {
        "type": "keyword"
      }
    }
  }
}

Java示例

CreateIndexRequest request = new CreateIndexRequest("products");
request.mapping("_doc", 
    "product_name", "type=text,analyzer=standard",
    "description", "type=text,analyzer=english",
    "price", "type=float",
    "category", "type=keyword"
);

CreateIndexResponse createIndexResponse = client.indices()
.create(request, RequestOptions.DEFAULT);

(二)删除索引

删除 Elasticsearch(ES)索引是一项重要的操作,可以用来清理不再需要的数据索引。要删除 Elasticsearch 索引,可以使用以下常规DSL语句:

DELETE /my_index

在上述示例中,DELETE 是 HTTP 请求方法,/my_index 是要删除的索引名称。这个简单的DSL语句会告诉 Elasticsearch 删除名为 my_index 的索引及其所有数据。

  • DELETE:这是 HTTP 请求方法,指示 Elasticsearch 执行删除操作。

  • /my_index:这是要删除的索引的名称。确保您提供的索引名称是正确的,因为删除后无法恢复。

假设您运营一个博客平台,以索引和存储博客文章。有时,您可能需要删除某些旧的博客索引以释放存储空间。要删除名为 blog_posts 的博客索引,可以使用以下DSL语句:

DELETE /blog_posts

对应java代码可以为:

DeleteIndexRequest deleteRequest = new DeleteIndexRequest("blog_posts");
AcknowledgedResponse deleteResponse = client.indices()
.delete(deleteRequest, RequestOptions.DEFAULT);

if (deleteResponse.isAcknowledged()) {
    System.out.println("博客索引删除成功");
} else {
    System.out.println("博客索引删除失败");
}

(三)关闭索引

关闭 Elasticsearch(ES)索引是一种操作,可以将索引设置为不可用状态,以减少资源消耗,但仍然保留索引定义和数据。要关闭 Elasticsearch 索引,可以使用以下常规DSL语句:

POST /my_index/_close

在上述示例中,POST 是 HTTP 请求方法,/my_index/_close 是要关闭的索引的路径。这个DSL语句会告诉 Elasticsearch 关闭名为 my_index 的索引。

  • POST:这是 HTTP 请求方法,用于执行关闭操作。

  • /my_index/_close:这是要关闭的索引的路径。请注意,关闭操作是通过向索引的特殊路径发送 POST 请求来执行的。

假设您运营一个文档管理系统,使用 Elasticsearch 来存储文档索引。有时,您可能需要关闭某个索引以释放资源,但仍然保留索引定义,以便以后再次启用。要关闭名为 document_index 的文档索引,可以使用以下DSL语句:

POST /document_index/_close

对应java代码可写为:

CloseIndexRequest closeIndexRequest = new CloseIndexRequest("document_index");
AcknowledgeResponse closeResponse = client.indices()
.close(closeIndexRequest, RequestOptions.DEFAULT);

if (closeResponse.isAcknowledged()) {
    System.out.println("索引关闭成功");
} else {
    System.out.println("索引关闭失败");
}

(四)打开索引

打开 Elasticsearch(ES)索引是一种操作,可以将先前关闭的索引重新设置为可用状态,以便进行搜索和写入操作。要打开 Elasticsearch 索引,可以使用以下常规DSL语句:

POST /my_index/_open

在上述示例中,POST 是 HTTP 请求方法,/my_index/_open 是要打开的索引的路径。这个DSL语句会告诉 Elasticsearch 打开名为 my_index 的索引。

  • POST:这是 HTTP 请求方法,用于执行打开操作。

  • /my_index/_open:这是要打开的索引的路径。请注意,打开操作是通过向索引的特殊路径发送 POST 请求来执行的。

假设您运营一个文档管理系统,使用 Elasticsearch 存储文档索引。有时,可能需要重新打开以前关闭的索引,以便用户可以再次访问和搜索文档。要重新打开名为 document_index 的文档索引,可以使用以下DSL语句:

POST /document_index/_open

对应java代码可写为:

OpenIndexRequest openIndexRequest = new OpenIndexRequest("document_index");
OpenIndexResponse openResponse = client.indices()
.open(openIndexRequest, RequestOptions.DEFAULT);

if (openResponse.isAcknowledged()) {
    System.out.println("索引打开成功");
} else {
    System.out.println("索引打开失败");
}

这个示例适用于文档管理系统,如果先前关闭的文档索引需要再次被用户访问和搜索,那么重新打开索引是一个有效的操作。这可以用于重新激活不再频繁使用但仍然有价值的索引。

总之,重新打开 Elasticsearch 索引是一种管理索引可用性的操作,可用于恢复先前关闭的索引以进行搜索和写入操作。根据具体需求,可以使用DSL或 Elasticsearch 客户端库来执行此操作。请注意,重新打开索引后,用户可以再次对其执行搜索和写入操作。

(五)索引别名

Elasticsearch索引别名是一项强大的功能,用于管理索引的命名别称,以提供更灵活的索引管理和查询。

用法分析

  1. 索引版本控制:索引别名可以用于实现索引版本控制。当您需要更新索引时,可以创建一个新的索引,并将别名指向新索引,而不需要更改应用程序中的查询。这使得您可以平滑地进行索引维护和升级。

  2. 切换索引:别名允许您在不中断查询的情况下切换索引。这对于在索引上执行滚动更新、备份、恢复和数据迁移等操作时非常有用。

  3. 多索引查询:您可以将一个别名关联到多个索引上,从而实现多索引查询。这对于执行跨多个索引的复杂查询非常有用,而无需明确指定每个索引的名称。

  4. 索引分割与归档:索引别名可以用于将数据分割到不同的索引中,以便更好地管理大量数据。例如,您可以创建每天一个新索引,然后使用别名汇总它们,之后可以轻松地归档或删除旧的索引。

  5. 索引安全性:通过使用别名,您可以在后端更改实际索引名称,从而增强索引的安全性。外部用户不需要知道真正的索引名称。

注意事项

  1. 别名不是索引:索引别名本身不存储数据,它只是一个指向一个或多个索引的符号引用。因此,创建和删除别名是低成本的操作。

  2. 别名更改是原子操作:将别名切换到新索引或删除别名是原子操作,这意味着它们不会中断正在执行的查询。但请注意,将别名从一个索引切换到另一个索引后,新的索引可能需要时间来完全加载数据。

  3. 谨慎使用别名:虽然索引别名非常强大,但也需要谨慎使用。不恰当的别名管理可能会导致混淆和错误。

  4. 版本控制的注意事项:当使用别名进行索引版本控制时,需要确保新索引的映射与旧索引的映射兼容。否则,应用程序可能会出现问题。

  5. 查询性能:尽管别名可以提高查询的灵活性,但跨多个索引执行查询可能会增加性能开销。请谨慎设计查询以优化性能。

总之,索引别名是 Elasticsearch 灵活索引管理的有力工具,但需要仔细规划和使用。它们可以用于索引版本控制、查询优化和索引维护,但需要谨慎管理以确保正确性和性能。

应用案例举例和具体案例展示

案例举例-版本控制:

  • 案例:假设您的应用程序存储用户生成的文档,并且您需要定期更新文档结构,例如添加新字段或更改映射。同时,您希望用户可以持续访问其旧文档,并逐渐迁移到新文档结构。
  • 解决方案:您可以为每个文档类型创建一个别名,例如"v1"和"v2",每个别名指向不同版本的索引。当您需要更新索引时,创建一个新的索引版本,并将别名指向新索引。这样,新文档将被写入新索引,而用户仍然可以查询旧索引以访问旧文档。逐渐迁移用户到新索引后,您可以删除旧索引。

案例举例-多索引查询:

  • 案例:您的应用程序需要执行复杂的查询,涉及多个索引。例如,在电子商务平台上,您可能有一个索引用于存储产品信息,另一个用于存储订单信息,而查询需要同时涵盖这两个索引。
  • 解决方案:创建一个别名,例如"ecommerce_data",将其指向产品和订单索引。然后,您的查询可以针对"ecommerce_data"别名执行,而无需明确指定每个索引的名称。这使得查询更简单且更具可维护性。

案例举例​​​​​​​-索引分割与归档:

  • 案例:您的应用程序需要存储大量数据,例如日志数据,但不希望将所有数据存储在一个巨大的索引中。您还希望能够轻松地归档旧数据,同时保持查询的可用性。
  • 解决方案:创建一个别名,例如"logs",将其指向每天一个新索引。每天结束时,创建新索引并更新别名,这样新数据将被写入新索引。旧索引可以被归档或删除,而查询可以继续使用"logs"别名,无需更改。

案例举例​​​​​​​索引切换:

  • 案例:您的应用程序需要进行滚动更新,例如,将新版本的数据引入到生产环境中,同时确保零停机时间。
  • 解决方案:创建一个别名,例如"live_data",将其指向当前的生产索引。然后,将新索引准备好,并在准备就绪后,将别名从旧索引切换到新索引。这样,新数据将在不中断查询的情况下引入到生产环境中。

这些案例说明了索引别名在处理数据版本控制、查询优化、数据分割与归档以及索引切换方面的实际应用。通过巧妙使用别名,可以更灵活地管理和操作您的 Elasticsearch 索引,同时确保数据的可用性和性能。

选择上面提到的 "版本控制" 案例,并进行具体的展示和分析步骤。这个案例涉及使用索引别名进行索引版本控制,允许平滑地更新索引结构而不中断用户查询。

背景:假设我们运营一个博客平台,使用 Elasticsearch 来存储博客文章。需要定期更新博客文章的结构,例如,添加新字段或更改映射。同时希望用户可以持续访问其旧的博客文章,并逐渐迁移到新的文章结构。

第一步:创建初始索引和别名

创建初始的博客索引,例如 blog_posts_v1

PUT /blog_posts_v1
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "content": {
        "type": "text"
      },
      "date_published": {
        "type": "date"
      }
    }
  }
}

创建一个别名 blog_posts,将其指向初始的博客索引。

POST /_aliases
{
  "actions": [
    {
      "add": {
        "index": "blog_posts_v1",
        "alias": "blog_posts"
      }
    }
  ]
}

第二步:定期更新索引结构。当需要更新索引结构时,创建一个新的博客索引,例如 blog_posts_v2,并更新映射。

PUT /blog_posts_v2
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "content": {
        "type": "text"
      },
      "date_published": {
        "type": "date"
      },
      "author": {
        "type": "keyword"
      }
    }
  }
}

第三步:切换别名。一旦新的博客索引 blog_posts_v2 准备就绪,使用别名切换将别名 blog_posts 从旧索引 blog_posts_v1 切换到新索引 blog_posts_v2

POST /_aliases
{
  "actions": [
    {
      "remove": {
        "index": "blog_posts_v1",
        "alias": "blog_posts"
      }
    },
    {
      "add": {
        "index": "blog_posts_v2",
        "alias": "blog_posts"
      }
    }
  ]
}

第四步:用户迁移。用户可以继续访问和查询博客文章,而无需更改他们的查询代码。新的博客文章将写入新的索引 blog_posts_v2,而旧的博客文章仍然可查询。

第五步:清理旧索引。定期清理旧的博客索引(例如,blog_posts_v1),或者在不再需要它们时进行归档或删除。

这个案例说明了如何使用索引别名在更新索引结构时,平滑地迁移用户到新的索引版本,同时保持查询的连续性。索引别名是实现版本控制和索引维护的有力工具。

二、映射操作

在 Elasticsearch 中,映射(Mapping)是用来定义如何存储和索引文档中字段的方式的重要概念。映射操作用于指定字段的数据类型、分析器以及其他属性,以便 Elasticsearch 能够正确地处理和查询文档中的数据。

映射是 Elasticsearch 中的元数据,它描述了索引中每个字段的数据类型、如何被索引以及如何存储。它允许 Elasticsearch 理解和处理文档中的数据。

映射的主要元素

  • 数据类型:定义字段的数据类型,如文本、数字、日期、地理位置等。
  • 分析器(Analyzer):指定用于分词和处理文本字段的分析器。分析器将文本字段拆分成单词,以便进行全文搜索。
  • 属性(Properties):定义字段的其他属性,如是否可搜索、是否存储原始值、是否支持排序等。
  • 嵌套映射(Nested Mapping):用于处理复杂数据结构,如嵌套文档或数组。

映射对于正确索引和查询文档非常重要。如果映射不正确,将导致搜索和分析错误。正确的映射可以优化查询性能,使 Elasticsearch 能够更好地理解和处理文档数据。一旦索引创建后,通常不能直接更改映射。但可以通过重新索引数据或创建新索引来应用新的映射

映射的注意事项

  • 映射的设计需要仔细考虑,因为不正确的映射可能会导致数据不一致或搜索性能下降。
  • 映射更改可能需要谨慎处理,特别是在生产环境中,因为不正确的映射更改可能会导致数据丢失或不可用。

总之,映射是 Elasticsearch 中用于定义和管理索引字段的关键操作。正确的映射设计可以提高查询性能和数据质量,而不正确的映射可能会导致问题。在设计和管理索引时,请谨慎考虑映射的使用和更改。

(一)查看映射

在 Elasticsearch 中,可以使用映射操作查看索引的映射信息。要查看索引的映射,可以使用以下常规DSL语句:

GET /my_index/_mapping

在上述示例中,GET 是 HTTP 请求方法,/my_index/_mapping 是要查看映射的索引名称。

  • GET:这是 HTTP 请求方法,用于执行查看映射操作。

  • /my_index/_mapping:这是要查看映射的索引的路径。

假设运营一个电子商务网站,使用 Elasticsearch 来存储产品信息。电子商务网站存储产品信息的 Elasticsearch 索引名为 products,该索引包含产品的名称、价格、描述等信息。使用以下DSL语句来查看产品索引 products 的映射:

GET /products/_mapping

使用以下DSL请求 GET /products/_mapping 会返回关于索引 products 的映射信息。返回结果将是一个JSON格式的响应,其中包含有关索引中字段的详细信息。以下是对返回结果的分析说明:

{
  "products": {
    "mappings": {
      "properties": {
        "name": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "price": {
          "type": "float"
        },
        "description": {
          "type": "text"
        },
        // 其他字段...
      }
    }
  }
}

(二)扩展映射

在 Elasticsearch 中,扩展映射(Mapping Expansion)是一项操作,用于在已有的索引映射基础上添加新的字段或修改已有字段的属性。这可以用于动态地适应数据模型的变化或为索引中的字段添加新功能。以下是有关扩展映射的分析:

扩展映射的使用场景

  • 适应数据模型的变化:当应用程序需要存储新类型的数据或更改现有数据的结构时,扩展映射是一种灵活的方式。例如,可以将新的文本字段添加到索引,以存储新类型的信息。

  • 引入新的数据属性:可能需要在索引中添加新的字段来存储与现有数据相关的新属性。例如,如果索引包含产品信息,可能希望在以后添加字段来存储产品的新特性。

  • 索引迭代和升级:当需要对索引进行迭代和升级时,扩展映射是必要的。例如,如果在旧版本的索引中不包括某些字段,但在新版本中需要这些字段,可以扩展映射以包括这些字段。

扩展映射的操作步骤

  1. 创建新映射:首先,需要定义新字段的映射。这包括指定字段的数据类型、分析器和其他属性。可以通过创建一个新的索引映射来完成。

  2. 将新映射添加到索引:一旦新映射定义好了,可以使用索引别名或新的索引名称,将新映射添加到索引中。

  3. 重新索引数据:如果新映射需要应用于已有的数据,需要重新索引现有数据以适应新的映射。这可以通过重新索引工具或 Elasticsearch 的 Reindex API 来实现。

  4. 测试和验证:在应用新映射之前,建议对其进行测试和验证,以确保数据存储和查询操作按预期工作。

注意事项和考虑因素

  • 扩展映射可能需要一些索引维护工作,特别是对于大型索引。重新索引数据可能会导致一些性能开销。

  • 在扩展映射时,确保新映射的定义与应用程序的需求和数据模型一致。

  • 考虑数据迁移策略,特别是在高可用性和生产环境中。数据迁移应谨慎进行,以确保不会导致数据丢失或中断查询。

总之,扩展映射是 Elasticsearch 中用于适应数据模型变化和引入新属性的重要操作。它提供了灵活性,允许根据应用程序需求不断发展和扩展索引映射。在执行扩展映射操作时,请谨慎规划和测试,以确保数据的完整性和性能。

业务举例:扩展映射以添加作者和标签字段

假设运营一个在线新闻门户网站,使用 Elasticsearch 来存储新闻文章的索引。最初的索引只包含文章的标题、内容和发布日期。现在,我们决定扩展映射,以添加新的字段以存储文章的作者和标签。新闻门户网站使用 Elasticsearch 索引 news_articles 来存储新闻文章。最初的映射定义如下:

{
  "news_articles": {
    "mappings": {
      "properties": {
        "title": {
          "type": "text"
        },
        "content": {
          "type": "text"
        },
        "publish_date": {
          "type": "date"
        }
      }
    }
  }
}

现在,决定扩展映射,以包括文章的作者和标签信息。

第一步:创建新映射。需要创建新的映射,以包括作者和标签字段。新映射如下所示:

{
  "news_articles": {
    "mappings": {
      "properties": {
        "title": {
          "type": "text"
        },
        "content": {
          "type": "text"
        },
        "publish_date": {
          "type": "date"
        },
        "author": {
          "type": "text"
        },
        "tags": {
          "type": "keyword"
        }
      }
    }
  }
}

在新映射中,我们添加了两个新字段:authortags,分别用于存储文章的作者名字和标签(以关键字类型存储)。

第二步:将新映射添加到索引。为了将新映射添加到现有索引中,可以执行以下步骤:

  • 创建一个新的索引,例如 news_articles_v2,并应用新的映射。
  • 使用 Elasticsearch 的 Reindex API 将现有索引中的数据重新索引到新索引中。在此过程中,新映射将被应用于已有的数据。
  • 更新索引别名,以使别名指向新的索引,使其成为主要的查询目标。

第三步:测试和验证。在应用新映射之前,进行测试和验证以确保查询和索引操作按预期工作。确保新字段的数据存储和检索都正确无误。

(三)基本的数据类型

keyword类型

在 Elasticsearch 映射操作中,keyword 类型是一种常用的基本数据类型,用于存储关键字数据。与 text 类型不同,keyword 类型不进行分词,它将整个文本视为单个词条。这使得 keyword 类型非常适合用于排序、聚合和精确匹配等操作

  • 关键字数据keyword 类型用于存储不需要分词的关键字数据。这包括标签、标识符、名称、状态等文本信息,通常需要进行精确匹配或按照字母顺序排序。

  • 不分词:与 text 类型不同,keyword 类型不会对文本进行分词。它将整个文本视为单个词条,保留原始文本的完整性。

  • 精确匹配和排序:由于不进行分词,keyword 类型非常适合进行精确匹配(例如,过滤和筛选操作)和排序操作。您可以确保查询的精确匹配,而不受分词的影响,同时还可以按照字母顺序对数据进行排序。

  • 不适用于全文搜索:由于不进行分词,keyword 类型不适用于全文搜索。如果需要全文搜索,通常应使用 text 类型。

假设您正在使用 Elasticsearch 存储产品信息,并且每个产品都有一个标签列表,希望能够按照标签进行精确匹配和排序。

创建一个索引映射,包括一个 keyword 类型的字段来存储产品标签。

PUT /products
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "tags": {
        "type": "keyword"
      }
    }
  }
}

向索引中添加一些产品文档,包括标签信息。

POST /products/_doc/1
{
  "name": "Product A",
  "tags": ["electronics", "smartphone"]
}

POST /products/_doc/2
{
  "name": "Product B",
  "tags": ["clothing", "shoes"]
}

执行一个精确匹配的查询,查找包含特定标签的产品。

GET /products/_search
{
  "query": {
    "match": {
      "tags": "electronics"
    }
  }
}

此查询将返回包含 "electronics" 标签的产品,而不会返回包含 "smartphone" 标签的产品。

执行一个排序查询,按标签字段的字母顺序对产品进行排序。

GET /products/_search
{
  "sort": [
    {
      "tags": "asc"
    }
  ]
}

此查询将返回产品按标签字段的字母顺序升序排列。

通过使用 keyword 类型来存储标签信息,可以轻松地进行精确匹配和排序,同时保留了标签的原始完整性。这在许多应用中非常有用,特别是在需要处理结构化数据的情况下。

text类型

在 Elasticsearch 映射操作中,text 类型是一种常用的基本数据类型,用于存储文本数据,通常用于全文搜索和分析

  • 文本数据text 类型主要用于存储文本数据,例如文章内容、产品描述、评论等。这些字段通常需要进行全文搜索和分析。

  • 分词text 类型会对文本进行分词,将文本拆分成单词或词条,以便更好地支持全文搜索和分析。分词可以根据配置的分析器进行,以便处理不同语言和文本特性

  • 全文搜索:由于分词的支持,text 类型非常适合进行全文搜索操作。它允许用户查询包含特定单词或短语的文档,而不需要精确匹配整个字段内容。

  • 分析功能text 类型还支持分析功能,包括在搜索时执行文本预处理(如小写化、去停用词、词干提取等)以及相关性评分

假设正在使用 Elasticsearch 存储产品评论,希望能够搜索和分析评论内容。创建一个索引映射,包括一个 text 类型的字段来存储评论内容。

PUT /product_reviews
{
  "mappings": {
    "properties": {
      "product_name": {
        "type": "keyword"
      },
      "comment": {
        "type": "text"
      }
    }
  }
}

向索引中添加一些产品评论文档。

POST /product_reviews/_doc/1
{
  "product_name": "Product A",
  "comment": "This product is amazing! I love it."
}

POST /product_reviews/_doc/2
{
  "product_name": "Product B",
  "comment": "Not satisfied with this product. It doesn't meet my expectations."
}

执行一个全文搜索的查询,查找包含特定关键字的评论。

GET /product_reviews/_search
{
  "query": {
    "match": {
      "comment": "amazing"
    }
  }
}

此查询将返回包含 "amazing" 关键字的评论。

执行一个分析查询,使用分析功能评分。

GET /product_reviews/_search
{
  "query": {
    "match_phrase": {
      "comment": "product satisfaction"
    }
  },
  "sort": [
    "_score" // 根据相关性评分排序
  ]
}

此查询将返回包含 "product satisfaction" 短语的评论,并且可以根据相关性进行排序。

{
  "took": 15,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1.2345678, // 最高评分
    "hits": [
      {
        "_index": "product_reviews",
        "_type": "_doc",
        "_id": "3",
        "_score": 1.2345678, // 文档的评分
        "_source": {
          "product_name": "Product C",
          "comment": "I have found great product satisfaction with this item."
        }
      },
      {
        "_index": "product_reviews",
        "_type": "_doc",
        "_id": "4",
        "_score": 0.9876543, // 文档的评分
        "_source": {
          "product_name": "Product D",
          "comment": "Product satisfaction is important for me."
        }
      }
    ]
  }
}

通过使用 text 类型来存储评论内容,可以进行全文搜索和分析,以更好地理解用户的反馈和需求。这对于处理文本数据的应用场景非常有用,例如产品评论、新闻文章、博客内容等。

数值类型

在 Elasticsearch 映射操作中,数值类型用于存储数值数据,这些数据通常包括整数和浮点数。数值类型非常适用于执行范围查询、聚合操作和数值计算。主要数值类型如下:

  1. integer:用于存储整数值。适用于存储没有小数部分的整数。

  2. long:用于存储长整数值。通常用于存储较大范围的整数。

  3. float:用于存储单精度浮点数值。

  4. double:用于存储双精度浮点数值。通常用于存储高精度的浮点数。

这些数值类型用于存储不同范围和精度的数值数据,以支持各种数值计算和分析需求。

假设正在使用 Elasticsearch 存储销售数据,其中包括产品的价格(浮点数)和销售数量(整数)。创建一个名为 "sales" 的索引,其中包括了价格(price)和销售数量(quantity)字段:

PUT /sales
{
  "mappings": {
    "properties": {
      "price": {
        "type": "float"
      },
      "quantity": {
        "type": "integer"
      }
    }
  }
}

插入了两个产品的销售数据:

POST /sales/_doc/1
{
  "price": 75.99,
  "quantity": 15
}

POST /sales/_doc/2
{
  "price": 95.50,
  "quantity": 20
}

假设希望查找价格在 50 到 100 之间且销售数量大于等于 10 的产品。

GET /sales/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "price": {
              "gte": 50,
              "lte": 100
            }
          }
        },
        {
          "range": {
            "quantity": {
              "gte": 10
            }
          }
        }
      ]
    }
  }
}

返回结果将包含与查询条件匹配的文档。

{
  "took": 10,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "sales",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "product_name": "Product A",
          "price": 75.99,
          "quantity": 15
        }
      },
      {
        "_index": "sales",
        "_type": "_doc",
        "_id": "2",
        "_score": 1.0,
        "_source": {
          "product_name": "Product B",
          "price": 95.50,
          "quantity": 20
        }
      }
    ]
  }
}

分析说明:

  • 查询使用了 range 查询来查找价格在 50 到 100 之间的产品,以及销售数量大于等于 10 的产品。

  • 返回结果包含了匹配的文档,每个文档都包括了相关信息和相关性评分。

  • 查询结果中包括两个产品,它们的价格和销售数量满足查询条件。

这个示例演示了如何使用数值类型进行范围查询,以查找满足特定条件的文档。数值类型非常适用于存储和查询数值数据,对于分析、统计和报告等用途非常有用。

布尔类型

在 Elasticsearch 映射操作中,布尔类型(Boolean)是一种基本的数据类型,用于存储布尔值,即 true 或 false。布尔类型通常用于存储表示真假条件的信息,例如是否已完成、是否可用等

  • 布尔数据:布尔类型用于存储布尔值,它们表示真假条件。在 Elasticsearch 中,布尔字段可以用于标识文档是否满足某些条件。

  • 存储效率:布尔字段非常节省存储空间,因为它们只需要一个位来表示 true 或 false。这对于存储大量布尔信息的索引非常有用。

  • 查询和过滤:布尔字段可用于执行查询和过滤操作。可以根据布尔字段的值来筛选文档,例如查找所有已完成的任务或所有可用的产品。

假设正在使用 Elasticsearch 存储任务列表,并希望标识哪些任务已完成(true)和哪些任务未完成(false)。使用 PUT 请求创建一个索引(index),并指定索引映射(mapping)。在此示例中,我们创建一个名为 "tasks" 的索引,并定义了两个字段:任务名称(task_name)和是否已完成(is_completed)。

PUT /tasks
{
  "mappings": {
    "properties": {
      "task_name": {
        "type": "text"
      },
      "is_completed": {
        "type": "boolean"
      }
    }
  }
}

插入一些示例任务数据的请求:

POST /tasks/_doc/1
{
  "task_name": "Task A",
  "is_completed": true
}

POST /tasks/_doc/2
{
  "task_name": "Task B",
  "is_completed": false
}

POST /tasks/_doc/3
{
  "task_name": "Task C",
  "is_completed": true
}

假设要查询所有已完成的任务:

GET /tasks/_search
{
  "query": {
    "term": {
      "is_completed": true
    }
  }
}

返回结果将包含已完成的任务文档:

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 3,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "tasks",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "task_name": "Task A",
          "is_completed": true
        }
      },
      {
        "_index": "tasks",
        "_type": "_doc",
        "_id": "3",
        "_score": 1.0,
        "_source": {
          "task_name": "Task C",
          "is_completed": true
        }
      }
    ]
  }
}
  • 查询使用了 term 查询来查找 is_completed 字段为 true 的任务。

  • 返回结果包含了已完成的任务文档,每个文档都包括了相关信息和相关性评分(如果使用相关性评分)。

这个示例演示了如何使用布尔类型字段来标识和查询已完成的任务。布尔类型在存储和查询表示真假条件的信息时非常有用,例如任务状态、商品可用性等。通过这种方式,可以有效地管理和查询布尔值数据。

日期类型

在 Elasticsearch 映射操作中,日期类型(Date)是一种基本的数据类型,用于存储日期和时间信息。日期类型通常用于记录事件发生的时间戳或日期值。

  • 日期时间数据:日期类型用于存储日期和时间信息,通常表示为 ISO 8601 格式的日期字符串(例如:"2023-10-06T15:30:00Z")。

  • 存储格式:Elasticsearch 内部将日期类型存储为 UNIX 时间戳(以毫秒为单位),但可以在查询和返回结果中使用更人类可读的日期字符串。

  • 支持的日期格式:Elasticsearch 支持多种日期格式的解析,允许索引不同格式的日期,并在查询时执行日期范围过滤和聚合。

  • 时区处理:日期类型支持时区信息,以确保正确处理不同时区的日期和时间。

假设您正在使用 Elasticsearch 存储新闻文章,并希望记录每篇文章的发布日期。使用 PUT 请求创建一个索引(index),并指定索引映射(mapping)。在此示例中,我们创建一个名为 "news_articles" 的索引,并定义了两个字段:新闻标题(headline)和发布日期(publish_date)。

PUT /news_articles
{
  "mappings": {
    "properties": {
      "headline": {
        "type": "text"
      },
      "publish_date": {
        "type": "date"
      }
    }
  }
}

插入一些示例新闻文章数据的请求:

POST /news_articles/_doc/1
{
  "headline": "Elasticsearch 8.0 Released",
  "publish_date": "2023-04-15T10:30:00Z"
}

POST /news_articles/_doc/2
{
  "headline": "Big Data Summit 2023 Recap",
  "publish_date": "2023-07-20T14:45:00Z"
}

POST /news_articles/_doc/3
{
  "headline": "AI Advances in Healthcare",
  "publish_date": "2023-11-10T08:15:00Z"
}

假设您要查询所有发布日期在特定时间段内的文章:

GET /news_articles/_search
{
  "query": {
    "range": {
      "publish_date": {
        "gte": "2023-01-01T00:00:00Z",
        "lte": "2023-12-31T23:59:59Z"
      }
    }
  }
}

返回结果将包含发布日期在指定时间段内的文章:

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 3,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "news_articles",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "headline": "Article A",
          "publish_date": "2023-04-15T10:30:00Z"
        }
      },
      {
        "_index": "news_articles",
        "_type": "_doc",
        "_id": "2",
        "_score": 1.0,
        "_source": {
          "headline": "Article B",
          "publish_date": "2023-07-20T14:45:00Z"
        }
      },
      {
        "_index": "news_articles",
        "_type": "_doc",
        "_id": "3",
        "_score": 1.0,
        "_source": {
          "headline": "Article C",
          "publish_date": "2023-11-10T08:15:00Z"
        }
      }
    ]
  }
}
  • 查询使用了 range 查询来查找发布日期在 2023 年内的文章。

  • 返回结果包含了发布日期在指定时间段内的文章,每个文档都包括了相关信息和相关性评分(如果使用相关性评分)。

这个示例演示了如何使用日期类型字段来存储和查询日期信息。日期类型在存储和分析与时间相关的数据时非常有用,例如新闻发布日期、事件发生时间等。通过这种方式,可以轻松地执行日期范围过滤和聚合操作,以满足各种时间相关的查询需求。

(四)复杂数据类型

数组类型

在 Elasticsearch 映射操作中,数组类型用于存储多个值的集合,这些值可以是相同类型的,也可以是不同类型的。数组类型通常用于表示复杂的多值字段,例如标签、评论、作者列表等

  • 数组数据:数组类型允许在单个字段中存储多个值,这些值可以是文本、数字、日期或其他数据类型。

  • 多值字段:与传统数据库不同,Elasticsearch 允许字段具有多个值,而不需要创建多个字段。这使得数组类型非常适用于存储多值属性。

  • 支持的数据类型:数组可以包含不同类型的数据,例如文本、数字、日期等。这使得它非常灵活。

  • 查询和过滤:可以使用数组字段执行查询和过滤操作,例如查找包含特定值的文档或在数组中查找范围内的值。

假设您正在使用 Elasticsearch 存储图书信息,每本书可以有多个作者。使用 PUT 请求创建一个索引(index),并指定索引映射(mapping)。在此示例中,我们创建一个名为 "books" 的索引,并定义了两个字段:书名(title)和作者列表(authors)。

PUT /books
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "authors": {
        "type": "keyword"
      }
    }
  }
}

插入一些示例图书数据的请求:

POST /books/_doc/1
{
  "title": "Book A",
  "authors": ["John Smith", "Alice Johnson"]
}

POST /books/_doc/2
{
  "title": "Book B",
  "authors": ["John Smith", "David Williams"]
}

POST /books/_doc/3
{
  "title": "Book C",
  "authors": ["Alice Johnson", "Emily Davis"]
}

假设要查询包含作者 "John Smith" 的书籍:

GET /books/_search
{
  "query": {
    "match": {
      "authors": "John Smith"
    }
  }
}

返回结果将包含包含 "John Smith" 作为作者的书籍:

{
  "took": 7,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "books",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "title": "Book A",
          "authors": ["John Smith", "Alice Johnson"]
        }
      },
      {
        "_index": "books",
        "_type": "_doc",
        "_id": "2",
        "_score": 1.0,
        "_source": {
          "title": "Book B",
          "authors": ["John Smith", "David Williams"]
        }
      }
    ]
  }
}
  • 查询使用了 match 查询来查找包含作者 "John Smith" 的书籍。

  • 返回结果包含了满足查询条件的书籍文档,每个文档都包括了相关信息和相关性评分(如果使用相关性评分)。

这个示例演示了如何使用数组类型字段来存储和查询多个值的集合。数组类型非常适用于表示多值属性,例如多个作者、标签或评论。通过这种方式,可以轻松地查询包含特定值的文档,以满足各种多值属性的查询需求。

对象类型

在 Elasticsearch 映射操作中,对象类型(Object)是一种复杂的数据类型,用于存储嵌套的结构化数据。对象类型允许将多个字段组合到一个单独的对象中,这些字段可以是不同类型的,形成了文档内的嵌套结构。

  • 对象数据:对象类型用于存储嵌套的结构化数据。它允许将多个字段组织为一个单独的对象,以便更好地表示数据的层次性和复杂性。

  • 嵌套字段:对象字段中的每个子字段都可以有自己的数据类型。这允许在一个文档中存储多个嵌套字段,每个字段可以有不同的数据类型,例如文本、数字、日期等。

  • 结构化数据:对象类型特别适用于存储具有层次结构的数据,例如产品包含属性、订单包含多个项目等。

  • 查询和过滤:可以使用对象类型执行查询和过滤操作,以访问和操作嵌套的数据。

假设您正在使用 Elasticsearch 存储个人信息,其中每个文档表示一个人,包括姓名(name)、地址(address)、联系信息(contact)等。

PUT /people
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "address": {
        "type": "object",
        "properties": {
          "city": {
            "type": "text"
          },
          "state": {
            "type": "keyword"
          }
        }
      },
      "contact": {
        "type": "object",
        "properties": {
          "email": {
            "type": "text"
          },
          "phone": {
            "type": "text"
          }
        }
      }
    }
  }
}

插入一些示例数据的请求:

POST /people/_doc/1
{
  "name": "Alice Johnson",
  "address": {
    "city": "New York",
    "state": "NY"
  },
  "contact": {
    "email": "[email protected]",
    "phone": "555-1234"
  }
}

POST /people/_doc/2
{
  "name": "Bob Smith",
  "address": {
    "city": "Los Angeles",
    "state": "CA"
  },
  "contact": {
    "email": "[email protected]",
    "phone": "555-5678"
  }
}

假设您要查询所有居住在特定城市的人:

GET /people/_search
{
  "query": {
    "match": {
      "address.city": "New York"
    }
  }
}

返回结果将包含居住在纽约的人的文档:

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "people",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "name": "Alice Johnson",
          "address": {
            "city": "New York",
            "state": "NY"
          },
          "contact": {
            "email": "[email protected]",
            "phone": "555-1234"
          }
        }
      },
      {
        "_index": "people",
        "_type": "_doc",
        "_id": "2",
        "_score": 1.0,
        "_source": {
          "name": "Bob Smith",
          "address": {
            "city": "New York",
            "state": "NY"
          },
          "contact": {
            "email": "[email protected]",
            "phone": "555-5678"
          }
        }
      }
    ]
  }
}
  • 查询使用了 match 查询来查找居住在纽约的人。

  • 返回结果包含了满足查询条件的人的文档,每个文档都包括了姓名、地址、联系信息等嵌套字段的信息。

这个示例演示了如何使用对象类型字段来存储和查询嵌套的结构化数据。对象类型非常适用于表示层次结构的数据,例如个人信息、产品属性、订单项目等。通过这种方式,可以轻松地访问和操作嵌套的数据,以满足各种复杂数据结构的存储和查询需求。

地理类型

在 Elasticsearch 映射操作中,地理类型(Geo)用于存储地理位置信息,如经度和纬度坐标。这种类型允许索引和查询地理位置数据,以便执行空间分析和地理搜索。

  • 地理数据:地理类型用于存储地理位置信息,通常表示为经度和纬度坐标。这种类型非常适用于存储地理空间数据,如地点、地理区域和地理坐标。

  • 地理索引:Elasticsearch 使用地理类型来构建地理索引,以便更容易地执行地理位置相关的查询和分析。这包括范围查询、距离查询、聚合等。

  • 支持的地理形状:Elasticsearch 支持多种地理形状,例如点、线、多边形等,使您能够索引和查询各种地理空间数据。

  • 地理距离计算:地理类型允许您计算地理坐标之间的距离,以便查找在一定距离内的地理位置。

假设您正在使用 Elasticsearch 存储餐厅信息,每个餐厅都有一个地理坐标,希望能够查询距离特定位置一定距离范围内的餐厅。创建一个名为 "restaurants" 的索引,其中包含了餐厅名称(name)和地理坐标(location)。

PUT /restaurants
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "location": {
        "type": "geo_point"
      }
    }
  }
}

插入一些示例餐厅数据的请求:

POST /restaurants/_doc/1
{
  "name": "Restaurant A",
  "location": {
    "lat": 40.7120,
    "lon": -74.0050
  }
}

POST /restaurants/_doc/2
{
  "name": "Restaurant B",
  "location": {
    "lat": 40.7130,
    "lon": -74.0070
  }
}

POST /restaurants/_doc/3
{
  "name": "Restaurant C",
  "location": {
    "lat": 40.7110,
    "lon": -74.0080
  }
}

假设要查找距离纽约市中心(40.7128, -74.0060)10公里以内的餐厅。

GET /restaurants/_search
{
  "query": {
    "bool": {
      "filter": {
        "geo_distance": {
          "distance": "10km",
          "location": {
            "lat": 40.7128,
            "lon": -74.0060
          }
        }
      }
    }
  }
}

返回结果将包含距离纽约市中心10公里以内的餐厅。

{
  "took": 12,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 3,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [
      {
        "_index": "restaurants",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.0,
        "_source": {
          "name": "Restaurant A",
          "location": {
            "lat": 40.7120,
            "lon": -74.0050
          }
        }
      },
      {
        "_index": "restaurants",
        "_type": "_doc",
        "_id": "2",
        "_score": 1.0,
        "_source": {
          "name": "Restaurant B",
          "location": {
            "lat": 40.7130,
            "lon": -74.0070
          }
        }
      },
      {
        "_index": "restaurants",
        "_type": "_doc",
        "_id": "3",
        "_score": 1.0,
        "_source": {
          "name": "Restaurant C",
          "location": {
            "lat": 40.7110,
            "lon": -74.0080
          }
        }
      }
    ]
  }
}
  • 查询使用了 geo_distance 查询来查找距离指定地理坐标一定距离范围内的餐厅。

  • 返回结果包含了满足查询条件的餐厅文档,每个文档都包括了餐厅名称和地理坐标的信息。

这个示例演示了如何使用地理类型字段来存储和查询地理位置信息。地理类型非常适用于处理地理空间数据,如地点搜索、附近搜索和地理分析等需求。通过这种方式,可以轻松地执行地理空间查询和分析,以满足各种地理位置相关的查询需求。

(五)动态映射

动态映射(Dynamic Mapping)是 Elasticsearch 中的一项功能,允许自动检测和创建索引映射,无需手动定义字段的数据类型和属性。当索引文档时,Elasticsearch 根据文档内容自动创建映射,包括字段的数据类型、分析器、索引选项等。这使得索引的管理更加灵活,特别适用于处理不断变化的数据和不确定的数据结构。

以下是常见的 JSON 数据类型和 Elasticsearch 索引类型的对应表:

JSON 数据类型:字符串(String)

  • Elasticsearch 索引类型:textkeyword
  • 说明:字符串类型可以映射为 text 类型用于全文搜索和分析,或映射为 keyword 类型用于精确匹配和聚合。

JSON 数据类型:整数(Integer)

  • Elasticsearch 索引类型:integerlong
  • 说明:整数类型可以映射为 integer 类型(32 位有符号整数)或 long 类型(64 位有符号整数),取决于数据范围。

JSON 数据类型:浮点数(Float/Double)

  • Elasticsearch 索引类型:floatdouble
  • 说明:浮点数类型可以映射为 float 类型(32 位浮点数)或 double 类型(64 位浮点数)。

JSON 数据类型:布尔值(Boolean)

  • Elasticsearch 索引类型:boolean
  • 说明:布尔值类型映射为 boolean 类型,用于存储 true 或 false。

JSON 数据类型:日期和时间(Date/Time)

  • Elasticsearch 索引类型:date
  • 说明:日期和时间类型映射为 date 类型,用于存储日期和时间信息。

JSON 数据类型:数组(Array)

  • Elasticsearch 索引类型:array
  • 说明:JSON 数组通常映射为 Elasticsearch 中的数组,可以包含多个值。Elasticsearch 中的数组字段通常需要指定 nested 类型,以支持多值字段的查询和聚合。

JSON 数据类型:对象(Object)

  • Elasticsearch 索引类型:object
  • 说明:JSON 对象可以映射为 Elasticsearch 的对象类型,用于存储嵌套的结构化数据。

JSON 数据类型:地理坐标(Geospatial Coordinates)

  • Elasticsearch 索引类型:geo_point
  • 说明:地理坐标类型用于存储经度和纬度坐标,以支持地理位置相关的查询和分析。

这个对应表展示了常见的 JSON 数据类型与 Elasticsearch 索引类型之间的映射关系。当索引文档时,Elasticsearch 会根据文档的字段内容自动选择合适的数据类型。如果需要更精细的控制,可以通过显式映射来定义字段的数据类型和属性。动态映射为 Elasticsearch 提供了灵活性,使其适应各种数据结构和用例。

(六)多字段

在 Elasticsearch 中,多字段(Multi-Field)是一种索引映射策略,用于将一个字段存储在多个不同的子字段中,每个子字段可以具有不同的数据类型或分析器。多字段的引入允许在一个字段上执行多种操作,例如全文搜索、精确匹配、聚合等,同时保留原始数据的不同表示形式。

多字段的特点和用途

  • 数据多样性:多字段允许您在一个字段上存储多个不同的数据表示,以适应各种查询需求。例如,一个字段可以同时存储原始文本和分析后的词汇。

  • 支持不同数据类型:每个子字段可以具有不同的数据类型。例如,一个字段可以同时映射为 text 类型用于全文搜索和 keyword 类型用于精确匹配。

  • 支持不同分析器:每个子字段可以使用不同的文本分析器。这使得您可以在一个字段上执行不同类型的文本分析。

  • 灵活性:多字段使您能够针对不同的查询场景选择最合适的子字段,同时保持原始数据的完整性。

  • 支持复杂查询:多字段允许您执行复杂的查询操作,例如同时执行全文搜索和精确匹配,或者在多个子字段上执行聚合操作。

多字段示例

假设有一个名为 "product" 的索引,其中包含了产品名称(product_name)字段。希望能够在同一字段上执行全文搜索和精确匹配。以下是使用多字段的示例映射:

PUT /product
{
  "mappings": {
    "properties": {
      "product_name": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

在上述映射中,我们定义了一个 product_name 字段,并在该字段下创建了一个子字段 keyword,它具有 keyword 数据类型。这个子字段将用于精确匹配。

多字段的用法示例-全文搜索:要执行全文搜索,可以使用原始字段 product_name。例如:

GET /product/_search
{
  "query": {
    "match": {
      "product_name": "Elasticsearch"
    }
  }
}

多字段的用法示例-精确匹配:要执行精确匹配,可以使用子字段 product_name.keyword。例如:

GET /product/_search
{
  "query": {
    "term": {
      "product_name.keyword": "Elasticsearch"
    }
  }
}

在此示例中,我们分别使用原始字段和子字段执行不同类型的查询。

多字段的引入使得索引中的字段可以灵活地适应各种查询需求,同时保持原始数据的完整性。这在处理多样性的数据和不同的查询场景时非常有用。

三、文档操作

(一)单条写入文档

在 Elasticsearch 中,要进行单条写入文档操作,可以使用 index 操作。要单条写入文档,可以使用以下DSL语句:

POST /your_index/_doc/1
{
  "field1": "value1",
  "field2": "value2",
  "field3": 123,
  "field4": true
}
  • POST 请求用于创建文档。
  • /your_index 是您的索引名称。
  • /_doc/1 中的 1 是文档的唯一标识符,您可以选择性地提供,如果未提供,Elasticsearch 会为您生成一个唯一标识符。
  • JSON数据包含文档的字段和值。

分析说明

  • POST 请求用于创建文档。如果指定的标识符(在上述示例中为 1)已经存在于索引中,它将更新现有文档。否则,它将创建一个新的文档。

  • 文档的字段和值在JSON数据中指定,您可以根据您的业务需求提供不同的字段和数据类型。

业务举例

假设您正在构建一个电子商务平台,并希望将一件商品的信息写入 Elasticsearch 中,以便进行搜索和分析。以下是一个示例,包括DSL和Java演示:

DSL语句示例

POST /products/_doc/12345
{
  "product_name": "Laptop",
  "description": "High-performance laptop with SSD storage.",
  "price": 999.99,
  "in_stock": true
}

Java演示

import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.RestStatus;

public class SingleDocumentIndexingExample {

    public static void main(String[] args) throws IOException {

        RestHighLevelClient client = createElasticsearchClient();

        // 构建索引请求
        IndexRequest request = new IndexRequest("products");
        request.id("12345"); // 文档标识符
        String jsonString = "{" +
                "\"product_name\":\"Laptop\"," +
                "\"description\":\"High-performance laptop with SSD storage.\"," +
                "\"price\":999.99," +
                "\"in_stock\":true" +
                "}";
        request.source(jsonString, XContentType.JSON);

        // 执行索引请求
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);

        // 分析响应
        if (response.status() == RestStatus.CREATED) {
            System.out.println("文档已创建");
        } else if (response.status() == RestStatus.OK) {
            System.out.println("文档已更新");
        } else {
            System.err.println("无法创建/更新文档");
        }

        // 关闭客户端
        client.close();
    }
}

(二)批量写入文档

在 Elasticsearch 中,批量写入文档通常使用批量索引(Bulk Indexing)API 来实现。允许一次性将多个文档索引到索引中,提高了性能和效率。要批量写入文档,可以使用 Bulk API 发送一批索引请求。

POST /your_index/_bulk
{"index":{"_id":"1"}}
{"field1":"value1","field2":"value2"}
{"index":{"_id":"2"}}
{"field1":"value3","field2":"value4"}
{"update":{"_id":"3"}}
{"doc":{"field1":"new_value"}}
{"delete":{"_id":"4"}}
  • POST 请求用于批量操作。
  • /your_index 是您的索引名称。
  • 使用 {"index": {"_id": "1"}} 定义文档的元数据,包括文档标识符。
  • 每个文档的数据在之后的行中提供,以JSON格式表示。

分析说明

  • Bulk API 允许一次性处理多个索引请求,包括索引、更新和删除操作。

  • 使用元数据(例如 {"index": {"_id": "1"}})可以指定每个文档的唯一标识符。

  • 除了索引操作,Bulk API 还支持更新和删除操作。

业务举例

假设您正在构建一个电子商务平台,需要批量索引多个产品的信息。以下是一个示例,包括DSL和Java演示:

DSL语句示例

POST /products/_bulk
{"index":{"_id":"1"}}
{"product_name":"Laptop1","description":"High-performance laptop with SSD storage.","price":999.99,"in_stock":true}
{"index":{"_id":"2"}}
{"product_name":"Laptop2","description":"Affordable laptop for everyday use.","price":599.99,"in_stock":true}
{"index":{"_id":"3"}}
{"product_name":"Smartphone1","description":"Flagship smartphone with advanced features.","price":799.99,"in_stock":false}

Java演示

import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class BulkIndexingExample {

    public static void main(String[] args) throws IOException {

        RestHighLevelClient client = createElasticsearchClient();

        // 创建批量请求对象
        BulkRequest request = new BulkRequest();

        // 添加索引请求
        request.add(new IndexRequest("products").id("1").source(/* JSON 数据 */));
        request.add(new IndexRequest("products").id("2").source(/* JSON 数据 */));
        request.add(new IndexRequest("products").id("3").source(/* JSON 数据 */));

        // 设置超时时间
        request.timeout(TimeValue.timeValueMinutes(2));
        request.timeout("2m");

        // 执行批量请求
        BulkResponse bulkResponse = client.bulk(request, RequestOptions.DEFAULT);

        // 分析响应
        if (bulkResponse.hasFailures()) {
            System.err.println("批量请求中存在失败的操作");
        } else {
            System.out.println("批量请求成功完成");
        }

        // 关闭客户端
        client.close();
    }
}

(三)更新单条文档

update 操作

在 Elasticsearch 中,更新单条文档通常使用 update 操作。要更新单条文档,您可以使用 update 操作,示例如下:

POST /your_index/_update/1
{
  "doc": {
    "field1": "new_value1",
    "field2": "new_value2"
  }
}

  • POST 请求用于执行更新操作。
  • /your_index 是您的索引名称。
  • /_update/1 中的 1 是要更新的文档的唯一标识符。
  • doc 字段中指定要更新的字段和新值。

分析说明

  • update 操作允许您仅更新文档的特定字段,而不必重写整个文档。这是一种高效的方式来更新文档。

  • 更新操作是部分更新,只会修改指定字段的值,而不会影响其他字段。

业务举例

假设您正在构建一个博客平台,并希望更新特定博客文章的内容。以下是一个示例,包括DSL和Java演示:

DSL语句示例

POST /blog_posts/_update/123
{
  "doc": {
    "title": "Updated Title",
    "content": "This is the updated content of the blog post."
  }
}

Java演示

import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.RestStatus;

import java.io.IOException;
import java.util.Map;

public class UpdateSingleDocumentExample {

    public static void main(String[] args) throws IOException {

        RestHighLevelClient client = createElasticsearchClient();

        // 创建更新请求
        UpdateRequest request = new UpdateRequest("blog_posts", "123");
        String jsonString = "{" +
                "\"doc\": {" +
                "\"title\": \"Updated Title\"," +
                "\"content\": \"This is the updated content of the blog post.\"" +
                "}" +
                "}";
        request.doc(jsonString, XContentType.JSON);

        // 执行更新请求
        UpdateResponse response = client.update(request, RequestOptions.DEFAULT);

        // 分析响应
        if (response.status() == RestStatus.OK) {
            System.out.println("文档已成功更新");
        } else {
            System.err.println("无法更新文档");
        }

        // 关闭客户端
        client.close();
    }
}
upsert 操作

upsert 是 Elasticsearch 更新操作中的一个重要概念,它允许在更新文档时,如果文档不存在,则将其插入(新增)。这在希望更新文档的同时,如果文档尚不存在,就创建一个新文档的情况下非常有用。要执行 upsert 操作,可以在 update 操作中使用 doc_as_upsert 参数,示例如下:

POST /your_index/_update/1
{
  "doc": {
    "field1": "new_value1",
    "field2": "new_value2"
  },
  "doc_as_upsert": true
}
  • doc 中指定要更新的字段和新值。
  • doc_as_upsert 设置为 true,表示如果文档不存在,则将 doc 中的内容插入(新增)为新文档。

分析说明

  • 当文档存在时,upsert 操作与普通更新操作相同,更新指定的字段。
  • 当文档不存在时,upsert 操作会将 doc 中的内容插入为新文档。

业务举例

假设您正在构建一个在线商店,想要更新产品的信息,同时如果产品不存在,则添加新产品。以下是一个示例,包括DSL和Java演示:

DSL语句示例

POST /products/_update/123
{
  "doc": {
    "product_name": "Updated Product",
    "price": 29.99
  },
  "doc_as_upsert": true
}

Java演示

import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.RestStatus;

import java.io.IOException;

public class UpsertExample {

    public static void main(String[] args) throws IOException {

        RestHighLevelClient client = createElasticsearchClient();

        // 创建更新请求,指定索引名称和文档标识符
        UpdateRequest request = new UpdateRequest("products", "123");

        // 设置要更新的字段和新值
        String jsonString = "{" +
                "\"product_name\": \"Updated Product\"," +
                "\"price\": 29.99" +
                "}";
        request.doc(jsonString, XContentType.JSON);

        // 设置doc_as_upsert为true,以支持upsert
        request.docAsUpsert(true);

        // 执行更新请求
        UpdateResponse response = client.update(request, RequestOptions.DEFAULT);

        // 分析响应
        if (response.status() == RestStatus.CREATED) {
            System.out.println("文档已创建(upsert)");
        } else if (response.status() == RestStatus.OK) {
            System.out.println("文档已成功更新");
        } else {
            System.err.println("无法更新文档");
        }

        // 关闭客户端
        client.close();
    }
}

(四)更新批量文档

如果只有文档的ID列表而没有其他条件来更新文档,可以使用 Elasticsearch 的 Bulk API 来批量更新这些文档。Bulk API 不需要DSL语句,而是需要一个包含每个文档更新操作的请求列表。每个更新操作通常包括三个部分:操作类型(update)、索引名称、文档ID和更新数据。

POST /_bulk
{"update":{"_index":"your_index","_id":"doc1"}}
{"doc":{"field1":"new_value1"}}
{"update":{"_index":"your_index","_id":"doc2"}}
{"doc":{"field2":"new_value2"}}

  • POST 请求用于执行批量更新操作。
  • _bulk 是Bulk API的端点。
  • 对于每个文档,首先定义了一个update操作,然后指定了索引名称(_index)和文档ID(_id),最后提供了要更新的数据。

分析说明

  • 使用Bulk API,可以在一个请求中批量执行多个文档更新操作。
  • 更新操作包括了要更新的文档的索引名称、文档ID以及要更新的数据。

Java演示

import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.RestStatus;

import java.io.IOException;
import java.util.List;

public class ElasticsearchBulkUpdater {

    private RestHighLevelClient client;

    public ElasticsearchBulkUpdater(RestHighLevelClient client) {
        this.client = client;
    }

    public void bulkUpdateByIdList(String indexName, List docIdList, List> updatedDataList) {
        try {
            BulkRequest request = new BulkRequest();

            for (int i = 0; i < docIdList.size(); i++) {
                String docId = docIdList.get(i);
                String jsonString = "{" +
                        "\"doc\":" + getJsonString(updatedDataList.get(i)) +
                        "}";
                request.add(client.updateRequest(indexName, docId)
                        .doc(jsonString, XContentType.JSON)
                        .docAsUpsert(true));
            }

            BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);

            if (response.status() == RestStatus.OK) {
                System.out.println("批量更新成功");
            } else {
                System.err.println("批量更新失败");
            }
        } catch (IOException e) {
            System.err.println("执行批量更新时出现IO异常: " + e.getMessage());
            // 在此处处理异常情况
        }
    }

    private String getJsonString(Map updatedData) {
        // 创建更新文档的JSON字符串
        // 省略实现细节
        return jsonString;
    }

    // 其他方法和资源清理

}

(五)根据条件更新文档

要根据条件更新文档,可以使用 Elasticsearch 的 Update By Query API。使用 Update By Query API 来根据条件更新文档。示例如下:

POST /your_index/_update_by_query
{
  "script": {
    "source": "ctx._source.field1 = 'new_value1'; ctx._source.field2 = 'new_value2';"
  },
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "field3": "value_to_match"
          }
        },
        {
          "range": {
            "field4": {
              "gte": 10,
              "lt": 20
            }
          }
        }
      ]
    }
  }
}
  • POST 请求用于执行更新操作。
  • /your_index 是您的索引名称。
  • _update_by_query 表示根据查询条件更新文档。
  • script 中指定要更新的字段和新值的逻辑。
  • query 中定义筛选条件,以确定要更新哪些文档。在此示例中,我们使用了布尔查询(bool),并设置了两个条件:一个是 field3 必须匹配特定值,另一个是 field4 的值必须在10到20之间。

分析说明

  • 使用 Update By Query API,您可以根据自定义查询条件更新文档。
  • script 部分,您可以编写更新逻辑,将需要更新的字段设置为新值。在这个示例中,我们使用 ctx._source.field1ctx._source.field2 来更新字段。

业务举例

假设您正在管理一个电子商务网站的产品目录,并需要根据条件更新产品信息。以下是一个示例,包括DSL和Java演示:

DSL语句示例

POST /products/_update_by_query
{
  "script": {
    "source": "ctx._source.price = ctx._source.price * 1.1;"
  },
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "category": "electronics"
          }
        },
        {
          "range": {
            "price": {
              "lt": 100
            }
          }
        }
      ]
    }
  }
}

Java演示

import org.elasticsearch.action.updatebyquery.UpdateByQueryRequest;
import org.elasticsearch.action.updatebyquery.UpdateByQueryResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.rest.RestStatus;

import java.io.IOException;

public class UpdateByQueryExample {

    public static void main(String[] args) throws IOException {

        RestHighLevelClient client = createElasticsearchClient();

        // 创建 Update By Query 请求
        UpdateByQueryRequest request = new UpdateByQueryRequest("products");

        // 在脚本中指定更新逻辑
        request.setScript("ctx._source.price = ctx._source.price * 1.1");

        // 设置查询条件,只更新电子产品且价格低于100的产品
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("category", "electronics"))
                .must(QueryBuilders.rangeQuery("price").lt(100));
        request.setQuery(boolQuery);

        // 执行 Update By Query 请求
        UpdateByQueryResponse response = client.updateByQuery(request, RequestOptions.DEFAULT);

        // 分析响应
        if (response.status() == RestStatus.OK) {
            System.out.println("文档更新成功");
        } else {
            System.err.println("文档更新失败");
        }

        // 关闭客户端
        client.close();
    }
}

(六)删除单条文档

要删除单条文档,可以使用 Elasticsearch 的 Delete API。使用 Delete API 来删除单条文档。示例如下:

DELETE /your_index/_doc/your_document_id
  • DELETE 请求用于执行删除操作。
  • /your_index 是您的索引名称。
  • /_doc 表示文档类型,根据Elasticsearch的最新版本,文档类型通常为_doc
  • your_document_id 是要删除的文档的唯一标识符。

分析说明

  • 使用 Delete API,您可以根据文档的唯一标识符删除单条文档。
  • 您需要指定索引名称和文档的唯一标识符来执行删除操作。

业务举例

假设正在管理一个博客平台的文章索引,以下是一个示例,包括DSL和Java演示,用于删除单篇文章:

DSL语句示例

DELETE /blog_posts/_doc/12345

Java演示

import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.rest.RestStatus;

import java.io.IOException;

public class DeleteSingleDocumentExample {

    public static void main(String[] args) throws IOException {

        RestHighLevelClient client = createElasticsearchClient();

        // 创建删除请求
        DeleteRequest request = new DeleteRequest("blog_posts", "12345"); // 指定索引名称和文档ID

        // 执行删除请求
        DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);

        // 分析响应
        if (response.status() == RestStatus.OK) {
            System.out.println("文档已成功删除");
        } else if (response.status() == RestStatus.NOT_FOUND) {
            System.err.println("文档未找到,无法删除");
        } else {
            System.err.println("无法删除文档");
        }

        // 关闭客户端
        client.close();
    }
}

(七)批量删除文档

要批量删除文档,可以使用 Elasticsearch 的 Bulk API。使用 Bulk API 来批量删除文档。示例如下:

POST /your_index/_bulk
{"delete":{"_index":"your_index","_id":"doc1"}}
{"delete":{"_index":"your_index","_id":"doc2"}}
  • POST 请求用于执行批量操作。
  • /your_index 是您的索引名称。
  • _bulk 是Bulk API的端点。
  • 对于每个文档,首先定义了一个delete操作,然后指定了索引名称(_index)和文档ID(_id)。

分析说明

  • 使用 Bulk API,可以在一个请求中批量执行多个文档的删除操作。
  • 每个删除操作包括要删除的文档的索引名称和文档ID。

业务举例

假设正在管理一个电子商务网站的订单历史记录,并需要批量删除特定日期之前的订单记录。以下是一个示例,包括DSL和Java演示:

DSL语句示例

POST /order_history/_bulk
{"delete":{"_index":"order_history","_id":"order1"}}
{"delete":{"_index":"order_history","_id":"order2"}}

Java演示

import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.rest.RestStatus;

import java.io.IOException;
import java.util.List;

public class ElasticsearchBulkDeleter {

    private RestHighLevelClient client;

    public ElasticsearchBulkDeleter(RestHighLevelClient client) {
        this.client = client;
    }

    public void bulkDeleteByIdList(String indexName, List docIdList) {
        try {
            BulkRequest request = new BulkRequest();

            for (String docId : docIdList) {
                request.add(client.deleteRequest(indexName, docId));
            }

            BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);

            if (response.status() == RestStatus.OK) {
                System.out.println("批量删除成功");
            } else {
                System.err.println("批量删除失败");
            }
        } catch (IOException e) {
            System.err.println("执行批量删除时出现IO异常: " + e.getMessage());
            // 在此处处理异常情况
        }
    }

    // 其他方法和资源清理

}

(八)根据条件删除文档

要根据条件删除文档,可以使用 Elasticsearch 的 Delete By Query API。使用 Delete By Query API 来根据条件删除文档。示例如下:

POST /your_index/_delete_by_query
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "field1": "value_to_match"
          }
        },
        {
          "range": {
            "field2": {
              "lte": 10
            }
          }
        }
      ]
    }
  }
}
  • POST 请求用于执行删除操作。
  • /your_index 是您的索引名称。
  • /_delete_by_query 表示根据查询条件删除文档。
  • query 中定义筛选条件,以确定要删除哪些文档。在此示例中,我们使用了布尔查询(bool),并设置了两个条件:一个是 field1 必须匹配特定值,另一个是 field2 的值必须小于或等于10。

分析说明

  • 使用 Delete By Query API,可以根据自定义查询条件删除文档。
  • query 部分,您可以定义要删除的文档的筛选条件。

业务举例

假设正在管理一个文档存储系统,需要根据条件删除文档。以下是一个示例,包括DSL和Java演示:

DSL语句示例

POST /documents/_delete_by_query
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "category": "archived"
          }
        },
        {
          "range": {
            "last_modified_date": {
              "lte": "2022-01-01"
            }
          }
        }
      ]
    }
  }
}

Java演示

import org.elasticsearch.action.deletebyquery.DeleteByQueryRequest;
import org.elasticsearch.action.deletebyquery.DeleteByQueryResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.rest.RestStatus;

import java.io.IOException;

public class DeleteByQueryExample {

    public static void main(String[] args) throws IOException {

        RestHighLevelClient client = createElasticsearchClient();

        // 创建 Delete By Query 请求
        DeleteByQueryRequest request = new DeleteByQueryRequest("documents");

        // 设置查询条件,只删除属于 "archived" 类别且最后修改日期早于等于 "2022-01-01" 的文档
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("category", "archived"))
                .must(QueryBuilders.rangeQuery("last_modified_date").lte("2022-01-01"));
        request.setQuery(boolQuery);

        // 执行 Delete By Query 请求
        DeleteByQueryResponse response = client.deleteByQuery(request, RequestOptions.DEFAULT);

        // 分析响应
        if (response.status() == RestStatus.OK) {
            System.out.println("文档删除成功");
        } else {
            System.err.println("文档删除失败");
        }

        // 关闭客户端
        client.close();
    }
}

(九)示例 Elasticsearch 操作工具类

package org.zyf.javabasic.es;

import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @program: zyfboot-javabasic
 * @description: Elasticsearch 操作工具类的简化示例
 * @author: zhangyanfeng
 * @create: 2023-10-06 22:29
 **/
public class ElasticsearchOperations {
    private RestHighLevelClient client;

    public ElasticsearchOperations(RestHighLevelClient client) {
        this.client = client;
    }

    public void singleIndexDoc(String indexName, String indexId, Map dataMap) {
        // 实现单条写入文档的逻辑,类似于之前示例中的单条写入代码
        try {
            IndexRequest request = new IndexRequest(indexName)
                    .id(indexId)
                    .source(dataMap, XContentType.JSON);

            IndexResponse response = client.index(request, RequestOptions.DEFAULT);

            if (response.status() == RestStatus.CREATED) {
                System.out.println("文档已创建");
            } else {
                System.err.println("无法创建文档");
            }
        } catch (IOException e) {
            System.err.println("执行单条写入文档时出现IO异常: " + e.getMessage());
            // 在此处处理异常情况
        }
    }

    public void bulkIndexDoc(String indexName, String docIdKey, List> recordMapList) {
        // 实现批量写入文档的逻辑,类似于之前示例中的批量写入代码
        try {
            BulkRequest request = new BulkRequest();

            for (Map recordMap : recordMapList) {
                String docId = recordMap.get(docIdKey).toString();
                request.add(new IndexRequest(indexName)
                        .id(docId)
                        .source(recordMap, XContentType.JSON));
            }

            BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);

            if (response.status() == RestStatus.OK) {
                System.out.println("批量写入成功");
            } else {
                System.err.println("批量写入失败");
            }
        } catch (IOException e) {
            System.err.println("执行批量写入文档时出现IO异常: " + e.getMessage());
            // 在此处处理异常情况
        }
    }

    public void singleUpdate(String indexName, String docIdKey, Map recordMap) {
        // 实现单条更新文档的逻辑,类似于之前示例中的单条更新代码
        try {
            String docId = recordMap.get(docIdKey).toString();
            UpdateRequest request = new UpdateRequest(indexName, docId)
                    .doc(recordMap, XContentType.JSON);

            UpdateResponse response = client.update(request, RequestOptions.DEFAULT);

            if (response.status() == RestStatus.OK) {
                System.out.println("文档已成功更新");
            } else {
                System.err.println("无法更新文档");
            }
        } catch (IOException e) {
            System.err.println("执行单条更新文档时出现IO异常: " + e.getMessage());
            // 在此处处理异常情况
        }
    }

    public void bulkUpdate(String indexName, String docIdKey, List> recordMapList) {
        // 实现批量更新文档的逻辑,类似于之前示例中的批量更新代码
        try {
            BulkRequest request = new BulkRequest();

            for (Map recordMap : recordMapList) {
                String docId = recordMap.get(docIdKey).toString();
                request.add(new UpdateRequest(indexName, docId)
                        .doc(recordMap, XContentType.JSON));
            }

            BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);

            if (response.status() == RestStatus.OK) {
                System.out.println("批量更新成功");
            } else {
                System.err.println("批量更新失败");
            }
        } catch (IOException e) {
            System.err.println("执行批量更新文档时出现IO异常: " + e.getMessage());
            // 在此处处理异常情况
        }
    }

    public void singleDelete(String indexName, String docId) {
        // 实现单条删除文档的逻辑,类似于之前示例中的单条删除代码
        try {
            DeleteRequest request = new DeleteRequest(indexName, docId);

            DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);

            if (response.status() == RestStatus.OK) {
                System.out.println("文档已成功删除");
            } else {
                System.err.println("无法删除文档");
            }
        } catch (IOException e) {
            System.err.println("执行单条删除文档时出现IO异常: " + e.getMessage());
            // 在此处处理异常情况
        }
    }

    public void bulkDelete(String indexName, List docIdList) {
        // 实现批量删除文档的逻辑,类似于之前示例中的批量删除代码
        try {
            BulkRequest request = new BulkRequest();

            for (String docId : docIdList) {
                request.add(new DeleteRequest(indexName, docId));
            }

            BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);

            if (response.status() == RestStatus.OK) {
                System.out.println("批量删除成功");
            } else {
                System.err.println("批量删除失败");
            }
        } catch (IOException e) {
            System.err.println("执行批量删除文档时出现IO异常: " + e.getMessage());
            // 在此处处理异常情况
        }
    }

    public void deleteByQuery(String indexName, Map query) {
        // 实现根据条件删除文档的逻辑,类似于之前示例中的 Delete By Query 代码
        try {
            // 创建 Delete By Query 请求
            DeleteByQueryRequest request = new DeleteByQueryRequest(indexName);

            // 设置查询条件
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
            for (Map.Entry entry : query.entrySet()) {
                boolQuery.must(QueryBuilders.matchQuery(entry.getKey(), entry.getValue()));
            }
            request.setQuery(boolQuery);

            // 执行 Delete By Query 请求
            DeleteByQueryResponse response = client.deleteByQuery(request, RequestOptions.DEFAULT);

            if (response.status() == RestStatus.OK) {
                System.out.println("文档删除成功");
            } else {
                System.err.println("文档删除失败");
            }
        } catch (IOException e) {
            System.err.println("执行根据条件删除文档时出现IO异常: " + e.getMessage());
            // 在此处处理异常情况
        }
    }

    // 可以添加其他操作方法,根据实际需求扩展

    public void closeClient() {
        try {
            client.close();
        } catch (IOException e) {
            System.err.println("关闭 Elasticsearch 客户端时出现异常: " + e.getMessage());
        }
    }
}

四、搜索操作

搜索操作是 Elasticsearch 的核心功能之一,它使您能够以高效的方式从大量数据中检索所需的信息。

(一)搜索辅助功能

辅助功能一:指定返回的字段

(二)搜索匹配功能

(三)按字段值排序

你可能感兴趣的:(ES相关,elasticsearch,大数据,搜索引擎)