当前位置: 首页 > news >正文

使用 Redis 统计网站 UV 的方法

使用 Redis 统计网站 UV 的方法(概率算法)

文章目录

    • 前言
    • 思路
    • HyperLogLog
      • 使用 Redis 命令操作
      • 使用 Java 代码操作
    • HyperLogLog 实现原理及特点
    • 使用 Java 实现 HyperLogLog
    • 小结

前言

网站 UV 就是指网站的独立用户访问量Unique Visitor,即相同用户的多次访问需要去重。

思路

提到 UV 去重,猜大家都会想到Set集合类。

  • 使用Set集合是一个不错的办法,Set里面存储用户的id。每一个用户访问页面的时候,我们直接把id存入Set,最终获取Setsize即可。问题就是Set的容量需要设置多大呢?如果应用是分布式的,是否需要合并操作?第一个问题其实可以通过计算来估计,如果用户量上亿的话,存储空间也是需要非常大的;第二个问题其实可以通过 Redis、DB 等存储,如 Redis 的Set结构,DB 的唯一键。
  • 我们上面提到的 DB 也是一种解决方案,不过写入量很大时,数据库压力会比较大。用户如果很多,则row也相应的多,且可能需要对每天的数据进行分表。在用户访问量小的情况下,可以采用该处理方式。

上面两种方式虽然可以实现统计网站 UV 的功能,但是一个比较占用内存,一个比较占用数据库资源。那我们该如何规避这两个问题呢?在这里,我们就介绍另外一种实现方法,即使用 Redis 里面的HyperLogLog结构,且仅占用12k的空间。

HyperLogLog

HyperLogLog的使用比较简单,实现略复杂。我们先看一下如何利用HyperLogLog来进行页面 UV 的统计。

使用 Redis 命令操作

# 添加元素
127.0.0.1:6379> pfadd user zhangsan lisi wangwu
# 添加成功返回1,添加失败返回0
(integer) 1
# 统计数量
127.0.0.1:6379> pfcount user
# 返回现在数量
(integer) 3
# 再生成一个pfkey
127.0.0.1:6379> pfadd user2 zhangsan2 lisi2 wangwu
(integer) 1
127.0.0.1:6379> pfcount user2
(integer) 3
# pfmerge会将后面pfkey中的值合并到前面的pfkey中
127.0.0.1:6379> pfmerge user2 user
OK
# 查看merge后的user2
127.0.0.1:6379> pfcount user2
(integer) 5

使用 Java 代码操作

import org.springframework.data.redis.core.HyperLogLogOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class RedisService {@Resourceprivate RedisTemplate < String, String > redisTemplate;/*** 记录用户访问** @param user*/public long statistic(String Key, String user) {HyperLogLogOperations<String,String>hyperLogLog=redisTemplate.opsForHyperLogLog();return hyperLogLog.add(Key, user);}/*** 统计当前 UV** @return*/public long size(String Key) {HyperLogLogOperations<String,String>hyperLogLog=redisTemplate.opsForHyperLogLog();return hyperLogLog.size(Key);}/*** 删除当前 key*/public void clear(String Key) {HyperLogLogOperations < String,String>hyperLogLog=redisTemplate.opsForHyperLogLog();hyperLogLog.delete(Key);}
}

HyperLogLog 实现原理及特点

  • 原理:其实这是个概率问题。举个 Java 的例子,我们每次将一个字符串放入HyperLogLog,其实是把字符串转换成了一个值,可以把它当成hash值,将这个值转换成 2 进制,从后向前看第一个 1 出现的位置。那么 1 出现在第三个位置的时候(xxxx x100),概率是多少呢?(1/2)^3=1/8,也就是大概有八个数字进到这个数据结构时,第一个 1 曾出现在第三个的位置的可能会比较大,所以我们只需要维护一个 1 出现位置的最大值(暂且称之为max position),我们就可以知道整个HyperLogLog数量是多少了。
  • 去重:我们上面讲到hash值,其实整个算法就是将一个固定的value固定的映射成一个数字就可以解决重复的问题了。如zhangsan对应8,那么max position=4,再来一个zhangsan,还是对应8,则max position不变。
  • 特点:因为是概率问题,总会出现不准确的情况,所以你在使用HyperLogLog时,可以将user数量设置大一些,如 100W。但是其结果,有可能你看到的是不到 100W,也有可能计算出来的 UV 还比 100W 大。

使用 Java 实现 HyperLogLog

