java postgresql插件_PostgreSQL HLL插件介绍

article/2025/10/9 1:50:33

前言

HLL是 HyperLogLog数据结构的简称。PostgresSQL通过插件的方式引入了这种新的数据类型hll。HyperLogLog是一个具有固定大小,类似于集合结构,用于可调精度的不同值计数。例如,在1280字节的hll数据结构中,它可以在很小的误差范围内估算出数百亿的不同值计数。

算法

hll可以被视为层次结构的不同集合/不同值计数算法的组合,并向上移动该层次结构的规则。为了区分上述描述算法,将其命名为以下:

♠ EMPTY

表示空集的常量值

♠ EXPLICIT

集合中确定的,唯一的,排序完整的整数列表,该列表保持一个固定的基数

♠ SPARSE

HyperLogLog是基于映射的“惰性”实现,是一种基于概率集合的数据结构。仅将非零寄存器的索引和值存储在 map中,直到非零寄存器的数量超过固定的基数。

♠ FULL

HyperLogLog是一个完全物化,基于列表的实现。它将每个寄存器的值显式存储在按寄存器索引排序的列表中。

f87fdcfe9d33312285a765d091f4a79c.png

基本概念基数计数

用来统计一个集合中不重复的元素的个数。基数计数实现

假设一个集合为Su,用列举法表示{2,3,1,4,5,9},如果此时有一个新的元素Xi=3要加入到集合Su中。如果Su中包含该元素,那么该元素将不会被加入到集合Su中,否则,加入该元素到集合中,计数值为Su,即基数值为元素的中非相同值的个数。如集合中{1,2,3,5,2},基数为4,因为2是 DV(Distinct Value),不被计算到基数中。

该实现有两个问题:当集合无限增加,元素增多时,相应的存储内存也会无限增长

当集合无线增加,元素增多,判断是否包含待加入元素的成本也将增加。

实现动机

最初扩充原始HLL算法如下:一般情况下,一个HLL占用 regwidth * 2^log2m 位存储。

典型使用中,log2m = 11 和 regwidth = 5时,将请求需要10240位或者1280个字节。即 5 2^11 = 5 2048 = 10240

还有一种就是有很多的字节

最初的HLL算法的第一个补充来自于实现1280个字节需要160个64位整数的大小。因此,如果希望在低基数下获得更高的准确性,则可以将一组明确的输入保留为64位整数的排序列表,直到达到第161个不同的值为止。这将为提供流中不同值的真实表示,同时需要相同数量的内存。 (这是EXPLICIT算法)。

第二个是不需要存储值为零的寄存器。可以简单地将一组具有非零值的寄存器表示为从索引到值的映射。该映射存储为索引值对的列表,这些索引值对是长度为log2m + regwidth的bit-packed的“short words”。 (这是SPARSE算法。)

结合这两种增强,得到了一个“promotion hierarchy”,可以对算法进行调整以提高准确性,内存或性能。

初始化和存储新的hll对象将仅分配一个小的小标记值,该值表示空集(EMPTY)。当添加前几个值时,唯一整数的排序列表存储在EXPLICIT集中。当希望停止权衡内存的准确性时,已排序列表中的值将“promoted”为基于SPARSE映射的HyperLogLog结构。最后,当有足够的寄存器时,基于映射的HLL将转换为位打包的FULL HLL结构。

自然地,EMPTY和EXPLICIT表示的基数估计是准确的,而SPARSE和FULL表示的准确性受原始HLL算法提供的保证的约束。

f87fdcfe9d33312285a765d091f4a79c.png

安装和使用HLL

解压安装包[postgres@pgserver plugin]$ ls

postgresql-hll-2.15.1 postgresql-hll-2.15.1.tar.gz

[postgres@pgserver plugin]$ cd postgresql-hll-2.15.1

[postgres@pgserver postgresql-hll-2.15.1]$ ls

CHANGELOG.md expected include Makefile REFERENCE.md src

DEVELOPER.md hll.control LICENSE README.md sql update

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

编译安装[postgres@pgserver postgresql-hll-2.15.1]$ make -j24 && make install

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

测试[postgres@pgserver postgresql-hll-2.15.1]$ psql -d postgres

psql (13.2)

Type "help" for help.

postgres=# CREATE EXTENSION hll;

CREATE EXTENSION

postgres=#

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

构建数据CREATE TABLE helloworld

(

id integer,

set hll

)

;

--- Insert an empty HLL

INSERT INTO helloworld

(id,

set

)

VALUES

(1,

hll_empty()

)

;

--- Add a hashed integer to the HLL

UPDATE

helloworld

SET

set = hll_add(set, hll_hash_integer(12345))

WHERE

id = 1

;

--- Or add a hashed string to the HLL

UPDATE

helloworld

SET

set = hll_add(set, hll_hash_text('hello world'))

WHERE

id = 1

;

--- Get the cardinality of the HLL

SELECT

hll_cardinality(set)

FROM

helloworld

WHERE

id = 1

;

postgres=# SELECT

postgres-# hll_cardinality(set)

postgres-# FROM

postgres-# helloworld

postgres-# WHERE

postgres-# id = 1

postgres-# ;

hll_cardinality

-----------------

2

(1 row)

postgres=# SELECT * FROM helloworld ;

id | set

----+------------------------------------------

1 | x128b7faaebcf97601e5541533f6046eb7f610e

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

从上面的示例中得到,首先构建了一个空的hll集合,然后向该集合中添加了两个值,那么得到的该hll的基数计数就是2。

f87fdcfe9d33312285a765d091f4a79c.png

接下来看一个更加实用的用例:

创建网站访问事实表和用户日访问表CREATE TABLE facts (

date date,

user_id integer,

activity_type smallint,

referrer varchar(255)

);

CREATE TABLE daily_uniques (

date date UNIQUE,

users hll

);

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

然后给网站访问表中插入过去1000天的访问数据(此处由于没有实际的数据,只能模拟过去1000天的数据)[postgres@pgserver ~]$ psql -d postgres -f ~/test.sql

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

查看表postgres=# SELECT count(*) FROM facts ;

count

----------

50000000

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

5000万数据

然后根据日期,对user_id进行hash处理,聚合每天用户访问网站的数据到 hll结构中。INSERT INTO daily_uniques(date, users)

SELECT date, hll_add_agg(hll_hash_integer(user_id))

FROM facts

GROUP BY 1;

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

查看表数据postgres=# SELECT count(*) FROM daily_uniques ;

count

-------

1000

(1 row)

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

只有1000行数据

现在查找一下每天hll的基数计数值postgres=# SELECT date, hll_cardinality(users) FROM daily_uniques LIMIT 10;

date | hll_cardinality

------------+-------------------

2021-02-06 | 9725.852733707077

2021-02-21 | 9725.852733707077

2021-02-02 | 9725.852733707077

2021-02-08 | 9725.852733707077

2021-02-10 | 9725.852733707077

2021-02-03 | 9725.852733707077

2021-02-14 | 9725.852733707077

2021-02-22 | 9725.852733707077

2021-02-11 | 9725.852733707077

2021-02-20 | 9725.852733707077

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

此刻,可能会想,可以用 COUNT DISTINCT做到基数统计。但是这里只能看到每天多少个唯一身份的用户访问了网站。

f87fdcfe9d33312285a765d091f4a79c.png

倘若想要查看每一周的唯一值呢?

HLL可以这样处理postgres=# SELECT hll_cardinality(hll_union_agg(users)) FROM daily_uniques WHERE date >= '2018-10-02'::date AND date <= '2018-10-08'::date;

hll_cardinality

-------------------

9725.852733707077

(1 row)

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

或者查看一年中的每个月访问情况postgres=# SELECT EXTRACT(MONTH FROM date) AS month, hll_cardinality(hll_union_agg(users))

postgres-# FROM daily_uniques

postgres-# WHERE date >= '2019-01-01' AND

postgres-# date < '2020-01-01'

postgres-# GROUP BY 1;

month | hll_cardinality

-------+-------------------

3 | 9725.852733707077

7 | 9725.852733707077

8 | 9725.852733707077

12 | 9725.852733707077

5 | 9725.852733707077

10 | 9725.852733707077

