作者:小影前端团队——小影匠
本文主要叙述对报表业务开发的一些分析思考以及怎么去解决重复开发过程的经验交流,会分两部分进行阐述。上半部分主要是我们内部如何通过自研技术手段去分析解决报表重复开发这个问题,下半部分主要就是介绍如何基于superset上进行定制化开发的经历了。
朋友你是否还在被无尽的报表业务折磨中,维度变更,口径修改,偶尔再新上线几个新产品,看似差不多功能页面,都要走一遍代码开发联调部署流程,其中滋味,有类似开发经验的同学可以感同身受。那要如何告别枯燥报表开发呢?我们先从报表需求的产生开始分析,看下能不能逐步进行优化。
一个报表的生命周期大概如下:
报表业务分析
从上面流程中我们可以看出,报表页面开发流程包括:
- 确定报表主题、指标以及维度
- 数据的获取以及包装
- 确定图表展示形态 整个开发流程需要需求方、数据组、前端互相沟通配合,就算简单报表完成周期也需要一至两天,那我们就从以上过程,一步步分解看看如何去解决优化。
确定报表主题、指标以及维度
首先每个报表分析都有三个关键要素构成:报表主题,报表指标,分析维度,报表主题一定清晰的对应着某个分析的目标,然后依次确立分析指标和维度。比如我们确定要做一个留存分析表,那么指标可以定为使用时长、使用频率、访问页面、使用间隔,接着分析维度可以由“日留存”、“周留存”、“月留存”构成三个不同的时间分析粒度。其实这时候报表的展示形态差不多也已经确定了,比如针对时间维度的比较可以用折线图很方便的进行数据横向对比,而像转化率这种可以直接使用漏斗图。
因而我们能不能把上面这个过程做成可配置的呢?比如需求方想要的是折线图的报表展示形式,通过页面后台选择报表展现形式和选择需要的展示指标,直接去生成报表页面。没错这就类似页面可视化编辑了,但我们初期不需要搞的这么复杂,页面编辑中能选能配就满足要求了。另外还有一个问题就是报表中每个模块怎么去和数据进行绑定?
数据的获取以及包装
数据的获取以及包装主要由BI同学进行负责,对于一般的报表会跑定时任务T+1形式将数据刷入到阿里云分析型数据库中,然后按照报表中指标进行SQL拼装查询字符串,进而返回想要的结果。如上如果需求方改变了口径一般就要手动去代码中调整SQL,也是很不方便。再回应上面这个问题,如何将报表中展示组件与数据源进行关联绑定,通过上面的描述我们不难发现一个实质就是将组件和SQL拼装查询建立绑定关系。
报表页面配置后台
那该如何去做呢?我们搭建了一个报表页面配置后台。主要由以下几个部分组成
- 需求管理列表页面
- 需求详情页面
- SQL拼装配置页面 简单交互流程如下图,虽然这个节约了一点开发成本,但是弊端依然挺多的,如果没有合适的基础组件依然要开发,并且数据组同学习惯了一些BI工具的使用,操作成本依旧挺高。
BI工具的二次开发
经过反复调研和比较,最后我们把思路定在定在了基于BI工具的二次开发上,一方面功能开源BI工具基本功能基本能满足业务需求,也避免了从0开发开发。另外数据组这边之前也有使用Tableau等BI工具,上手也会很快。在几款免费的开源BI中,我们最终选择了Superset去做二开,理由简单如下吧。
- 知名公司Airbnb开源,并由apache托管,项目维护也比较活跃
- 后端是基于python开发的,开源、轻量级、图表丰富
- 通过SQLAlchemy与大多数基于SQL语言的RDBMS集成,兼容市场上绝大部分数据库类型
- 细粒度高可扩展性的安全访问模型,支持主要的认证供应商(数据库、OpenID、LDAP、OAuth 等)
- 与 Druid深度集成,可以快速解析大规模数据集,很适合后续基于大数据的分析
依赖的技术栈
- python + flask
- react + ts
- sqlite3(默认) 或 mysql
项目下载及安装
Superset: github.com/apache/supe… 官方介绍文档: superset.apache.org/docs/instal… 项目基于python,因而首先需要在本地安装python,虽然写着大于3.7版本就好,但是实测过高版本后续会安装依赖失败,建议通过Homebrew安装python。 在项目主目录下找到CONTRIBUTING.md文件,里面有关于项目启动、注入管理员用户、注入样例数据、切换数据库等命令,一般执行完成后项目也就能正常启动了,具体如下:
# Create a virtual environment and activate it (recommended)
python3 -m venv venv # setup a python3 virtualenv
source venv/bin/activate
# Install external d`ependencies
pip install -r requirements/local.txt
# Install Superset in editable (development) mode
pip install -e .
# Create an admin user in your metadata database
superset fab create-admin
# Initialize the database
superset db upgrade
# Create default roles and permissions
superset init
# Load some data to play with (you must create an Admin user with the username `admin` for this command to work)
superset load-examples
# Start the Flask dev web server from inside your virtualenv.
# Note that your page may not have css at this point.
# See instructions below how to build the front-end assets.
FLASK_ENV=development superset run -p 8088 --with-threads --reload --debugger
Or you can install via our Makefile
######
项目简单介绍
主要的是superset和superset-frontend这两个目录,一个后端一个前端代码。
superset目录
- config.py 主要配置入口,像一些蛮实用功能默认都是不打开的,需要在这里面进行修改。比如查询缓存配置,图集编辑页面指标的拖拽等。
# config.py
# The SQLAlchemy connection string.
# 切换数据库类型
SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(DATA_DIR, "superset.db")
# SQLALCHEMY_DATABASE_URI = 'mysql://root:123456@localhost/superset'
# SQLALCHEMY_DATABASE_URI = 'postgresql://root:password@localhost/myapp'
- 模块业务代码主要看文件名称了,比如dashboard/就是对应了看板页面的业务代码,比如dashboard/api.py,就是具体的业务接口了,但是像一下获取页面list的接口就要到基类里面去查看了。实在找不到接口就去接口文档里面,找关键字全局搜索吧。http://localhost:8080/swagger/v1
- views/ 前端是多页面应用,少数页面的跳转和数据注入在此注册
- security/,二开过程中,如果有对权限修改的,这个目录下的代码就要好好看看了
superset-frontend目录
- 可以先看下package.json了解下项目使用了哪些依赖,主要UI库的话是Antd和@superset-ui。2. webpack-config中可以了解下项目哪些入口文件,一般router.js中找不到的就到就是后端置入数据的页面。
二次开发
主要结合其它BI工具里面的交互优点,对superset中不好用的地方进行了一波优化,主要如下
- 更换logo和名称,找到对应的一些文件更换就好了
- 接入用户第三方注册方式,superset原先是通过admin账户或有权限创建用户账号进行创建,显然不好用
- 权限优化,superset里面的权限点太具体太分散了,尤其数据集的权限,数据集多的话需要一个一个进行勾选很麻烦,因而我们进行了包装可以将多个数据集权限包装成一个权限点,再通过这个权限点去关联角色
- 看板优化,superset中所有看板都是平铺的,显然如果看板多的话,查看起来会很不方便,而且列表形式太过于后台了,因而改成了菜单目录形式 + 面板直接展示方式
- 有些优化可以先看下代码,没准只是在config.py中,默认不使用而已
菜单优化
下面简单说一下菜单优化的改造流程
原先是直接取得dashboards
中表数据,打算新增一个dashboards_category
表,在这个表中控制去处理菜单和面板的关联关系,主要以下两个字段
- dashboards_id,关联dashboards表id,若存在则为dashboards页面,否则作为文件夹
- parent_id,0为顶级菜单,否则关联此表中菜单id,构成目录数状层级结构
CREATE TABLE `dashboard_category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间',
`changed_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录更新时间',
`category_title` varchar(500) NOT NULL,
`dashboards_id` int(11) DEFAULT NULL COMMENT "关联dashboards表id,若存在则为dashboards页面,否则作为文件夹",
`parent_id` int(11) DEFAULT 0 COMMENT "0为顶级菜单,否则关联此表中其它id,构成目录层级结构",
`created_by` int(11) DEFAULT NULL,
`changed_by` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_departmentid` (`departmentid`) USING HASH,
KEY `created_by` (`created_by`),
KEY `changed_by` (`changed_by`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
因为可以在面板属性上添加角色,此角色下的用户用户查看此面板所有图集的权限,那我们要做的就是数据集管理权限的分发和回收,我们把面板里面的图集关联的数据集的权限进行整合管理,就是之前提到的数据集权限组
关于权限分配,dashboard面板,按照其配置角色进行访问控制
- 配定指定角色权限后,此面板中图集对关联角色都可访问
- 面板菜单权限,通过对底层dashboard的关联角色权限判断,自下往上判断菜单权限
dashboard中权限 分发/回收 数据集权限,链路图如下:
招贤纳士
小影前端团队,是一个年轻、活动且富有创造力的团队,隶属于小影科技开发中心,Base 在风景如画的杭州。团队在日常的业务对接之外,还在互动技术、图像渲染、跨端技术、工程化平台、性能体验、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,并一直保持好奇,持续探索前端技术。 如果你想大胆自信的表达你的想法;如果你想有个机会实现自己的想法;如果你希望落地的想法有一个团队来支撑;如果你愿意跟一群积极向上的小伙伴干一些持续迭代自己,持续提升技术能力的事;如果你相信相信的力量;那就加入我们吧!快戳链接>>>quvideo.jobs.feishu.cn/s/eV8jfyf