跳转到主要内容

使用Redis位图实现强大的分析库。

项目描述

bitmapist

Build Status

全新! 尝试使用我们全新的独立版 bitmapist-server,它将内存效率提升了443倍,使得您的设置运行成本更低(并且更具可扩展性)。它与运行在Redis上的bitmapist完全兼容。

bitmapist:Redis强大的分析库

这个Python库使得实现实时、高度可扩展的分析成为可能,可以回答以下问题:

  • 用户123今天、这周、这个月在线了吗?
  • 用户123执行了操作“X”吗?
  • 这个月有多少用户活跃?这个小时有多少用户活跃?
  • 这个周有多少唯一用户执行了操作“X”?
  • 上周活跃的用户中还有多少%仍然活跃?
  • 上个月活跃的用户中还有多少%这个月仍然活跃?
  • 哪些用户执行了操作“X”?

这个库非常易于使用,并允许您轻松创建自己的报告。

使用Redis位图,您可以在非常小的内存量(兆字节)中存储数百万用户的操作事件。您应该小心使用大ID,因为这可能需要更多的内存。ID应该在范围[0, 2^32)内。

此外,bitmapist可以生成以下 cohort 图表:

  • 用户留存率 cohort
  • 上周有多少%的用户仍然活跃([天、周、月])?
  • 执行了操作X的用户中还有多少%也执行了操作Y(并且随着时间的推移)?
  • 还有很多其他的东西!

如果您想了解更多关于位图的信息,请阅读以下内容:

安装

可以通过以下方式轻松安装:

$ pip install bitmapist

端口

示例

设置环境

from datetime import datetime, timedelta
from bitmapist import setup_redis, delete_all_events, mark_event,\
                      MonthEvents, WeekEvents, DayEvents, HourEvents,\
                      BitOpAnd, BitOpOr

now = datetime.utcnow()
last_month = datetime.utcnow() - timedelta(days=30)

将用户123标记为活跃并且已播放歌曲

mark_event('active', 123)
mark_event('song:played', 123)

回答用户123这个月是否活跃

assert 123 in MonthEvents('active', now.year, now.month)
assert 123 in MonthEvents('song:played', now.year, now.month)
assert MonthEvents('active', now.year, now.month).has_events_marked() == True

这个周有多少用户活跃?

print(len(WeekEvents('active', now.year, now.isocalendar()[1])))

迭代本周所有活跃的用户

for uid in WeekEvents('active'):
    print(uid)

如果您对“当前事件”感兴趣,可以省略额外的now.whatever参数。事件将自动用当前时间填充。

例如,这两个调用是等效的

MonthEvents('active') == MonthEvents('active', now.year, now.month)

此外,为了统一,您可以使用from_date静态方法从任何datetime对象创建事件。

MonthEvents('active').from_date(now) == MonthEvents('active', now.year, now.month)

获取这些用户(用户ID)的列表

print(list(WeekEvents('active', now.year, now.isocalendar()[1])))

有一些特殊的方法prevnext返回“兄弟”事件,并允许您在不使用复杂的迭代器的情况下遍历事件。一个delta方法允许您“跳过”多个步骤。统一的API允许您使用所有类型的基事件(从小时到年)使用相同的代码。

current_month = MonthEvents()
prev_month = current_month.prev()
next_month = current_month.next()
year_ago = current_month.delta(-12)

每个事件对象都有period_startperiod_end方法来查找事件的时间范围。这可能对缓存值很有用,当不希望缓存“未来的事件”时。

ev = MonthEvent('active', dt)
if ev.period_end() < now:
    cache.set('active_users_<...>', len(ev))

作为新功能,每小时跟踪已禁用(为了节省内存!)要默认启用它,请执行以下操作:

import bitmapist
bitmapist.TRACK_HOURLY = True

此外,您还可以向mark_event提供额外的参数以绕过默认值:

mark_event('active', 123, track_hourly=False)

唯一事件

有时事件日期几乎没有意义,例如,过滤您的付费账户,或者在A/B测试中。为此目的有一个UniqueEvents模型。该模型只创建一个Redis密钥,并且不依赖于日期。

您可以将唯一事件与其他类型的事件结合使用。

A/B测试示例

active_today = DailyEvents('active')
a = UniqueEvents('signup_form:classic')
b = UniqueEvents('signup_form:new')

print("Active users, signed up with classic form", len(active & a))
print("Active users, signed up with new form", len(active & b))

