使用 Perceptual hashing 去除微信头像内容干扰

本文是「微信用户授权头像内容带随机干扰的问题」的延续。本文对效果进行量化,并找到一个phash库,达到了更好的效果。

实验框架

相关脚本点此

实验数据

10 组微信头像,每组 10万个头像。

准备 10万 微信头像链接,重复下载10次:

./download.sh

实验期望

期望目标:

  1. 1 个头像链接对应 1 个特征:期望特征抽取算法能够剥离微信对头像内容加入的干扰。不然使用密码学哈希算法,1 个头像链接下载 10 次可能就对应 10 个特征了。
  2. 1 个特征对应 1 个头像链接。跟哈希算法一样,希望哈希冲突尽可能小。

实验

图像降维方法

延续上文中在有限数据下得出的规则,图像降维到:32级灰度,10x10 尺寸。

python extract_feature_p2.py

echo "file,feature" > header.csv
cat header.csv download_1.csv download_2.csv download_3.csv download_4.csv download_5.csv download_6.csv download_7.csv download_8.csv download_9.csv download_10.csv > data.csv

两个指标分析如下:

csvsql --query "select avg(cnt) as expect1 from (select file, count(distinct feature) as cnt from 'data' group by file)" data.csv

expect1
2.186088754189832

csvsql --query "select avg(cnt) as expect1 from (select feature, count(distinct file) as cnt from 'data' group by feature)" data.csv

expect1
1.0051170602511927

每个头像链接,重复下载 10 次的情况下,平均有生成 2.18 个特征。

Metabase SSO 登录

探讨如何将 Metabase 融入业务系统(SaaS 服务)。

为何需要集成 Metabase 到业务系统中呢?一般,通用的数据需求都做到SaaS服务中了。而现实情况是,客户是有很多定制化数据需求的。使用 Metabase 制作报表,直接跳过前后端开发,快速满足客户需求。

(最终极地,进一步提高生产效率,把 Metabase 的组件化能力内化到 SaaS 服务中才是正道。)

试分析下 Metabase 提供的方案,以及适配我们的场景,分析该怎么改。

分析现存方案

开源版本的 Metabase 支持两种第三方登录:

  1. LDAP: Allows users within your LDAP directory to log in to Metabase with their LDAP credentials, and allows automatic mapping of LDAP groups to Metabase groups.
  2. Sign in with Google: Allows users with existing Metabase accounts to login with a Google account that matches their email address in addition to their Metabase username and password.

企业版本:

Metabase 日期筛选控件实践

Metabase Dashboard 可以是动态的,常用的是指定时间范围筛选,查看这个时间段的指标。

简单示范

使用 SAMPLE DATASET 数据库。定义一个Question:在某一时间段,订单数是多少。使用以下 SQL模板。

select count(1) FROM ORDERS
WHERE 1=1 
[[AND {{CREATED_AT}} ]]

Variables侧栏选择如下:

  1. Variable type:Field Filter。(其他选项,Text/Number/Date 都是单值,没有范围。)
  2. Field to map to:选择对应的数据表字段,这里使用ORDERS表的CREATED_AT字段。
  3. Filter widget type:Date Range。注意,只有日期类型(date/ timestamp)有这些选择。(其他选项,大同小异,都会生成对应SQL语句。)

../../images/image-20200605151107271.png

在日期控件中选择时间范围,实际执行的SQL语句如下。

select count(1) FROM ORDERS
WHERE 1=1 
AND CAST("PUBLIC"."ORDERS"."CREATED_AT" AS date) BETWEEN date '2020-06-03' AND date '2020-06-04'

打开浏览器开发者工具就能看到。

../../images/image-20200605151454671.png

可以看到,生成了这个过滤条件:CAST("PUBLIC"."ORDERS"."CREATED_AT" AS date) BETWEEN date '2020-06-03' AND date '2020-06-04'替代了。