public class HyperLogLogSelf {static class BitKeeper {private int maxBits;public void random() {// 这里的随机数可以当成一个对象的hashCode。// long value = new Object().hashCode() ^ (2 << 32);long value = ThreadLocalRandom.current().nextLong(2L << 32);int bits = lowZeros(value);if (bits > this.maxBits) {this.maxBits = bits;}}/*** 低位有多少个连续0* 思路上 ≈ 倒数第一个1的位置** @param value* @return*/private int lowZeros(long value) {int i = 1;for (; i < 32; i++) {if (value >> i << i != value) {break;}}return i - 1;}}static class Experiment {private int n;private BitKeeper keeper;public Experiment(int n) {this.n = n;this.keeper = new BitKeeper();}public void work() {for (int i = 0; i < n; i++) {this.keeper.random();}}public void debug() {double v = Math.log(this.n) / Math.log(2);System.out.printf("%d %.2f %d\n", this.n, v, this.keeper.maxBits);}}public static void main(String[] args) {for (int i = 10000; i < 1000000; i += 10000) {Experiment exp = new Experiment(i);exp.work();exp.debug();}}
}

如上述代码所示,如果只有一个BitKeeper,那么精度很难控制,BitKeeper越多,则越精确,所以 Redis 在设置HyperLogLog的时候,设置了16384个桶,也就是2^14,每个桶的maxbits需要 6 个bit来存储,最大可以表示maxbits=63,于是总共占用内存就是2^14 * 6 / 8 = 12k字节。

小结

我们从应用场景开始,讲述了HyperLogLog的使用方法和实现原理,还给出了HyperLogLog的 Java 简单实现。

最后,我们在使用HyperLogLog的时候,需要注意:

  • HyperLogLog需要占用12k内存的(数据量大的时候),所以HyperLogLog不适合单独存储一个user相关的信息;
  • HyperLogLog是有一定精度损失的,可能比真实数量多,也可能比真实数量少,但基本上都在n‰(0<n<10)以内。

相关文章:

使用 Redis 统计网站 UV 的方法

使用 Redis 统计网站 UV 的方法(概率算法) 文章目录 前言思路HyperLogLog 使用 Redis 命令操作使用 Java 代码操作 HyperLogLog 实现原理及特点使用 Java 实现 HyperLogLog小结 前言 网站 UV 就是指网站的独立用户访问量Unique Visitor&#xff0c;即相同用户的多次访问需要…...

黑客工具软件大全

黑客工具软件大全100套 给大家准备了全套网络安全梓料&#xff0c;有web安全&#xff0c;还有渗透测试等等内容&#xff0c;还包含电子书、面试题、pdf文档、视频以及相关的网络安全笔记 &#x1f447;&#x1f447;&#x1f447; 《黑客&网络安全入门&进阶学习包》 &a…...

uniapp主题切换功能的第二种实现方式(scss变量+require)

在上一篇 “uniapp主题切换功能的第一种实现方式&#xff08;scss变量vuex&#xff09;” 中介绍了第一种如何切换主题&#xff0c;但我们总结出一些不好的地方&#xff0c;例如扩展性不强&#xff0c;维护起来也困难等等&#xff0c;那么接下我再给大家介绍另外一种切换主题的…...

# 蓝牙音频相关知识

蓝牙音频相关知识 文章目录 蓝牙音频相关知识1 音频源2 蓝牙音频编解码器3 一些标准4 蓝牙音频其他相关知识4.1 蓝牙版本4.2 ANC&#xff08;主动降噪&#xff09;4.3 音响相关参数4.4 音质评价4.5 HI-Fi声音特点4.6 耳机线材4.7 耳机分类4.8 IP防尘防水等级4.9 噪音与量化噪音…...

【AI作画】使用DiffusionBee with stable-diffusion在mac M1平台玩AI作画

DiffusionBee是一个完全免费、离线的工具。它简洁易用&#xff0c;你只需输入一些标签或文本描述&#xff0c;它就能生成艺术图像。 DiffusionBee下载地址 运行DiffusionBee的硬性要求&#xff1a;MacOS系统版本必须在12.3及以上 DBe安装完成后&#xff0c;去C站挑选自己喜欢…...

2 STM32库函数 之 通用同步异步收发器(USART、串口)所有函数的介绍及使用

2 STM32库函数 之 通用同步异步收发器&#xff08;USART、串口&#xff09;所有函数的介绍及使用 前言一、USART固件库函数预览二、USART固件库函数具体介绍2.1 库函数 USART_DeInit2.2 库函数 USART_Init2.2.1 USART_InitTypeDef structure2.2.2 USART_InitTypeDef 成员 USART…...

SpringCloudAlibaba整合Sentinel实现流量控制熔断降级

目录 一、概念 二、整合Sentinel控制台 三、Sentinel规则配置 四、@SentinelResource资源保护注解...

CentOS 7安装 Postgre

零、前置条件 系统CentOS 7&#xff0c;并已联网&#xff0c;已安装gcc或者g编译器&#xff0c;GNU make版本3.80或以上&#xff0c;系统有至少一个除root之外的普通用户user gcc安装-参考链接查看make命令的版本——make --version更新make版本-参考链接postgresql的使用一般…...

rpc 异步非阻塞 io 配置 线程池和队列

相关 雪崩 - 如何重试 - sla和重试风暴的双保证_个人渣记录仅为自己搜索用的博客-CSDN博客 接口耗时公式 耗时 cpu时间 io时间 线程池数量 最佳数目 1s / 平均cpu时间 * 内核数. 最大平均cpu时间 接口耗时- all外部io时间. 结合gc , linux本身其他线程, 只会还少点. …...

【Turfjs的java版本JTS】前面讲了Turfjs可以实现几何计算,空间计算的功能,如果后端要做这项功能也有类似的类库,JTS

JTS Java Topology Suite 几何计算&#xff1a; 1. 前端js就用这个 Turfjs的类库。参考网站&#xff1a; 计算两线段相交点 | Turf.js中文网 2. 后端java语言就可以用 JTS这个类库&#xff0c;参考网站&#xff1a; JTS参考网站&#xff1a; 1. https://github.com/locatio…...

从Window中先多瞥几眼

JavaFx17官方文档中有如下的描述: Window类是一个顶层窗口类,在其中可以承载场景,并与用户交互。窗口可以是Stage、PopupWindow或其他类似的顶层窗口。 JavaFX Stage类是顶级的JavaFX容器。初级阶段由平台搭建。其他Stage对象可以由应用程序构造。 许多Stage属性是只读的…...

【STM32训练—WiFi模块】第二篇、STM32驱动ESP8266WiFi模块获取天气

目录 第一部分、前言 1、获取心知天气API接口 2、硬件准备 第二部分、电脑串口助手调试WIFI模块获取天气 1、ESP8266获取天气的流程 2、具体步骤 第三部分、STM32驱动ESP8266模块获取天气数据 1、天气数据的解析 1.1、什么函数来解析天气数据&#xff1f; 2.1、解析后…...

Maven私服

Maven 私服是一种特殊的远程仓库&#xff0c;它是架设在局域网内的仓库服务&#xff0c;用来代理位于外部的远程仓库&#xff08;中央仓库、其他远程公共仓库&#xff09;。 建立了 Maven 私服后&#xff0c;当局域网内的用户需要某个构件时&#xff0c;会按照如下顺序进行请求…...

手写RPC总结篇

协议制定&#xff1a;client到server做交互的通信协议&#xff0c;比如request response 网络端点peer 难点1 : Jetty嵌入 ◆jetty Server ◆ServletContextHandler ◆ServletHolder jetty server 起到网络监听的作用ServletContextHandler注册到jetty server中ServletHolde…...

c++11 标准模板(STL)(std::ios_base)成员类型与常量

流打开模式类型 std::ios_base::openmode typedef /*implementation defined*/ openmode; static constexpr openmode app /*implementation defined*/ static constexpr openmode binary /*implementation defined*/ static constexpr openmode in /*implementation defi…...

我用 ChatGPT 写 2023 高考语文作文:全国卷(一)

【2023】新高考|卷 “好的故事&#xff0c;可以帮我们更好地表达和沟通&#xff0c;可以触动心灵、启迪智慧&#xff1a;好的故事以改变一个人的命运&#xff0c;可以展现一个民族的形象故事是有力量的。” 以上材料引发了你怎样的联想和思考&#xff1f;请写一篇文章 要求&…...

4.java转义符,javadoc 标签

java常用转义字符 在控制台&#xff0c;输入tab键&#xff0c;可以实现命令补全 (如何解决cmd中Tab键不能自动补充的问题&#xff1f;百度一下) \t : 一个制表符&#xff0c;实现对齐功能\n : 换行符\ \ : 一个\\ " &#xff1a;一个"\ ’ : 一个’\r : 一个回车 …...

PinYin4j库的使用

一、PinYin4j库简介 1、PinYin4j简介 Pinyin4j 是一个流行的 Java 库&#xff0c;支持汉字和大多数流行的拼音系统之间的转换&#xff08;汉语拼音&#xff0c;罗马拼音等&#xff09;。可自定义拼音输出格式&#xff0c;功能强大。 官网地址&#xff1a;http://pinyin4j.sou…...

日志框架 --- Logback

文章目录 1. 什么是logback2. logback的日志级别3. 日志级别的层级4. logback配置文件4.1 logger标签4.2 root标签4.3 appender标签4.4 filter标签4.5 encoder标签 5. 整体演示5.1 配置文件5.2 运行结果 1. 什么是logback Logback是一个用于Java应用程序的日志框架&#xff0c…...

QML 与 Python 交互

在 Qt 中&#xff0c;C 和 QML 交互一般有如下三种方法 上下文属性&#xff1a;setContextProperty( )向引擎注册类型&#xff1a;调用 qmlRegisterType( )QML 扩展插件&#xff1a;虽然有很大的灵活性&#xff0c;但是用 Python 创建 QML 插件比较麻烦&#xff0c;所以这种方法…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...