【数据开发离谱场景记录】Hive + ES 复杂查询场景处理

场景

存在数据 :

id value
1 1001_1,1002_3,1004_5
2 1002_1, 1003_1, 1005_3
3 1001_2, 1003_3, 1004_1

查询要求:

场景1: 查询 value 前半部分 in (1001,1002 ) 且 后半部为 = 2 的数据(即 1001_2, 1002_2)

场景2:查询 value 前半部分 in (1001,1002) 且 所有的后半部分之和 > 8 (即拿id2举例 1001, 1003,1005 且 1+1+3 > 8)

相当于 在标签1的情况下 (1001_1 = 子标签(1001) + 标签值(1))

ps : 先不管为很么是这个数据结构,问就是前人留坑,到你这里已经没法改变了,但是你得把现在的需求实现,呼呼~~~~

熟话说,没有挑战就没有进步 干他

实现方式

当前的数据是存在 hive中的,value 字段为逗号分割的字符串, 查询引擎使用ES

第一步:

es 索引设计

思路:要实现同一个字段 1001_1 前半部分和后半部分分开查询,肯定要将字段拆开存为 1001 和 1 两部分,

官网寻找后 发现, es 数据类型 nested (类似map结构 {part1:'1001', part2: 1})可以支持, 定义方式:

sql 复制代码
{
  "mappings": {
    "properties": {
      "cus_field_name": { // 字段名称
        "type": "nested", // 字段类型
        "properties": {
          "value": {       // 第一部分
            "type": "keyword" 
          },
          "int_value": { // 第二部分
            "type": "integer"  
          }
        }
      }
    }
  }
}

hive 数据构建即将 逗号分割的字符串转成 map 数组的格式:

sql 复制代码
select 
COLLECT_LIST(
    NAMED_STRUCT(
      'value', split(single_str, '_')[0], -- 获取下划线前的部分,例如 '1001'
      'int_value', split(single_str, '_')[1]  -- 获取下划线后的部分并转为整数,例如 1
    )
  ) AS f_000073
  from tb
  LATERAL VIEW EXPLODE(split(f_field,',')) exploded_table AS single_str -- 先将字符串数组"炸开"成多行
  group by 
  user_id 

最终效果

sql 复制代码
[
{"value":"10006","int_value":"8"},
{"value":"10007","int_value":"1"}
]

写入es数据效果:

sql 复制代码
"cus_field_name" : 
[
 {
   "value" : "10006",
   "int_value" : "8"
},
{
   "value" : "10007",
   "int_value" : "1"
}
]

第二步 查询

场景1: 查询 value 前半部分 in (1001,1002 ) 且 后半部为 = 2 的数据(即 1001_2, 1002_2)

sql 复制代码
{ 
  "size":10, 
  "query": {
    "nested": { // 查询类型
            "path": "cus_field_name", // nested 类型的字段名称
            "query": {
              "bool": {
                "must": [
                  {
                    "terms": {
                      "cus_field_name.value": [ // 表示第一部分在 1007 和 1008 中
                        "10007",
                        "10008"
                      ]
                    }
                  },
                  {
                    "range": {
                      "f_000073.int_value": { // 并且 后面的值 = 2
                        "eq": 2
                      }
                    }
                  }
                ]
              }
            }
          }
        }
  }

场景2: 查询 value 前半部分 in (1001,1002) 且 所有的后半部分之和 > 8 (即拿id2举例 1001, 1003,1005 且 1+1+3 > 8)

需要求和 要使用到 ES 的 Agg