column CREATED_AT 被转为date类型。因为日期控件的日期精度只到年月日,没有时分秒,实际使用中确实也没必要时分秒。

不同的数据库,支持的数据类型是不同的,比如Impala就不支持date类型。Metabase 用如下语句达到相同效果(由各个数据库驱动负责实现),将timestamp类型的精度截断到年月日:

CAST(from_unixtime(unix_timestamp(from_timestamp(CAST(`table`.`column` AS timestamp), 'yyyy-MM-dd'), 'yyyy-MM-dd')) AS timestamp) BETWEEN to_timestamp('2020-05-25 00:00:00', 'yyyy-MM-dd HH:mm:ss') AND to_timestamp('2020-05-31 00:00:00', 'yyyy-MM-dd HH:mm:ss') 

参考:

使用 REPL 调试 Clojure 项目(Metabase)

开发工具

Intellij IDEA + Cursive

安装 IDEA 社区版即可,并安装插件 Cursive。

../../images/image-20200604161831382.png

Cursive 插件按键冲突

比如我会用组合键⌘ + [浏览代码,与 Cursive 插件的按键冲突。可以取消 Cursive 的这个组合键。

../../images/image-20200604162732892.png

Emacs

Added 2020-07-10

参考:How to Use Emacs, an Excellent Clojure Editor

实践Metabase代码库失败:在REPL中执行(-main)直接挂了,待研究。TBD

实践

Metabase

接触 Clojure 是因为 Metabase 这个项目 https://github.com/metabase/metabase 。以 Metabase 为例,说明如何调试 Clojure 项目。

Metabase 由前后端两部分组成,后端是由 Clojure 写的 REST API 项目。启动前端工程,需要在前端界面上触发 API 请求。

记一次数据项目经历

分享下 4月、5月(特别是5月,5/1假期后基本上全身心投入)在忙的这个数据项目经历,工作面覆盖陪同拜访客户、开会、需求分析、提供方案、数据清洗、数据分析、数据基础设施的搭建开发、帮甲方IT调试代码等环节,累到头秃。

(本文刻意隐去客户信息。)

需求背景

客户需求是做一个聚合小程序(此处脑补下麦当劳的微信小程序「i麦当劳」),用于广告投放,比如微信系APP的弹屏广告。应用本身不复杂,只是罗列客户其他小程序、H5应用和一些广告链接,让用户选择。

投放效果需要数据量化,我们做了前后端的数据埋点,尽可能收集用户的行为记录。

客户花钱投广告,是为了企业销售额等指标的提升。我们也对接了客户的订单数据,多方数据进行交叉分析。

数据量化的结果,也就是数据报告,以日报、周报、月报的形式体现。

技术细节

下文就以数据的生命周期来讲,数据是怎么从毛料,到精修,最后到报表的。

数据采集

工作重点:

  1. 定义数据对接规范,或是理解别人的规范。
  2. 与自家开发做好数据对接。把握数据质量。
  3. 与甲方开发做好数据对接。把握数据质量。(为了加快数据对接速度,又是写示例代码、又是帮他们定位中文编码问题。体验真是酸爽。还是自家小伙伴靠谱。)
  4. 数据质量很重要。数据质量决定了后续工作是否需要反复。

1. 前端应用埋点

用于收集聚合小程序的用户行为记录。

整体架构还是沿用几年前的,唯一变化的就是埋点的规范,因为需求的不同而变化。基本上如下逻辑:

  1. 前端应用开发主动在代码中加入用户行为埋点。
  2. 埋点 SDK 异步地将数据上传到服务器。多台服务器通过 DNS 解析来负载均衡。
  3. WEB 服务器使用的是 openresty,有一些 lua 脚本,用于处理 cookie,和格式化存储行为日志。
  4. 之后数据通过Filebeat、Kafka、StreamSets等软件分发到Hadoop集群、实时处理任务。

../../images/image-20200512145610312.png

2. SFTP 文件同步

用于接收甲方的订单数据(二期、三期项目还有其他类型数据)。

根据双方约定时间收取文件,将文件存入Hadoop集群。

3. 微信公众号授权

客户授权后,我们获取到了公众号的粉丝关注记录(由后端开发请求微信服务器取到数据并写入Kafka集群)。同样,也存放到了Hadoop集群。

ETL 与 数据仓库

工作重点:

  1. 承上启下的工作。以方便数据分析为出发点,反过来检验数据质量。
  2. 字符串类型的时间转为时间戳类型。BI 工具需要。
  3. 基于数据金字塔模型、维度分析模型建模。
  4. 数据仓库未来可以考虑 ClickHouse。Hadoop体系数据粒度是文件,更新历史数据中的某条记录,得更新所在的整个文件!

1. ETL

经过数据采集阶段,毛料数据以文件形式存储于Hadoop集群。本阶段主要将毛料数据抽取成表(实际还是文件存储)。

技术上使用 Hive/Spark 框架写SQL。Hive SQL实在太慢了,所以一般使用Spark做清洗,Hive更多地是用其metastore组件,维护表结构信息。

因为Spark(SQL)脚本得用Python写。抽象了一个清洗脚本模板,填空:

  1. 可选填清洗前执行的SQL。比如建表DDL。
  2. 可选填毛料数据的解析schema。(直接依靠框架采样推理出schema,与实际schema比,可能缺字段,程序会崩。schema也没必要手写。一个技巧就是准备一条最全的数据记录,让Spark推理,把schema存下来使用。)
  3. 填核心的清洗逻辑。

2. 数据仓库

数据是有层次结构的。以用户行为记录为例:

Metabase Impala Driver 0528更新日志

体验过程中还是碰到不少问题。

1. TIMESTAMP 类型没有过滤器样式

现象

../../images/image-20200528173609294.png

连 SparkSQL 没这个问题。同样是TIMESTAMP类型,表现不同。

初步分析

在数据库中查看存储的字段信息,Impala/SparkSQL对比看,发现 Impala 数据库下的字段 base_type 都是 type/*。而 database_type,Impala 都是大写的,比如TIMESTAMP,而不是timestamp。所以,并不仅仅是TIMESTAMP类型没有过滤器样式。

../../images/image-20200528173915594.png

Metabase 数据库类型会映射为 Clojure类型,数据库类型的名称是大小写敏感的。所以不能复用hive-like中的实现(都是小写的),而且Hive与Impala的类型还是有些不同的。

Hive Impala的数据类型异同

以 Hive Data Types 为基准。

Type Name Type Catgory Comment Impala Support?
TINYINT Numeric Types Yes
SMALLINT Numeric Types Yes
INT Numeric Types Yes
BIGINT Numeric Types Yes
FLOAT Numeric Types Yes
DOUBLE Numeric Types Yes
DOUBLE PRECISION Numeric Types alias for DOUBLE, only available starting with Hive 2.2.0 No
DECIMAL Numeric Types Introduced in Hive 0.11.0 with a precision of 38 digitsHive 0.13.0 introduced user-definable precision and scale Yes
NUMERIC Numeric Types same as DECIMAL, starting with Hive 3.0.0 No
TIMESTAMP Date/Time Types available starting with Hive 0.8.0 Yes
DATE Date/Time Types available starting with Hive 0.12.0 No
INTERVAL Date/Time Types available starting with Hive 1.2.0 No
STRING String Types Yes
VARCHAR String Types available starting with Hive 0.12.0 Yes
CHAR String Types available starting with Hive 0.13.0 Yes
BOOLEAN Misc Types Yes
BINARY Misc Types available starting with Hive 0.8.0 No
arrays: ARRAY<data_type> Complex Types Yes
maps: MAP<primitive_type, data_type> Complex Types Yes
structs: STRUCT<col_name : data_type [COMMENT col_comment], …> Complex Types Yes
union: UNIONTYPE<data_type, data_type, …> Complex Types No

参考: