elasticsearch在统计存储用量方面的应用

news2024/11/26 9:46:35

存储介绍

对象存储在现在的项目中应用非常广泛,主要用来存储图片、视频、音频、文件等静态资源,所有云服务厂商基本上都有对象存储,对象存储收费一般 按每月每GB收费,如七牛的0.098 元/GB/月,阿里的0.12元/GB/月。比如上个月我用了30GB那上个月的费用就是30*0.098,这里要注意的是上个月用了30G并不是到上个月结束Bucket里有30G的数据,而是指上个平均每天用量是30G。例如小明上个月每天上午传1G文件,那么上个月用量为(1+2+3+…+30)/30=15.5G,这里就引出一个新问题了,如果小明每天上午传1G文件,下午又删除了1G文件,那么上个月存储用量是多少?肯定不是0,不然不是白嫖了吗?为了不让用户白嫖可以定义每天的用量为当天Bucket出现的最大使用空间,那么小明上午上传1G,下午删除1G,当天存储最大空间为1G,当月的用量为(1+1+1…+1)/30=1G。如果要精确计算当天的最大空间,就需要在每个文件增加和删除时统计了下当前的用量,然后取一天中的最大值,如果要求不高也可以每隔一段时间统计一下用量。这里我介绍使用elasticsearch来统计每天的存储用量。

在这里插入图片描述

统计基本流程

每隔30分钟统计一下当前存储用量存入ES,主要字段如下:

租户ID统计时间大小
12023-07-10 00:00:001024
12023-07-10 00:00:302024
12023-07-10 00:00:001024

创建ES索引

PUT /bucket_size 
{
  "settings": {
    "number_of_shards": 6,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "id": {
        "type": "long"
      },
      "size": {
        "type": "long"
      },
      "tenantId": {
        "type": "long"
      },
      "time": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
      }
    }
  }
}

测试数据

{
        "id": "1",
        "tenantId": 1,
        "size": 1024,
        "time": "2023-07-17 18:00:00"
    }
    {
        "id": "2",
        "tenantId": 1,
        "size": 2048,
        "time": "2023-07-17 19:00:00"
    }
    {
        "id": "3",
        "tenantId": 1,
        "size": 1024,
        "time": "2023-07-17 10:00:00"
    }
    {
        "id": "4",
        "tenantId": 2,
        "size": 1024,
        "time": "2023-07-17 09:00:00"
    }
    {
        "id": "5",
        "tenantId": 2,
        "size": 0,
        "time": "2023-07-17 10:00:00"
    }
    {
        "id": "6",
        "tenantId": 2,
        "size": 1024,
        "time": "2023-07-17 11:11:00"
    }

查询租户每天用量

查询要求,传入租户ID,起时时间和结束时间,返回指定时间内每个租户每天的用量。

GET /bucket_size/_search
{
    "query": {
        "bool": {
            "must": [
                {
                    "terms": {
                        "tenantId": [
                            1,
                            2
                        ],
                        "boost": 1
                    }
                },
                {
                    "range": {
                        "time": {
                            "from": "2023-07-01",
                            "to": "2023-07-31",
                            "include_lower": true,
                            "include_upper": true,
                            "boost": 1
                        }
                    }
                }
            ],
            "adjust_pure_negative": true,
            "boost": 1
        }
    },
    "aggregations": {
        "tenantGroup": {
            "terms": {
                "field": "tenantId",
                "size": 10,
                "min_doc_count": 1,
                "shard_min_doc_count": 0,
                "show_term_doc_count_error": false,
                "order": [
                    {
                        "_count": "desc"
                    },
                    {
                        "_key": "asc"
                    }
                ]
            },
            "aggregations": {
                "groupDay": {
                    "date_histogram": {
                        "field": "time",
                        "format": "yyyy-MM-dd",
                        "calendar_interval": "1d",
                        "offset": 0,
                        "order": {
                            "_key": "asc"
                        },
                        "keyed": false,
                        "extended_bounds" : { 
                            "min" : "2023-07-01",
                            "max" : "2023-07-31"
                        }

                    },
                    "aggregations": {
                        "maxSize": {
                            "max": {
                                "field": "size",
                                "missing": 0 
                            }
                        }
                    }
                }
            }
        }
    }
}

