redis 的bitmap 开源包 bitmapist的应用

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

原理:http://my.oschina.net/u/1458120/blog/545224

bitmap包:https://github.com/Doist/bitmapist

要求redis>= 2.6.0 

bitmapist-master.zip  安装自己下载解压 python setup.py install

(由于包内默认连接本机redis 6379 端口 ,如果想要修改 把下载的包放到自己的项目中 修改__init__.py中

SYSTEMS = {'default': redis.Redis(host='192.168.1.3', port=6379)
}

不能运行在集群模式下,使用时最好keys *查看存过哪些key  设置过期时间
 

事件标记默认天周月

只标记天可修改__init__.py 中_mark()函数

# obj_classes = [MonthEvents, WeekEvents, DayEvents]
# obj_classes = [DayEvents]

推荐阅读:

http://www.zhihu.com/question/21581696 

(cohort analysis 同期群分析)感觉bitmapist的 cohort 讲的就是这 

声明:本文的测试大部分都是 开源中的原测试加上自己的一些理解,读者可以直接看源文

# -*- coding: utf-8 -*-
# from builtins import range
import os
import traceback
import subprocess
import atexit
import socket
import time
import pytest
from bitmapist.cohort import get_dates_datafrom bitmapist import setup_redis, delete_all_eventsfrom datetime import datetime, timedeltafrom bitmapist import mark_event, unmark_event,\MonthEvents, WeekEvents, DayEvents, HourEvents,\BitOpAnd, BitOpOr, get_event_names
from bitmapist.cohort import get_dates_data
##################################################################
#下面是启动redis服务 如果已经启动可忽略def redis_server():"""Fixture starting the Redis server"""redis_host = '192.168.15.100'redis_port = 6379if is_socket_open(redis_host, redis_port):yield Noneelse:proc = start_redis_server(redis_port)wait_for_socket(redis_host, redis_port)yield procproc.terminate()
def setup_redis_for_bitmapist():setup_redis('default', '192.168.15.100', 6379)setup_redis('default_copy', 'l92.168.8.101', 6380)def start_redis_server(port):"""Helper function starting Redis server"""devzero = open(os.devnull, 'r')devnull = open(os.devnull, 'w')#查看自己的redis-serverm命令proc = subprocess.Popen(['/usr/local/redis/bin/redis-server', '--port', str(port)],stdin=devzero, stdout=devnull, stderr=devnull,close_fds=True)#close_fds关闭子进程atexit.register(lambda: proc.terminate())return procdef is_socket_open(host, port):"""Helper function which tests is the socket open"""sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.settimeout(0.1)return sock.connect_ex((host, port)) == 0def wait_for_socket(host, port, seconds=3):"""Check if socket is up for :param:`seconds` sec, raise an error otherwise"""polling_interval = 0.1iterations = int(seconds / polling_interval)sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.settimeout(0.1)for _ in range(iterations):result = sock.connect_ex((host, port))if result == 0:sock.close()breaktime.sleep(polling_interval)else:raise RuntimeError('Service at %s:%d is unreachable' % (host, port))########################################################################################
def base_test():try:setup_redis_for_bitmapist()redis_server()#mark_event的两个重要参数now=None, track_hourly=None,# track_hourly =True标记用户小时活跃  默认只标记到月周天#now=None时指现在时间   否则 指定到特定的用户活跃时间mark_event('active', 123, track_hourly=True)now = datetime.utcnow()unmark_event('active', 124, track_hourly=True)#取消标记print MonthEvents('active', now.year, now.month).has_events_marked()print set(get_event_names(batch=2))#获取所有的事件名称set(["active"])print set(get_event_names(prefix='b', batch=2))#获取所有以b开头的事件名称set()set([])# Monthassert 123 in MonthEvents('active', now.year, now.month)assert 124 not in MonthEvents('active', now.year, now.month)# Weekassert 123 in WeekEvents('active', now.year, now.isocalendar()[1])assert 124 not in WeekEvents('active', now.year, now.isocalendar()[1])# Dayassert 123 in DayEvents('active', now.year, now.month, now.day)assert 124 not in DayEvents('active', now.year, now.month, now.day)# Hourassert 123 in HourEvents('active', now.year, now.month, now.day, now.hour)assert 124 not in HourEvents('active', now.year, now.month, now.day, now.hour)assert 124 not in HourEvents('active', now.year, now.month, now.day, now.hour-1)mark_event("active",124)#标记用户125本月活跃mark_event('active', 125)assert 125 in MonthEvents('active', now.year, now.month)#取消用户125本月活跃unmark_event('active', 125)assert 125 not in MonthEvents('active', now.year, now.month)yesterday = now - timedelta(days=1)mark_event('active', 126, now=now)mark_event('active', 127, now=yesterday)#把用户活跃标记到昨天的月周天上#获取活跃的用户数 提示错误没有bitcount命令 要求redis>= 2.6.0  info查看redis版本print MonthEvents('active', now.year, now.month).get_count()#4print list(WeekEvents('active', now.year, now.isocalendar()[1]))# [123, 124, 126, 127]print list(MonthEvents('active', now.year, now.month))#[123, 124, 126, 127]ev = DayEvents('active', now.year, now.month,now.day) # [123, 124, 126]print list(ev)#3print len(ev)#3print list(DayEvents('active',yesterday.year,yesterday.month,yesterday.day))#[127]last_month = datetime.utcnow() - timedelta(days=30)ago3_month = datetime.utcnow() - timedelta(days=60)# 123,127 128上月活跃,127 上上月活跃mark_event('active', 127, now=ago3_month)mark_event('active', 123, now=last_month)mark_event('active', 127, now=last_month)mark_event('active', 128, now=last_month)# 近三个月都活跃的用户(交集)active_3_months = BitOpAnd(MonthEvents('active', ago3_month.year, ago3_month.month),MonthEvents('active', last_month.year, last_month.month),MonthEvents('active', now.year, now.month))print list(active_3_months)#[127]active_3_months.delete()#嵌套查询active_3_months = BitOpAnd(MonthEvents('active', ago3_month.year, ago3_month.month),MonthEvents('active', last_month.year, last_month.month),BitOpAnd(MonthEvents('active', now.year, now.month)))print list(active_3_months)#[127]# 近三个月活跃过的用户(并集)print list(BitOpOr(MonthEvents('active', ago3_month.year, ago3_month.month),MonthEvents('active', last_month.year, last_month.month),MonthEvents('active', now.year, now.month)))#[123, 124, 126, 127, 128]#用备份redis查询active_2_months = BitOpAnd('default_copy',MonthEvents('active', last_month.year, last_month.month),MonthEvents('active', now.year, now.month))print list(active_2_months)active_2_months.delete()delete_all_events()#清理所有的bitmapexcept:traceback.print_exc()def test_bit_operations_complex():now = datetime.utcnow()tom = now + timedelta(days=1)mark_event('task1', 111, now=now)mark_event('task1', 111, now=tom)mark_event('task2', 111, now=now)mark_event('task2', 111, now=tom)mark_event('task1', 222, now=now)mark_event('task1', 222, now=tom)mark_event('task2', 222, now=now)mark_event('task2', 222, now=tom)now_events = BitOpAnd(DayEvents('task1', now.year, now.month, now.day),DayEvents('task2', now.year, now.month, now.day))tom_events = BitOpAnd(DayEvents('task1', tom.year, tom.month, tom.day),DayEvents('task2', tom.year, tom.month, tom.day))both_events = BitOpAnd(now_events, tom_events)print list(both_events)def test_bitop_key_sharing():#测试key共享today = datetime.utcnow()#假设task1为唱歌 task2为跳舞mark_event('task1', 111, now=today)mark_event('task2', 111, now=today)mark_event('task1', 222, now=today)mark_event('task2', 222, now=today)ev1_task1 = DayEvents('task1', today.year, today.month, today.day)ev1_task2 = DayEvents('task2', today.year, today.month, today.day)ev1_both = BitOpAnd(ev1_task1, ev1_task2)#今天即唱歌又跳舞的ev2_task1 = DayEvents('task1', today.year, today.month, today.day)ev2_task2 = DayEvents('task2', today.year, today.month, today.day)ev2_both = BitOpAnd(ev2_task1, ev2_task2)print ev1_both,ev2_bothprint ev1_both.redis_key,ev2_both.redis_keyprint  len(ev1_both), len(ev2_both)#2,2ev1_both.delete()print  len(ev1_both), len(ev2_both)#0,0 同一个查询的实例相同def test_bit_operations_magic():delete_all_events()mark_event('foo', 1)mark_event('foo', 2)mark_event('bar', 2)mark_event('bar', 3)foo = DayEvents('foo')bar = DayEvents('bar')print list(foo & bar)#交集print  list(foo | bar)#并集print  list(foo ^ bar)#异或 (foo和bar不相同的)print  list(~foo & bar)#[2]#[1, 2, 3]#[1, 3]#[3]def test_cohort():'''测试场景:当天注册用户 三天内每天有多少活跃过'''today = datetime.utcnow()#20160608yes = today - timedelta(days=1)ago2 = today - timedelta(days=2)#20160606tomorrow = today +timedelta(days=1)after2 = today +timedelta(days=2)####################################前天注册用户追踪#前天注册mark_event("regist",111,now=ago2)mark_event("regist",112,now=ago2)mark_event("regist",113,now=ago2)mark_event("regist",114,now=ago2)mark_event("regist",115,now=ago2)#前天活跃mark_event("active",111,now=ago2)mark_event("active",112,now=ago2)mark_event("active",113,now=ago2)mark_event("active",114,now=ago2)#昨天活跃的mark_event("active",111,now=yes)mark_event("active",112,now=yes)mark_event("active",113,now=yes)#今天活跃的mark_event("active",115,now=today)############################昨天注册用户追踪#昨天注册mark_event("regist",116,now=yes)mark_event("regist",117,now=yes)mark_event("regist",118,now=yes)mark_event("regist",119,now=yes)mark_event("regist",120,now=yes)#昨天活跃mark_event("active",116,now=yes)mark_event("active",117,now=yes)mark_event("active",118,now=yes)mark_event("active",119,now=yes)#今天活跃mark_event("active",119,now=today)mark_event("active",120,now=today)#明天活跃mark_event("active",116,now=tomorrow)########################################################今天注册用户追踪#今天注册mark_event("regist",121,now=today)mark_event("regist",122,now=today)mark_event("regist",123,now=today)#今天活跃mark_event("active",121,now=today)mark_event("active",122,now=today)#明天活跃mark_event("active",121,now=tomorrow)#后天活跃mark_event("active",123,now=after2)for select1,select1b,select2,select2b in [('regist', None, 'active', None)]:'''select1:初始条件 本例指注册select1b:select1的附属条件 例如中国注册用户(mark_event("registchina",123,now=today))select2:初始条件下的过滤select2b:同select1btime_group:时间跨度 `days`, `weeks`, `months`, `years`as_precent:0输出经过select过滤后的数量  1百分比num_results:time_group+num_results 得到关注的时间范围  如近三天、三周、三月 三年num_of_rows:对select1(或select1+select1b)条件下的select2(或select2+select2b)输出未来几天(周/月/年)的本例:近三天(time_group+num_results=3days)当天注册用户(select1='regist')三天内(num_of_rows=3)每天的活跃(select2='active')人数'''r = get_dates_data(select1=select1, select1b=select1b,select2=select2, select2b=select2b,time_group='days', as_precent=0,num_results=3, num_of_rows=3)print list(r)#当天注册   #当天活跃  #未来三天活跃
# [[datetime.datetime(2016, 6, 6, 6, 21, 43, 845437), 5,               4,     3, 1, 0.0],
#  [datetime.datetime(2016, 6, 7, 6, 21, 43, 845437), 5,               4,     2, 1, 0.0],
#  [datetime.datetime(2016, 6, 8, 6, 21, 43, 845437), 3,               2,     1, 1, '']]
#以6号为例  20160606 当天注册5人 4人活跃  未来三天20160607 在20160606注册的人中其中3人活跃 20160608 1人活跃 20160609 0人活跃(0.0代表有人活跃但不在20160606的注册人中 '' 代表压根没人活跃)
#redis中查找key:
#:6379> BITCOUNT trackist_regist_2016-6-7
#6379> BITCOUNT trackist_regist_W2016-27
#6379> BITCOUNT trackist_buyid_regist_2016-6
if __name__ == '__main__':test_bitop_key_sharing()delete_all_events()test_bit_operations_magic()delete_all_events()test_cohort()

 

 

转载于:https://my.oschina.net/u/1458120/blog/688739

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

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

相关文章

Django Views(视图函数)

http请求中产生两个核心对象: http请求:HttpRequest对象 http响应:HttpResponse对象 所在位置:django.http 之前我们用到的参数request就是HttpRequest 检测方法:isinstance(request,HttpRequest) 1 HttpRequest对象…

Android 4 +https(如何启动TLS1 1 and TLS1 2)

之前用的网络请求框架是鸿洋的OkHttpUtils,网络请求在5.0手机上使用https没有问题,但是最近突然使用了一个4.4的系统,就报错SSLException ....咋地咋地 然后 我们的副总给我们找一个博客,如何解决4.系统出现的这个问题&#xff0…

massCode 一款优秀的开源代码片段管理器

本文将介绍一款适合程序员使用的个人代码片段管理工具 massCode[1]。massCode小时候,也许我们每个人都会被老师要求有一个到处摘录优美句子段落的作文素材本 —— 采蜜集。不可否认,这对我们的写作水平的提高确实有很大的帮助。对开发人员来说当然也需要…

【ArcGIS Pro微课1000例】0021:Win10系统ArcGIS Pro3.0.1安装教程(附ArcGIS Pro下载)

本文讲解Win10系统上ArcGIS Pro3.0.1安装教程,附软件包下载。 文章目录 一、 软件安装步骤1. 安装.net Runtime 62. 安装ArcGIS Pro3. 安装中文语言4. 删除代理二、软件下载地址一、 软件安装步骤 [软件名称]: ArcGIS Pro 3.0.1 [软件大小]:4.33GB [安装环境]: Win 11/Win …

iOS逆向工程——非越狱调试

其实iOS的逆向分析业界已经十分成熟了,网上也有许多有趣的尝试(一步一步实现iOS微信自动抢红包(非越狱)。本文着重于如何在非越狱机器上进行调试,出于学习及总结的目的,记录于此。 本文以破解游戏梦幻西游为例,逐步讲解整个调试流…

[转]2022 Flutter 宣布发布 Windows 正式版

原文链接: https://medium.com/flutter/announcing-flutter-for-windows-6979d0d01fed 自从推出 Flutter 以来,我们一直专注于为漂亮的定制应用提供跨平台解决方案,这些应用被编译为机器代码并充分利用设备的底层图形硬件功能。 今天这一愿景…

电脑经常弹出“不支持的硬件”解决办法

电脑经常弹出“不支持的硬件”解决办法。 通过微软官方查证,这是由于以上处理器需要最新的Windows10系统才会这样子的,而大多出现该提示的都安装了Win7或是Win8.1系统。 来至微软官方的说明 此错误出现的原因是各代新处理器要求最新Windows版本以获得支持。 例如,Windows 1…

使用 Web API 上传和下载多个文件

原文作者:Jay Krishna Reddy原文链接:https://www.c-sharpcorner.com/article/upload-and-download-multiple-files-using-web-api/翻译:沙漠尽头的狼(谷歌翻译加持,文中版本使用.NET 6升级)---正文开始---…

详解T-SQL的联接机制

T-SQL的联接分三种类型: 交叉联接 ( cross join ) 内部联接 (inner join) 外部联接 (outer join) 每种联接在逻辑上经历不同的阶段,分为笛卡尔乘积、筛选、添加外部行,如图: 联接类型 阶段 交叉联接 笛卡儿乘积 内部联接…

Android FrameWork学习(一)Android 7 0系统源码下载 编译

最近计划着研究下 Android 7.0 的系统源码,之前也没做过什么记录,这次正好将学习的内容记录下来,方便以后复习巩固。 既然要学习我们的系统源码,那我们第一步要做的就是下载源码并进行编译了。 #硬件环境要求 ###1. 编译环境 按照…

【MapGIS精品教程】002:GDB本地数据库的使用

本文主要内容为MapGISGDB本地数据库的使用,包括:GDB企业管理器的认识、GDB本地数据库的创建方法、GDB本地数据库的备份和恢复。 1. GDB企业管理器的认识 GDB是地理数据的资源管理器,主要对空间数据进行有序组织与管理。 GDB数据管理包括&…

RabbitMQ学习3----运行和管理RabbitMQ

1.服务为管理 Erlang天生就是为了让应用程序无需知道对方是否存在同一台机器上即可互相通信。 Erlang节点:Erlang虚拟机的每个实例。多个Erlang应用程序可以运行在同一个节点之上。节点之间可以进行本地通信(不管他们是运行在同一台服务器之上&#xff0…

各代移动网络性能

摘自《中国元宇宙白皮书》 下载整书完整版https://www.aliyundrive.com/s/gXQvRLM22kD

EFCore高级Saas系统下单DbContext如何支持不同数据库的迁移

前言随着系统的不断开发和迭代默认的efcore功能十分强大,但是随着Saas系统的引进efcore基于表字段的多租户模式已经非常完美了,但是基于数据库的多租户也是可以用的,但是也存在缺点,缺点就是没有办法支持不同数据库,mi…

poj 1679: The Unique MST【次小生成树】

题目链接 参考博客 希望注释足够清楚。。欢迎指出不足~ #include<cstdio> #include<cstring> #include<algorithm> using namespace std;const int maxn110; const int INF0x3f3f3f3f;int n,m; int mp[maxn][maxn]; int maxlen[maxn][maxn]; //maxlen…

51. Python 数据处理(2)

1.Python 修改excel文件import xlrd import xlutils.copy excelr xlrd.open_workbook("hello.xlsx") excelw xlutils.copy.copy(excelr) sheet1 excelw.get_sheet(0) sheet1.write(3, 5, "xlutils.copy test test") excelw.save("hello.xlsx"…

人工智能十大流行算法

导读&#xff1a;本文为有志于成为数据科学家或对此感兴趣的读者们介绍最流行的机器学习算法。 作者&#xff1a;Fahim ul Haq 译者&#xff1a;刘志勇&#xff0c;策划&#xff1a;赵钰莹 来源&#xff1a;InfoQ&#xff08;ID&#xff1a;infoqchina&#xff09; 机器学习是…

Win7+Win10双系统安装全攻略

安装双系统,不仅能给你非凡的体验,还可以满足工作中因系统版本,兼容性,处理器等原因带来的不便。本文讲解Win7+Win10双系统安装全攻略,亲测可用。 1. 硬盘分区 本文讲解利用固态硬盘+机械硬盘的分区方式。 固态硬盘:为了绝对提高系统运行的速度,将固态硬盘作为双系统的…

[矩形并-扫描线-线段树]Picture

最近在补数学和几何&#xff0c;没啥好写的&#xff0c;因为已经决定每天至少写一篇了&#xff0c;今天随便拿个题水水。 题目大意&#xff1a;给你N个边平行于坐标轴的矩形&#xff0c;求它们并的周长。(N<5000) 思路&#xff1a;这个数据范围瞎暴力就过了&#xff0c;但我…

聊聊研发团队中的“人”

大家好&#xff0c;我是Z哥。汉字博大精深&#xff0c;很多时候我们可以通过拆字来更形象地理解一个词的含义。比如“团队”这个词的两个字"团"和“队”单独看也都是表示一种由多人组成的组织。再做一下拆字就是“口”“才”和“耳”“人”。前者表示一个人才如果没有…