sql 复制代码
"aggs": {
    "docs_aggs": { // docs_aggs 自定义 聚合的名称 
      "terms": { // 表示 根据哪个字段分组 相当于 group by 的字段
        "field": "user_id.keyword", 
        "size": 10000
      },
      "aggs": {  
        "netsed_field": { // netsed_field 自定义聚合名称 
          "nested": { // 指定为 nested 类型 
            "path": "f_000073" // 指定 nested 类型字段
          },
          "aggs": { 
            "sum_int_value": { // sum_int_value 自定义聚合名称 
              "sum": { // 定义聚合方式
                "field": "f_000073.int_value" // 指定需要聚合的字段
              }
            }
          }
        }
        ,
        "sum_filter": { // 定义过滤名称 sum_filter 和 aggs 同一个层级
          "bucket_selector": { // bucket_selector 过滤方式, 该方式可以使用 aggs 上下文中自定义的字段信息,这里是 sum_int_value 
            "buckets_path": {
              "sum_value":"netsed_field.sum_int_value" // sum_value 定义参数名: 
              // netsed_field.sum_int_value 为参数的实际层级
              // sum_filter 
            },
            "script": "params.sum_value>19" // 固定写法
          }
        },
        "res":{
          "top_hits": { // 表示返回前10个
            "size": 10 
          }
        
        }
      }
     
    }
  }

查询结果展示:

需要注意的是 在 hits 中返回的数据不会根据聚合中的 params.sum_value>19 进行过滤,所以我们一般将 size 设置为0,表示 hits 中不返回数据,使用 aggregations 中返回的数据作为最终结果

sql 复制代码
{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "docs_aggs" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "183624",
          "doc_count" : 1,
          "res" : {
            "hits" : {
              "total" : {
                "value" : 1,
                "relation" : "eq"
              },
              "max_score" : 3.6376085,
              "hits" : [
                {
                  "_index" : "te_emp_tags_v4",
                  "_type" : "_doc",
                  "_id" : "183624",
                  "_score" : 3.6376085,
                  "_source" : {
                    "user_id" : "183624",
                    "f_000077" : "100119",
                    "f_000075" : "100083",
                    "f_000081" : "100090",
                    "f_000074" : "100078",
                    "f_000008" : "100026",
                    "f_000073" : [
                      {
                        "value" : "100073",
                        "int_value" : "10"
                      },
                      {
                        "value" : "100075",
                        "int_value" : "10"
                      }
                    ]
                  }
                }
              ]
            }
          },
          "netsed_field" : {
            "doc_count" : 2,
            "sum_int_value" : {
              "value" : 20.0
            }
          }
        }
      ]
    }
  }
}

以上即为当前场景的解决方案,希望对有相同场景的伙伴有帮助 , 加油 ~~~~

相关推荐
yumgpkpm1 小时前
Acceldata ODP(Open Data Platform)3.3.6.4(RHEL9)保姆级完整安装手册
大数据·人工智能·hive·hadoop·kafka·hbase·cloudera
sunxunyong2 小时前
hs2偶发连接失败问题处理
hadoop
陈年老古董5 小时前
Hive 函数学习笔记(上):单行函数与炸裂函数
hive·笔记·学习
ofoxcoding10 小时前
借助 CLAUDE.md 约束 Sonnet 5.5 多文件重构行为的提示词实践
大数据·elasticsearch·ai·重构
Elasticsearch10 小时前
隆重推出 AlertZero:让你的告警队列实现 “收件箱清零” 式管理
elasticsearch
陈年老古董10 小时前
Hive 分区表学习笔记:语法、操作、二级分区与动态分区
hive·笔记·学习
ly768910 小时前
从 TF-IDF 到 BM25:Elasticsearch 相关性评分的字段长度归一化与 boost 调参边界
java·elasticsearch·query dsl·bm25·相关性评分
SL-staff11 小时前
技术实践:将Excel自动升级为可搜索的知识节点(JVS平台实现)
mongodb·elasticsearch·知识图谱·jvs平台·语义解析·企业文档管理·excel结构化
Elasticsearch11 小时前
2026 年唯一获得端点预防与响应(EPR)满分的厂商是 Elastic
elasticsearch
计算机毕业编程指导师11 小时前
大数据毕设选题推荐:基于Hadoop+Spark全球碳排放减排策略分析与可视化系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·计算机·spark·毕业设计·碳排放减排