结果

{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 6,
        "successful": 6,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 6,
            "relation": "eq"
        },
        "max_score": 2,
        "hits": [

            {
                "_index": "bucket_size",
                "_type": "_doc",
                "_id": "2",
                "_score": 2,
                "_source": {
                    "id": "2",
                    "tenantId": 1,
                    "size": 2048,
                    "time": "2023-07-17 19:00:00"
                }
            }
        ]
    },
    "aggregations": {
        "tenantGroup": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
                {
                    "key": 1,
                    "doc_count": 3,
                    "groupDay": {
                        "buckets": [
                            {
                                "key_as_string": "2023-07-01",
                                "key": 1688169600000,
                                "doc_count": 0,
                                "maxSize": {
                                    "value": null
                                }
                            },
                            {
                                "key_as_string": "2023-07-02",
                                "key": 1688256000000,
                                "doc_count": 0,
                                "maxSize": {
                                    "value": null
                                }
                            }
                        ]
                    }
                },
                {
                    "key": 2,
                    "doc_count": 3,
                    "groupDay": {
                        "buckets": [
                          
                            {
                                "key_as_string": "2023-07-31",
                                "key": 1690761600000,
                                "doc_count": 0,
                                "maxSize": {
                                    "value": null
                                }
                            }
                        ]
                    }
                }
            ]
        }
    }
}

使用JAVA代码实现

 public Map<Long, Map<String, Long>> getTenantSize(Long[] tenantIds, String mouthStartDate, String mouthEndDate) throws IOException {
        Map<Long, Map<String, Long>> map = new TreeMap<>();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("tenantId", Arrays.asList(tenantIds)));
        queryBuilder.must(QueryBuilders.rangeQuery("time").gte(mouthStartDate).lte(mouthEndDate));
        AggregationBuilder tenantGroup = AggregationBuilders.terms("tenantGroup").field("tenantId")
                .subAggregation(AggregationBuilders.dateHistogram("groupDay").field("time").calendarInterval(DateHistogramInterval.DAY)
                        .format(DatePattern.NORM_DATE_PATTERN).order(BucketOrder.key(true)).extendedBounds(new LongBounds(mouthStartDate,mouthEndDate))
                        .subAggregation(AggregationBuilders.max("maxSize").field("size"))
                );
        Aggregations aggregations = esClient.search(queryBuilder, tenantGroup, "bucket_size");
        Map<String, Aggregation> tenantGroupMap = aggregations.asMap();
        if (MapUtil.isNotEmpty(tenantGroupMap)) {
            tenantGroupMap.forEach((k, v) -> {
                Terms terms = (Terms) v;
                List<? extends Terms.Bucket> buckets = terms.getBuckets();
                if (CollUtil.isNotEmpty(buckets)) {
                    buckets.forEach(bucket -> {
                        Map<String, Long> daySizeMap = new TreeMap<>();
                        Map<String, Aggregation> dayGroup = bucket.getAggregations().asMap();
                        if (MapUtil.isNotEmpty(dayGroup)) {
                            dayGroup.forEach((key, value) -> {
                                ParsedDateHistogram daySizeTerms = (ParsedDateHistogram) value;
                                List<? extends Histogram.Bucket> daySizeBucket = daySizeTerms.getBuckets();
                                if (CollUtil.isNotEmpty(daySizeBucket)) {
                                    daySizeBucket.forEach(daySize -> {
                                        ParsedMax maxSize = daySize.getAggregations().get("maxSize");
                                        Long size=maxSize.getValue()!=Double.NEGATIVE_INFINITY? Double.valueOf(maxSize.getValue()).longValue():0L;
                                        daySizeMap.put(daySize.getKeyAsString(),size);
                                    });
                                }
                            });
                        }
                        map.put(Long.valueOf(bucket.getKeyAsString()), daySizeMap);
                    });

                }
            });
        }
        return map;
    }

总结