11 | 9725.852733707077

9 | 9725.852733707077

4 | 9725.852733707077

1 | 9725.852733707077

2 | 9725.852733707077

6 | 9725.852733707077

1190000039292171?utm_source=tag-newest

1190000039292171?utm_source=tag-newest

等等。因此,可以得到hll可以很好的来计算DV值,并且很快。

关于更多内容,大家可以去访问github网站来获取。

f45780c3de3916732fdc4477fda1707e.png

1190000039292171?utm_source=tag-newest


http://chatgpt.dhexx.cn/article/pdG46sd2.shtml

相关文章

DataSketches HLL Sketch module

上图是官网的介绍&#xff0c;翻译后的意思是此模块提供Apache Druid聚合器为不同的计数基于HLL sketch来自datasketches数据库。摄入的时候这个聚合器创建HLL sketch对象存储在Druid的segments中。在查询的时候sketches被读取并且被合并到一起。最后默认情况下&#xff0c;你可…

UV 统计- HLL算法(JAVA实现)

HLL是什么 HyperLogLog&#xff08;HLL&#xff09;算法经常在数据库中被用来统计某一字段的Distinct Value&#xff0c;比如Redis的HyperLogLog结构。目前在我们项目中用于UV统计。 网上有一篇大佬博文十分深入&#xff1a; https://www.jianshu.com/p/55defda6dcd2 注意&…

HTTP的Referrer Policy

客户端通过设置Referrer Policy来控制是否在请求头中告知服务端请求来源。来源信息写在生成的请求头的referer中。 注意 Referer 实际上是单词 “referrer” 的错误拼写。Referrer-Policy 这个首部并没有延续这个错误拼写。 Referrer Policy的取值&#xff1a; no-referrer 整…

接口基础-HTTP请求中的referrer和Referrer-Policy

本文将介绍一个涉及安全和隐私的http请求头中的字段—referrer&#xff0c;以及如何通过Referrer Policy去修改referrer的值或者是显示与否。 什么是referrer 当一个用户点击当前页面中的一个链接&#xff0c;然后跳转到目标页面时&#xff0c;目标页面会收到一个信息&#x…

Referrer还是Referer? 一个迷人的错误

诗人郑愁予曾经在一首诗中写道&#xff1a;我达达的马蹄是个美丽的错误&#xff0c;我不是归人&#xff0c;是个过客。而对我来说&#xff0c;十九岁之前的我&#xff0c;一样是个沉浸在诗歌中的文艺少年。十九岁之后的我&#xff0c;作为一名程序员&#xff0c;更多的是邂逅各…

HTTP系列之Referer和Referrer policy简介

文章目录 1、前言摘要2、Referer简介3、Referer安全性4、相关术语5、Referrer Policy5.1、no-referrer5.2、no-referrer-when-downgrade5.3、same-origin5.4、origin5.5、strict-origin5.6、origin-when-cross-origin5.7、strict-origin-when-cross-origin5.8、unsafe-url5.9、…

浅析HTTP请求中的referrer和Referrer-Policy

本文将介绍一个涉及安全和隐私的http请求头中的字段—referrer&#xff0c;以及如何通过Referrer Policy去修改referrer的值或者是显示与否。 什么是referrer 当一个用户点击当前页面中的一个链接&#xff0c;然后跳转到目标页面时&#xff0c;目标页面会收到一个信息&#xff…

document.referrer之隐藏来源

document.referrer document.referrer是用来获取跳转链接的来源&#xff0c;正规的解释是:referrer 属性可返回载入当前文档的文档的 URL。 实际中使用在广告相关业务中较多&#xff0c;包括推广等。 举个例子&#xff1a; 比如我们从百度中跳转到w3c&#xff0c;那我们从w3…

java referrer_JavaScript中document.referrer的用法详解

前言 在JavaScript中&#xff0c;document对象有很多属性&#xff0c;其中有3个与对网页的请求有关的属性&#xff0c;它们分别是URL、domain和referrer。 URL属性包含页面完整的URL&#xff0c;domain属性中只包含页面的域名&#xff0c;而referrer属性中则保存着链接到当前页…

meta标签的 referrer