通用过滤器示例

def premium_up(uid):
    # called when user promoted to premium
    ...
    mark_unique('premium', uid)


def premium_down(uid):
    # called when user loses the premium status
    ...
    unmark_unique('premium', uid)

active_today = DailyEvents('active')
premium = UniqueEvents('premium')

# Add extra Karma for all premium users active today,
# just because today is a special day
for uid in premium & active_today:
    add_extra_karma(uid)

为了达到两全其美,您可以在同一时间标记唯一事件和常规位图事件。

def premium_up(uid):
    # called when user promoted to premium
    ...
    mark_event('premium', uid, track_unique=True)

执行位运算

上个月活跃的用户有多少人这个月仍然活跃?

active_2_months = BitOpAnd(
    MonthEvents('active', last_month.year, last_month.month),
    MonthEvents('active', now.year, now.month)
)
print(len(active_2_months))

# Is 123 active for 2 months?
assert 123 in active_2_months

或者,您可以使用标准的Python位运算语法。

last_month_event = MonthEvents('active', last_month.year, last_month.month)
this_month_event = MonthEvents('active', now.year, now.month)
active_two_months = last_month_event & this_month_event

支持操作符 &|^~

处理嵌套位运算(想象一下你可以用它做什么 ;-))!

active_2_months = BitOpAnd(
    BitOpAnd(
        MonthEvents('active', last_month.year, last_month.month),
        MonthEvents('active', now.year, now.month)
    ),
    MonthEvents('active', now.year, now.month)
)
print(len(active_2_months))
assert 123 in active_2_months

# Delete the temporary AND operation
active_2_months.delete()

删除

如果您想永久删除任何时间段内标记的事件,可以使用 delete() 方法

last_month_event = MonthEvents('active', last_month.year, last_month.month)
last_month_event.delete()

如果您想删除所有位图事件,请使用

bitmapist.delete_all_events()

在使用位运算(例如 BitOpAnd)时,您可以(并可能应该)删除结果,除非您希望它们被缓存。有几种不同的方法可以实现这一点

active_2_months = BitOpAnd(
    MonthEvents('active', last_month.year, last_month.month),
    MonthEvents('active', now.year, now.month)
)
# Delete the temporary AND operation
active_2_months.delete()

# delete all bit operations created in runtime up to this point
bitmapist.delete_runtime_bitop_keys()

# delete all bit operations (slow if you have many millions of keys in Redis)
bitmapist.delete_temporary_bitop_keys()

位图群体

使用位图群体,您可以获取您在位图群体中保存的数据的表单和表格渲染。如果这听起来很复杂,请查看Mixpanel

以下是一个如何生成位图群体内部数据的表单和渲染的简单示例

from bitmapist import cohort

html_form = cohort.render_html_form(
    action_url='/_Cohort',
    selections1=[ ('Are Active', 'user:active'), ],
    selections2=[ ('Task completed', 'task:complete'), ]
)
print(html_form)

dates_data = cohort.get_dates_data(select1='user:active',
                                   select2='task:complete',
                                   time_group='days')

html_data = cohort.render_html_data(dates_data,
                                    time_group='days')

print(html_data)

# All the arguments should come from the FORM element (html_form)
# but to make things more clear I have filled them in directly

这将渲染类似的内容

bitmapist cohort screenshot

贡献

请参阅我们的指南这里

本地开发

我们使用Poetry进行依赖管理和打包。请参阅这里的设置说明。

安装Poetry后,您可以在虚拟环境中运行以下命令来安装依赖项

poetry install

测试

要运行我们的测试,需要确保已安装本地redis服务器。

我们使用pytest运行unittest,您可以在Poetry shell中使用以下命令运行

poetry run pytest

发布新版本

  • pyproject.toml中提升版本
  • 更新CHANGELOG
  • 使用提交消息“版本X.X.X”提交更改
  • 使用vX.X.X标记当前提交
  • 在GitHub上创建名为vX.X.X的新版本
  • GitHub Actions将为您将新版本发布到PIP

法律

版权:2012年Doist Ltd.

许可:BSD

项目详情


下载文件

下载您平台的文件。如果您不确定选择哪个,请了解安装包的更多信息。

源分发

bitmapist-3.114.tar.gz (48.3 kB 查看哈希值)

构建分发

bitmapist-3.114-py3-none-any.whl (47.6 kB 查看哈希值)

Python 3

由以下支持