本文主要通过介绍使用elasticsearch计算存储来学习一下elasticsearch分组查询的使用以及使用JAVA代码调用elasticsearch分组查询,有以下注意事项:

  1. 如果查询7月1号到7月30号,ES中没有当天数据也要返回,这里使用了date_histogram,extended_bounds强制返回null
  2. 查询结果分组后要按时间排序
  3. 按天aggregations后再用max取当天最大的size为当天的存储用量
  4. elasticsearch分组查询比较吃内存,已经三层分组了,时间和租户数量不宜太多,不然会OOM
  5. 案例中是每隔30分钟统计一次存储,如果在30分钟内上传又删除就会被白嫖了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/782237.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s网络之(一)如何调试容器网络 nsenter

① 背景 ② 三种解决策略 最常见&#xff1a; 镜像为了保持精简化,没有安装网络命令,缺少必要的基础网络软件 ③ pod_id和container_id关系 细节&#xff1a; 一个pod内可以有多个容器,意味者可以有多个容器id说明&#xff1a; docker ps 默认容器id只有前12位案例&#x…

如何理解自动化

目录 1.如何定义自动化 2.自动化给人类带来的福利 3.如何学习自动化 4.自动化潜在的危害 1.如何定义自动化 自动化是指利用计算机、机械、电子技术和控制系统等现代科学技术手段&#xff0c;对各种工业、商业、农业和日常生活中的操作和过程进行自动控制和执行的过程。它旨在…

《博客继续更新说明》

目录 1.博客停更原因2.考研和比赛3.工作和博客题外话 1.博客停更原因 自2022.6.20起&#xff0c;本人CSDN博客断更了&#xff0c;故很多粉丝的私信没有看到&#xff0c;非常抱歉哈&#xff0c;简单叙说下这一年经历&#xff0c;当时大三后期原本想法是直接找嵌入式实习的&#…

怎样用IDEA社区版以及企业版创建spring boot项目?

Spring 的诞生是为了简化 Java 程序的开发的&#xff0c;而 Spring Boot 的诞生是为了简化 Spring 程序开发的 。 Spring Boot 翻译一下就是 Spring 脚手架&#xff0c;什么是脚手架呢&#xff1f;如下图所示&#xff1a; 盖房子的这个架子就是脚手架&#xff0c;脚手架…

脑电信号处理与特征提取——三. 脑电实验设计的原理与实例(古若雷)

三、脑电实验设计的原理与实例 被试间设计的实验结果也有可能是人员不同造成的&#xff0c;所以建议被试内设计。

【力扣每日一题】2023.7.22 柠檬水找零

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码运行结果&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 这是一道模拟题&#xff0c;我们贩卖五美元&#xff08;忒贵了&#xff09;一杯的柠檬水&#xff0c;然后只收取5,10,20面值的钞票…

API自动化测试总结

目录 Jmeter是怎么做API自动化测试的&#xff1f; Jmeter中动态参数的处理&#xff1f; 怎么判断前端问题还是后端问题&#xff1f; 详细描述下使用postman是怎么做API的测试的&#xff1f; 资料获取方法 Jmeter是怎么做API自动化测试的&#xff1f; 1、首先在JMeter里面…

57. 插入区间

题目链接&#xff1a;&#xff1a;力扣 解题思路&#xff0c;因为只插入一个新的区间&#xff0c;所以只需要找到插入的新区见的位置即可&#xff0c;如果与来的区间重叠&#xff0c;则进行合并&#xff0c; 两个区间重叠需要判断的情况比较多&#xff0c;可以判断两个区间不重…

已解决-使用Adobe Acrobat去除PDF水印

这个方法只能去带颜色的水印&#xff0c;灰色的去不了&#xff0c;等我有空时候&#xff0c;再写一篇使用PS去除水印的方法&#xff0c;也非常简单。敬请期待 安装软件 网上下载安装Adobe Acrobat Pro DC 安装Adobe PDF打印机 点击“添加打印机” 选择“我的打印机未列出”…

VCL界面组件DevExpress VCL v23.1 - 全新的Windows 11主题

DevExpress VCL是Devexpress公司旗下最老牌的用户界面套包&#xff0c;所包含的控件有&#xff1a;数据录入、图表、数据分析、导航、布局等。该控件能帮助您创建优异的用户体验&#xff0c;提供高影响力的业务解决方案&#xff0c;并利用您现有的VCL技能为未来构建下一代应用程…