首先&#xff0c;我先不解释&#xff0c;先看下我下面的请求数据图。 1.默认 (<meta name"referrer" content"origin"/>不写 也不 指定时) 2.origin时 3.no-referrer时 实验了这三个&#xff0c;就知道referrer的默认值和请求头的参数键值数据&…

设置referrer

1.全界面设置 所有界面挑战时携带地址origin&#xff0c;所有请求不携带地址never&#xff08;修改后记得从新启动&#xff09; <meta name"referrer" content"origin"> 2.单页面设置 vue的话可以设置一个vue-meta的插件&#xff08;暂不介绍&…

php referrer policy,Referrer Policy介绍

referer的写法是错的&#xff0c;正确的是referrer。大概是早期http规范的拼写错误&#xff0c;然后为了保持向下兼容&#xff0c;就将错就错了。 一、九种policy enum ReferrerPolicy { "", "no-referrer", "no-referrer-when-downgrade", &quo…

Referer和Referrer Policy详解

最近换了个负责网络安全的leader&#xff0c;整个部门开始网络安全整顿&#xff0c;我们负责WEB的接到通知要求防御CSRF攻击&#xff0c;设置referer白名单。之前看过一点referer相关的&#xff0c;但是了解不够深入&#xff0c;趁这次机会好好了解了一下。 1. 什么是 Referer…

Referer  是什么?

版权所属&#xff1a;SO JSON在线解析 原文地址&#xff1a;https&#xff1a;//www.sojson.com/blog/58.html 转载时必须以链接形式注明原始出处及本声明。 Referer 是 HTTP 请求header 的一部分&#xff0c;当浏览器&#xff08;或者模拟浏览器行为&#xff09;向web 服…

响应式网页设计

目录 Responsive Web Design响应式网页设计流体网格&#xff08;Fluid grid&#xff09;弹性图片&#xff08;Flexible image&#xff09;srcset和sizes属性 SVGbackground-size CSS3媒体查询&#xff08;CSS3 media query&#xff09;和断点 meta渐进增强过时控制工具Moderniz…

css 与 html5

折叠隐藏文字 快捷键&#xff1a;span*6&#xff0c;然后敲一个tap键&#xff0c;会生成6个span标签写业务style之前&#xff0c;需要先清除style的内置样式也就是在style里面写上* {margin: 0;padding: 0;}注意body的height:100vh;不要写100%弹性盒子能使子元素垂直居中的条件…

前端Vue书籍翻页功能利用turn.js来完成以及知识点(源码)

目录 下载文档开始构造方法可配置项 方法语法 事件两种方式添加事件 自动翻页loading加载功能 案例CSSbasic.css源码如下 JS里面代码太多了,直接官网下载index.html源码如下 最终效果如下 下载 下载完里面有源码,好几种翻页效果,很不错~ 官网 文档 接口文档 开始 构造方法 …

html局部翻页效果,基于Turn.js 实现翻书效果实例解析

最近项目经理我个项目练练手,其项目需求是要实现翻书效果,看到这个需求后,我真是懵了,这咋整,我可是java出身的啊,这个问题真是难住我了,后来有同事的指导,之前他曾经做过PC版的翻书效果,当时使用的是Turn.js ,查过其相关API后,整个人突然豁然开朗呀,使用Turn.js 完…

用Modernizr和Yepnope进行递归增强

Alex Sexton的yepnope.js脚本加载程序的1.0版已于上周发布&#xff0c;因此我认为这是一个向您展示如何将Yepnope与Modernizr结合使用HTML5功能而又不招致最新用户下载的绝佳时机。 -划痕的浏览器。 什么是回归增强&#xff1f; 您可能已经熟悉渐进增强的概念&#xff1a;设计…

modernizr_使用Modernizr和Yepnope进行递归增强

modernizr Alex Sexton的yepnope.js脚本加载程序的1.0版已于上周发布&#xff0c;因此我认为这是向您展示如何将Yepnope与Modernizr结合起来以利用HTML5功能而又不招致最新用户的最佳时机。 -划痕的浏览器。 什么是回归增强&#xff1f; 您可能已经熟悉渐进增强的概念&#x…