暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

使用 Elasticsearch 实现类似 MySQL 的 JOIN 查询

新智锦绣 2025-07-31
222

点击蓝字关注我们


Elasticsearch 作为 NoSQL 数据库,不直接支持传统关系型数据库(如 MySQL)的 JOIN 操作,但通过 8.18 版本引入的 ES|QL LOOKUP JOIN(技术预览)以及其他方式(如嵌套文档、父子关系),可以实现类似功能。以下以一个具体场景为例,展示实现方法。


场景描述


  • 索引:

    • users:存储用户信息(user_id, user_name)。

    • orders:存储订单信息(order_id, user_id, order_amount)

  • 目标:查询每个用户的订单信息,类似 MySQL 的

    SELECT * FROM users JOIN orders ON users.user_id = orders.user_id


    方法一:使用 ES|QL 的 LOOKUP JOIN


    1. 准备索引和数据


    创建并填充 users 和 orders 索引:

    • 创建 users 索引

      PUT users 
      {
        "mappings": {
          "properties": {
            "user_id": {
              "type""keyword"
            },
            "user_name": {
              "type""text"
            }
          }
        }
      }
      • 插入 users 数据

        POST users/_doc 
        "user_id""u1""user_name""Alice" } 
        POST users/_doc 
        "user_id""u2""user_name""Bob" } 
        • 创建 orders 索引

          PUT orders 
          {
            "mappings": {
              "properties": {
                "order_id": {
                  "type""keyword"
                },
                "user_id": {
                  "type""keyword"
                },
                "order_amount": {
                  "type""float"
                }
              }
            }
          }
          • 插入 orders 数据

            POST orders/_doc 
            "order_id""o1""user_id""u1""order_amount": 100.50 } 
            POST orders/_doc 
            "order_id""o2""user_id""u1""order_amount": 200.75 } 
            POST orders/_doc 
            "order_id""o3""user_id""u2""order_amount": 50.25 }


            2. 执行 LOOKUP JOIN 查询


            使用 ES|QL 实现关联查询:

              POST _query?format=txt 
              {
                "query"""
                
                FROM users |
                LOOKUP orders ON users.user_id = orders.user_id |
                KEEP user_id,
                user_name,
                order_id,
                order_amount ""
                "
              }


              3. 输出结果


                user_id | user_name | order_id | order_amount 
                --------|-----------|----------|------------- 
                u1 | Alice | o1 | 100.50
                u1 | Alice | o2 | 200.75
                u2 | Bob | o3 | 50.25


                4. 特点与注意事项


                • 行为:类似 MySQL 的 INNER JOIN,仅返回匹配记录。若需 LEFT JOIN 效果,需额外处理空值。

                • 适用场景:适合中小规模数据关联,快速构建跨索引查询。

                • 限制:LOOKUP JOIN 为技术预览功能,生产环境需测试稳定性。复杂嵌套字段或多对多关系可能受限。

                • 版本要求:Elasticsearch 8.18 或更高版本。


                方法二:使用嵌套文档


                1. 索引设计


                将 orders 嵌入 users 文档,使用 nested 字段类型:

                  PUT users 
                  {
                    "mappings": {
                      "properties": {
                        "user_id": {
                          "type""keyword"
                        },
                        "user_name": {
                          "type""text"
                        },
                        "orders": {
                          "type""nested",
                          "properties": {
                            "order_id": {
                              "type""keyword"
                            },
                            "order_amount": {
                              "type""float"
                            }
                          }
                        }
                      }
                    }
                  }
                  • 插入数据

                    POST users/_doc 

                    "user_id""u1"
                    "user_name""Alice"
                    "orders": [ 
                    "order_id""o1""order_amount": 100.50 }, 
                    "order_id""o2""order_amount": 200.75 } 


                    POST users/_doc 
                    {
                      "user_id""u2",
                      "user_name""Bob",
                      "orders": [{
                        "order_id""o3",
                        "order_amount": 50.25
                      }]
                    }


                    2. 查询示例


                    查询订单金额大于 100 的记录:

                      GET users/_search 
                      {
                        "query": {
                          "nested": {
                            "path""orders",
                            "query": {
                              "range": {
                                "orders.order_amount": {
                                  "gte": 100
                                }
                              }
                            }
                          }
                        }
                      }


                      3. 特点与注意事项


                      • 优点:数据存储在单一文档中,查询性能较高,适合一对多关系。

                      • 缺点:更新嵌套字段需要重写整个文档,数据量大时可能增加开销。

                      • 适用场景:数据关系稳定,更新频率较低。


                      方法三:使用父子关系


                      1. 索引设计


                      在同一索引中使用 join 字段定义父子关系:

                        PUT users_orders 
                        {
                          "mappings": {
                            "properties": {
                              "my_join_field": {
                                "type""join",
                                "relations": {
                                  "user""order"
                                }
                              },
                              "user_id": {
                                "type""keyword"
                              },
                              "user_name": {
                                "type""text"
                              },
                              "order_id": {
                                "type""keyword"
                              },
                              "order_amount": {
                                "type""float"
                              }
                            }
                          }
                        }
                        • 插入父文档(user)

                          POST users_orders/_doc/u1?routing=u1 

                          "user_id""u1"
                          "user_name""Alice"
                          "my_join_field""user"

                          • 插入子文档(order)

                            POST users_orders/_doc/o1?routing=u1 
                            {
                              "order_id""o1",
                              "user_id""u1",
                              "order_amount": 100.50,
                              "my_join_field": {
                                "name""order",
                                "parent""u1"
                              }
                            }


                            2. 查询示例


                            查询有订单金额大于 100 的用户的记录:

                              GET users_orders/_search 
                              {
                                "query": {
                                  "has_child": {
                                    "type""order",
                                    "query": {
                                      "range": {
                                        "order_amount": {
                                          "gte": 100
                                        }
                                      }
                                    }
                                  }
                                }
                              }


                              3. 特点与注意事项


                              • 优点:支持动态添加子文档,适合数据频繁更新的场景。

                              • 缺点:查询性能较嵌套文档低,分片路由需额外管理。

                              • 适用场景:需要灵活维护一对多关系的场景。


                              对比与选择建议



                              注意事项


                              1.性能优化:


                              大规模数据场景下,优先考虑嵌套文档或预聚合数据,避免频繁跨索引关联。

                              使用 LOOKUP JOIN 时,测试查询性能,确保索引规模可控。


                              2.版本要求:


                              LOOKUP JOIN 需 Elasticsearch 8.18 或更高版本。



                              关于公司

                              感谢您关注新智锦绣科技(北京)有限公司!作为 Elastic 的 Elite 合作伙伴及 EnterpriseDB 在国内的唯一代理和服务合作伙伴,我们始终致力于技术创新和优质服务,帮助企业客户实现数据平台的高效构建与智能化管理。无论您是关注 Elastic 生态系统,还是需要 EnterpriseDB 的支持,我们都将为您提供专业的技术支持和量身定制的解决方案。


                              欢迎关注我们,获取更多技术资讯和数字化转型方案,共创美好未来!

                              Elastic 微信群

                              EDB 微信群


                              发现“分享”“赞”了吗,戳我看看吧


                              文章转载自新智锦绣,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                              评论