RT-Thread qemu mps2-an385 bsp 移植制作 :环境搭建篇

前言 最近打算系统地研究一下 RT-Thread&#xff0c;包括 RT-Thread BSP 的移植&#xff0c;由于一直在使用 QEMU 进行一些软件功能的验证&#xff0c;qemu 支持很多的CPU 与 开发板&#xff0c;所以想移植一个新的 qemu board 到 RT-Thread&#xff0c;掌握BSP 移植的方法 当…

pytest配置文件:pytest.ini

1. 开始 pytest配置文件可以改变pytest的默认运行方式&#xff0c;它是一个固定的文件名称pytest.ini。 pytest.ini存放路径为项目的根路径。 2. 使用addopts-追加默认参数 我们每次在命令行中执行pytest命令时&#xff0c;如果参数是固定的&#xff0c;可以在pytest.ini进…

OpenCV:图像直方图计算

图像直方图为图像中像素强度的分布提供了有价值的见解。通过了解直方图&#xff0c;你可以获得有关图像对比度、亮度和整体色调分布的信息。这些知识对于图像增强、图像分割和特征提取等任务非常有用。 本文旨在为学习如何使用 OpenCV 执行图像直方图计算提供清晰且全面的指南。…

【Java基础教程】(四十三)多线程篇 · 下:深入剖析Java多线程编程:同步、死锁及经典案例——生产者与消费者,探究sleep()与wait()的差异

Java基础教程之多线程 下 &#x1f539;本节学习目标1️⃣ 线程的同步与死锁1.1 同步问题的引出2.2 synchronized 同步操作2.3 死锁 2️⃣ 多线程经典案例——生产者与消费者&#x1f50d;分析sleep()和wait()的区别&#xff1f; &#x1f33e; 总结 &#x1f539;本节学习目标…

SpringBoot Redis 配置多数据源

Redis 从入门到精通【应用篇】之SpringBoot Redis 配置多数据源 文章目录 Redis 从入门到精通【应用篇】之SpringBoot Redis 配置多数据源1.教程0. 添加依赖1. 配置多个 Redis 连接信息我们将上面的配置改造一下&#xff0c;支持Redis多数据源 2. 配置3. 创建 RedisTemplate 实…

Compose中常用的一些Modifier的扩展ui方法记录

Compose中常用的一些Modifier的扩展ui方法记录 关于防快速点击虚实分割线虚线边框阴影 关于 本篇主要记录一些开发中可能用到的常用方法的扩展记录&#xff0c;包括防快速带点击&#xff0c;画虚实线divider&#xff0c;画虚线边框&#xff0c;绘制阴影等。 防快速点击 inlin…

每天五分钟机器学习:线性回归和非线性回归之间的区别?

本文重点 在前面的课程中,我们学习了单变量线性回归模型以及多变量的线性回归模型,无论是单变量线性回归还是多变量线性回归,这二者都是一样的,都是线性的。本文我们将学习一下线性回归模型和非线性回归之间的区别和联系。 关于模型的基本区别 线性回归:线性回归就是每…

第三天 运维高级 MySQL主从复制

1.理解MySQL主从复制原理 1、master&#xff08;binlog dump thread&#xff09;主要负责Master库中有数据更新的时候&#xff0c;会按照binlog格式&#xff0c;将更新的事件类型写入到主库的binlog文件中。 2、I/O thread线程在Slave中创建&#xff0c;该线程用于请求Master&…

YApi 服务端测试新增 globalCookie ,兼容自动化触发服务端测试功能

YApi是一个开源的接口管理平台&#xff0c;它提供了丰富的接口管理和测试功能。其中&#xff0c;服务端测试是YApi的一个重要特性&#xff0c;可以帮助开发人员自动化执行接口测试。 在YApi的服务端测试中&#xff0c;新增globalCookie是一个很有用的功能。通过设置globalCook…

2023/7/23周报

目录 摘要 论文阅读 1、题目和现存问题 2、问题阐述及相关定义 3、LGDL模型框架 4、实验准备 5、实验过程 深度学习 1、GCN简单分类任务 2、文献引用数据分类案例 3、将时序型数据构建为图数据格式 总结 摘要 本周在论文阅读上&#xff0c;对基于图神经网络与深度…