elasticsearch联表查询2

本文介绍如何在Elasticsearch中通过非规范化提高搜索性能。通过在文档中复制相关字段,可以避免复杂的联接操作,加快查询速度。例如,将用户姓名复制到其撰写的每篇博客文章中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文:https://www.elastic.co/guide/cn/elasticsearch/guide/current/denormalization.html


非规范化你的数据编辑

使用 Elasticsearch 得到最好的搜索性能的方法是有目的的通过在索引时进行非规范化 denormalizing。对每个文档保持一定数量的冗余副本可以在需要访问时避免进行关联。

如果我们希望能够通过某个用户姓名找到他写的博客文章,可以在博客文档中包含这个用户的姓名:

PUT /my_index/user/1
{
  "name":     "John Smith",
  "email":    "john@smith.com",
  "dob":      "1970/10/24"
}

PUT /my_index/blogpost/2
{
  "title":    "Relationships",
  "body":     "It's complicated...",
  "user":     {
    "id":       1,
    "name":     "John Smith" 
  }
}

这部分用户的字段数据已被冗余到 blogpost 文档中。

现在,我们通过单次查询就能够通过 relationships 找到用户 John 的博客文章。

GET /my_index/blogpost/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title":     "relationships" }},
        { "match": { "user.name": "John"          }}
      ]
    }
  }
}

数据非规范化的优点是速度快。因为每个文档都包含了所需的所有信息,当这些信息需要在查询进行匹配时,并不需要进行昂贵的联接操作。

### Spring Boot 中使用 Elasticsearch 进行多索引 Join 查询 在处理复杂的数据检索需求时,类似于 SQL 的查询,在 Elasticsearch 和 Spring Boot 集成环境中可以通过特定的方式实现。由于 Elasticsearch 并不直接支持传统意义上的 JOIN 操作,因此推荐采用其他策略来达到相似的效果。 #### 使用 Nested 或 Parent-Child 关系模拟 Join 对于结构化良好的文档模型,可以考虑利用 `nested` 类型字段或者 parent-child 映射关系来设计索引模式[^1]。这种方式允许在一个文档内部存储子对象数组(即嵌套),或者是定义两个独立但相互关的不同类型的文档集合之间的父子级系。 当涉及到跨不同索引的实体间的关系时,则更倾向于后者——parent-child 结构: ```java // 定义父类映射 (例如作者) @Document(indexName = "author") public class Author { @Id private String id; private String name; // getters and setters... } // 定义子类映射 (例如书籍), 设置其为 child of author @Document(indexName = "book", parent = Author.class) public class Book { @Id private String id; private String title; // other fields... // getters and setters... } ``` #### 利用 Terms Query 执行 Multi-index Search 另一种方法是在应用程序层面处理所谓的“join”,这通常意味着先从一个索引中获取所需 ID 列,再基于这些 ID 对另一个或多个目标索引发起新的查询请求。此过程可通过组合使用 terms query 来高效完成: ```java SearchRequest searchRequestAuthors = new SearchRequest("authors"); SearchSourceBuilder builderForAuthors = new SearchSourceBuilder(); builderForAuthors.query(QueryBuilders.matchAllQuery()); searchRequestAuthors.source(builderForAuthors); List<String> authorIds = extractAuthorIdsFromResponse(client.search(searchRequestAuthors, RequestOptions.DEFAULT)); if (!authorIds.isEmpty()) { SearchRequest searchBooksByAuthors = new SearchRequest("books"); SearchSourceBuilder bookQueryBuilder = new SearchSourceBuilder(); bookQueryBuilder.query(QueryBuilders.termsQuery("_id", authorIds)); searchBooksByAuthors.source(bookQueryBuilder); SearchResponse booksResponse = client.search(searchBooksByAuthors, RequestOptions.DEFAULT); processBookResults(booksResponse); } ``` 上述代码片段展示了如何首先搜索 authors 索引来获得一系列作者ID,接着把这些ID作为条件去查询 books 索引下的记录[^3]。 #### 考虑使用 Scripted Fields 动态计算连接结果 如果确实需要更加灵活地模仿 SQL-style joins 行为的话,还可以探索 scripted_fields 特性。不过需要注意的是这种方法可能会带来性能上的开销,并不适合大规模生产环境部署。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值