Python之MongoDB数据分析及其Highcharts可视化
近期使用requests
把内部bugziila
上的bug
数据爬取了一遍,并存入了本地的MongoDB
数据库,想着对数据做些简单的可视化处理,将所有产品的bug数做一个统计和可视化,于是便有了这篇简短的文章。
MongoDB中的数据存储格式
之前爬取数据后,存入MongoDB
的数据格式如下,而我要分析的仅仅是其中的metadata.Product
{
"_id" : ObjectId("5c3ea1d3fbf7884588041acc"),
"id" : 1,
"title" : "\"Show interface dot11radio advanced\" command doesn't work",
"metadata" : {
"Status" : "已解決 (RESOLVED) 已修復 (FIXED)",
"Product" : "AP54GTSW",
"Component" : "Baseline",
"Version" : "0.1",
"Platform" : "PC Linux",
"Importance" : "P2 normal",
"Assigned" : "Wallace Peng",
"Reported_author" : "happy Hu",
"Reported" : "2004-05-11 20:32 CST",
"Modified" : "2010-08-27 15:42 CST"
},
"comments" : {
"描述" : {
"user" : "happy Hu",
"time" : "2004-05-11 20:32:24 CST",
"text" : "\"Show interface dot11radio advanced\" command doesn't work -- Happy"
},
"意見1" : {
"user" : "Wallace Peng",
"time" : "2004-05-12 21:01:56 CST",
"text" : "image 0.1rc8 fixed this bug. -- Wallace"
}
}
}
读取MongoDB数据
获取所有产品名称
首先获取所有产品名称,可以通过pymongo
库的find函数获取metadata.Product
段数据。
from pymongo import MongoClient
import os
MONGOSERVER = 'localhost:27017'
DATABASE = 'bugzilla'
COLLECTION = 'bugs'
class Analysis(object):
def __init__(self):
client = MongoClient(MONGOSERVER)
db = client[DATABASE]
self.col = db[COLLECTION]
def getAllProductsName(self):
records = self.col.find({}, {'metadata.Product':1, '_id':0})
prdoucts = [ record['metadata']['Product'] for record in records ]
prdoucts = list(set(prdoucts))
prdoucts = sorted(prdoucts, key=lambda s: s.lower())
return prdoucts
MongoClient
用来打开一个client去连接数据库,通过指定database
和collection
可以定位到数据源,再用find
函数检索出产品名称信息。以上的getAllProductsName
后面通过set
集合的方式去重,最后通过sorted
进行排序,即可获得有序的产品名称products
。
获取产品bug数
当然,我们想要的其实是产品bug数量,对于单个产品,可以通过pymongo
库的count_documents
函数获得该指定产品bug数。
def countOneProduct(self, product):
return self.col.count_documents({'metadata.Product':product})
想要获取所有的产品bug数,简单的想法当然是循环调用countOneProduct
函数,但这样会需要大量的时间,9万多条数据量需24s左右的时间。为什么这么久,因为每次执行count_documents
都需要重新遍历一遍数据库,这显然是不合适的。更好的方法是只遍历一遍数据库,然后对不同产品的bug数进行区分统计。
def countAllProducts(self):
counts = {}
records = self.col.find({}, {'metadata.Product':1, '_id':0})
prdoucts = [ record['metadata']['Product'] for record in records ]
for product in prdoucts:
if product in counts:
counts[product] += 1
else:
counts[product] = 1
counts = sorted(counts.items(), key=lambda item: item[0].lower())
return counts
以上代码段首先找出数据库每条记录的metadata.Product
信息,然后循环判别product
名称,对不同产品的出现次数进行计数,然后存入相应的字典记录counts[product]
中,总耗时约1s。
保存数据至json文件
def saveProductsIssues(self, path):
counts = self.countAllProducts()
with open(path, 'w', encoding='utf-8') as f:
f.write('{\n')
f.write(',\n'.join(['"{}":{}'.format(key, val) for key,val in counts]))
f.write('\n}')
保存数据时,需要使用utf-8
格式,否则可能出现后续可视化时的中文乱码问题。
Highcharts数据可视化
Highcharts是一款超级棒的用于web
端数据可视化的js
库,图表样式及其丰富,使用简单,强烈推荐!!!
我们要做的就是把highcharts
的js库文件下载到本地,然后拷贝一个例程,最后修改一下数据来源即可,下面是针对bug
数选择的一个图表样式对应的html
文件
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Highcharts Example</title>
<style type="text/css">
</style>
</head>
<body>
<!-- 下面是需要引入的库,包含JQuery及highcharts库 -->
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
<script src="./code/highcharts.js"></script>
<script src="./code/modules/exporting.js"></script>
<script src="./code/modules/export-data.js"></script>
<!-- 根据数据量大小修改下方的显示范围 -->
<div id="container" style="min-width: 310px; max-width: 800px; height: 600px; margin: 0 auto"></div>
<script type="text/javascript">
// 使用$.ajax导入数据,并配置Highcharts参数
$.ajax({
url: 'products.json',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function (src) {
var categories = new Array();
var data = new Array();
for (item in src){
categories.push(item)
data.push(src[item])
}
Highcharts.chart('container', {
chart: {
type: 'bar'
},
title: {
text: 'All products issues number on bugzilla'
},
subtitle: {
text: 'Source: bugzilla'
},
xAxis: {
// 更改分类
categories: categories,
title: {
text: null
}
},
yAxis: {
min: 0,
title: {
text: 'Issues',
align: 'high'
},
labels: {
overflow: 'justify'
}
},
tooltip: {
valueSuffix: ''
},
plotOptions: {
bar: {
dataLabels: {
enabled: true
}
}
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'top',
x: -40,
y: 80,
floating: true,
borderWidth: 1,
backgroundColor: ((Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'),
shadow: true
},
credits: {
enabled: false
},
series: [{
name: 'Issues Number',
// 更改数据来源
data: data
}]
});
}
}
)
</script>
</body>
</html>
以上最主要的一段代码如下,通过JQuery的ajax读取web server中的json文件,同时将json数据的key和value分离至categories
和data
$.ajax({
url: 'products.json',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function (src) {
var categories = new Array();
var data = new Array();
for (item in src){
categories.push(item)
data.push(src[item])
}
可视化效果展示
为了方便展示,我仅仅截取了一段数据,product
名称做了随机替换处理,毕竟主要还是看可视化效果嘛。
随机替换字符串
上面提到对product
名称进行随机替换处理,其代码如下:
import json
import secrets
import string
import numpy as np
with open('products.json','r',encoding='utf-8') as f:
data = json.load(f)
new = {}
for key, val in data.items():
N = np.random.randint(5,20)
key = ''.join(secrets.choice(string.ascii_uppercase + string.digits) for _ in range(N))
new[key] = val
with open('products_new.json','w',encoding='utf-8') as f:
json.dump(new, f, indent=4)
该替换方法参考以下文章:
小结
本文介绍了如何检索MongoDB
中的数据,如何将数据存入json文件,以及如何使用highcharts
实现数据可视化,最后给出了随机替换字符串的一种实现方法。
版权声明:本博客所有文章除特殊声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明出处 litreily的博客!