?? 本文章實(shí)現(xiàn)了基于MapReduce的手機(jī)瀏覽日志分析
?? 文章簡(jiǎn)介:主要包含了數(shù)據(jù)生成部分,數(shù)據(jù)處理部分,數(shù)據(jù)存儲(chǔ)部分與數(shù)據(jù)可視化部分
?? 【本文僅供參考??!非唯一答案】其中需求實(shí)現(xiàn)的方式有多種,提供的代碼并非唯一寫(xiě)法,選擇適合的方式即可。
手機(jī)日志分析需求
- 本文主要實(shí)現(xiàn)以下需求
- 編寫(xiě)數(shù)據(jù)生成器生成1G~10G大小的數(shù)據(jù),字段必須包括id,日期,手機(jī)號(hào)碼、型號(hào)、操作系統(tǒng)字段。
- 需要將手機(jī)號(hào)碼4~9為掩碼處理。
- 分析2021年、2022年操作系統(tǒng)市場(chǎng)占比、手機(jī)型號(hào)市場(chǎng)占比情況
- 分析2022年手機(jī)運(yùn)營(yíng)商市場(chǎng)占比情況
- 分析數(shù)據(jù)存儲(chǔ)到HDFS集群/ana/phone節(jié)點(diǎn)下面
- 將分析結(jié)果存儲(chǔ)到Mysql,并進(jìn)行數(shù)據(jù)可視化
數(shù)據(jù)生成工具類
- 手機(jī)號(hào)碼隨機(jī)生成
- 可以采用隨機(jī)數(shù)生成的方式,結(jié)合三大運(yùn)營(yíng)商的號(hào)碼前三位數(shù)為規(guī)則進(jìn)行生成 代碼如下
/**
* @Description 生成三大運(yùn)營(yíng)商的手機(jī)號(hào)
*/
/**
* 中國(guó)移動(dòng)手機(jī)號(hào)段:
* 134、135、136、137、138、139、147、150、151、152、157、158、159、172、178、182、183、184、187、188、198、1703、1705、1706
* 中國(guó)聯(lián)通手機(jī)號(hào)段:
* 130、131、132、145、155、156、166、171、175、176、185、186、1704、1707、1708、1709
* 中國(guó)電信手機(jī)號(hào)段:
* 133、153、173、177、180、181、189、191、193、199、1700、1701、1702
* 騰訊云API https://market.cloud.tencent.com/products/31101
*/
public class PhoneNumberGenerator {
//生成一萬(wàn)個(gè)手機(jī)號(hào)碼,只需將 generatePhoneNumbers 方法中的參數(shù) count 修改為 10000 即可
//移動(dòng)
private static final String[] CHINA_MOBILE_PREFIX = {"134", "139", "150", "151", "182"};
//聯(lián)通
private static final String[] CHINA_UNICOM_PREFIX = {"130","155","186"};
//電信
private static final String[] CHINA_TELECOM_PREFIX = {"133","153","180","181","189"};
public static void main(String[] args) {
String phoneNumbers = generatePhoneNumbers(1);
System.out.println(phoneNumbers);
}
public static String generatePhoneNumbers(int count) {
String phoneNumber=null;
Random random = new Random();
for (int i = 0; i < count; i++) {
String prefix;
int operatorIndex = random.nextInt(3);
switch (operatorIndex) {
case 0:
prefix = CHINA_MOBILE_PREFIX[random.nextInt(CHINA_MOBILE_PREFIX.length)];
break;
case 1:
prefix = CHINA_UNICOM_PREFIX[random.nextInt(CHINA_UNICOM_PREFIX.length)];
break;
default:
prefix = CHINA_TELECOM_PREFIX[random.nextInt(CHINA_TELECOM_PREFIX.length)];
}
phoneNumber = prefix + generateRandomNumber(random, 11 - prefix.length());
}
return replaceCharacters(phoneNumber,3,8);
}
private static String replaceCharacters(String input, int startIndex, int endIndex) {
if (input == null || input.length() < endIndex) {
return input;
}
StringBuilder sb = new StringBuilder(input);
for (int i = startIndex; i <= endIndex; i++) {
sb.setCharAt(i, '*');
}
return sb.toString();
}
private static String generateRandomNumber(Random random, int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(random.nextInt(10));
}
return sb.toString();
}
}
- 運(yùn)營(yíng)商解析的其中一種方式 【采用接口分析】
- 這里可以使用鵝廠或者其他廠商開(kāi)發(fā)的接口進(jìn)行運(yùn)營(yíng)商識(shí)別 申請(qǐng)獲取對(duì)應(yīng)的秘鑰即可 例子如下
public class PhoneOperator {
public static String calcAuthorization(String source, String secretId, String secretKey, String datetime)
throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {
String signStr = "x-date: " + datetime + "\n" + "x-source: " + source;
Mac mac = Mac.getInstance("HmacSHA1");
Key sKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), mac.getAlgorithm());
mac.init(sKey);
byte[] hash = mac.doFinal(signStr.getBytes("UTF-8"));
String sig = new BASE64Encoder().encode(hash);
String auth = "hmac id=\"" + secretId + "\", algorithm=\"hmac-sha1\", headers=\"x-date x-source\", signature=\"" + sig + "\"";
return auth;
}
public static String urlencode(Map<?, ?> map) throws UnsupportedEncodingException {
StringBuilder sb = new StringBuilder();
for (Map.Entry<?, ?> entry : map.entrySet()) {
if (sb.length() > 0) {
sb.append("&");
}
sb.append(String.format("%s=%s",
URLEncoder.encode(entry.getKey().toString(), "UTF-8"),
URLEncoder.encode(entry.getValue().toString(), "UTF-8")
));
}
return sb.toString();
}
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {
//云市場(chǎng)分配的密鑰Id
String secretId = "xx";
//云市場(chǎng)分配的密鑰Key
String secretKey = "xx;
String source = "market";
Calendar cd = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String datetime = sdf.format(cd.getTime());
// 簽名
String auth = calcAuthorization(source, secretId, secretKey, datetime);
// 請(qǐng)求方法
String method = "POST";
// 請(qǐng)求頭
Map<String, String> headers = new HashMap<String, String>();
headers.put("X-Source", source);
headers.put("X-Date", datetime);
headers.put("Authorization", auth);
// 查詢參數(shù)
Map<String, String> queryParams = new HashMap<String, String>();
queryParams.put("mobile","XXX");
// body參數(shù)
Map<String, String> bodyParams = new HashMap<String, String>();
// url參數(shù)拼接
String url = "https://service-8c43o60c-1253285064.gz.apigw.tencentcs.com/release/sms";
if (!queryParams.isEmpty()) {
url += "?" + urlencode(queryParams);
}
BufferedReader in = null;
try {
URL realUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestMethod(method);
// request headers
for (Map.Entry<String, String> entry : headers.entrySet()) {
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
// request body
Map<String, Boolean> methods = new HashMap<>();
methods.put("POST", true);
methods.put("PUT", true);
methods.put("PATCH", true);
Boolean hasBody = methods.get(method);
if (hasBody != null) {
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setDoOutput(true);
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
out.writeBytes(urlencode(bodyParams));
out.flush();
out.close();
}
// 定義 BufferedReader輸入流來(lái)讀取URL的響應(yīng)
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
String result = "";
while ((line = in.readLine()) != null) {
result += line;
}
System.out.println(result);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
結(jié)果如下 (另一種方式為:直接根據(jù)前三位手機(jī)號(hào)進(jìn)行判斷)
模擬數(shù)據(jù)生成類
- 數(shù)據(jù)生成器 id,日期,手機(jī)號(hào)碼、型號(hào)、操作系統(tǒng)
/**
* @Description
* 數(shù)據(jù)生成器 id,日期,手機(jī)號(hào)碼、型號(hào)、操作系統(tǒng)
* id:UUID 隨機(jī)生成 日期:2021 2022 手機(jī)號(hào)碼:三大運(yùn)營(yíng)商 型號(hào):Apple HuaWei Oppo Vivo Meizu Nokia 操作系統(tǒng):Apple ios Harmony Samsung
* 1.分析2021年、2022年操作系統(tǒng)市場(chǎng)占比、手機(jī)型號(hào)市場(chǎng)占比情況
* 2.分析2022年手機(jī)運(yùn)營(yíng)商市場(chǎng)占比情況
* 3.分析數(shù)據(jù)存儲(chǔ)到HDFS集群/ana/phone節(jié)點(diǎn)下面
* 4.將分析結(jié)果存儲(chǔ)到Mysql,并進(jìn)行數(shù)據(jù)可視化
*/
public class DataGenerator {
public static void main(String[] args) {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter("data/phone.log"));
for (int i = 0; i < 1000; i++) {
//UUID隨機(jī)生成 id,日期,手機(jī)號(hào)碼、型號(hào)、操作系統(tǒng)
String id = UUID.randomUUID().toString();
String date = getRandomDate();
String phoneNumber = PhoneNumberGenerator.generatePhoneNumbers(1);
String model = getRandomModel();
String operatingSystem = getRandomOperatingSystem();
String line = id + "," + date + "," + phoneNumber + "," + model + "," + operatingSystem;
writer.write(line);
writer.newLine();
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static String getRandomDate() {
Random random = new Random();
int year = random.nextInt(2) == 0 ? 2021 : 2022;
int month = random.nextInt(12) + 1;
int dayOfMonth;
if (month == 2) {
dayOfMonth = random.nextInt(28) + 1;
} else if (month == 4 || month == 6 || month == 9 || month == 11) {
dayOfMonth= random.nextInt(30) + 1;
} else {
dayOfMonth= random.nextInt(31) + 1;
}
return year + "-" +
(month < 10 ? "0" : "") +
month+ "-" +
(dayOfMonth<10? "0":"")+
dayOfMonth ;
}
private static String getRandomPhoneNumber() {
Random random = new Random();
StringBuilder phoneNumber = new StringBuilder("1");
for (int i = 0; i < 10; i++) {
phoneNumber.append(random.nextInt(10));
}
return phoneNumber.toString();
}
private static String getRandomModel() {
String[] models = {"Apple", "HuaWei", "Oppo", "Vivo", "Meizu", "Nokia"};
return models[new Random().nextInt(models.length)];
}
private static String getRandomOperatingSystem() {
String[] operatingSystems = {"Apple", "HarmonyOS", "Samsung","iOS"};
return operatingSystems[new Random().nextInt(operatingSystems.length)];
}
}
結(jié)果如下
MapReduce程序需求編寫(xiě)
- 分析2021年、2022年操作系統(tǒng)市場(chǎng)占比、手機(jī)型號(hào)市場(chǎng)占比情況
/**
* @Description
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class PhoneOSAnalysis {
private static int totalCount;
private static int lineCount2021 = 0;
private static int lineCount2022 = 0;
public static class TokenizerMapper extends Mapper<Object, Text, Text, DoubleWritable> {
private final static DoubleWritable one = new DoubleWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
String[] fields = value.toString().split(",");
if (fields.length >= 5) {
// 操作系統(tǒng)市場(chǎng)占比
word.set(fields[1].substring(0, 4) + "-OS-" + fields[4]);
context.write(word, one);
// 手機(jī)型號(hào)市場(chǎng)占比
word.set(fields[1].substring(0, 4) + "-Model-" + fields[3]);
context.write(word, one);
}
}
}
public static class MarketShareReducer extends Reducer<Text, DoubleWritable, Text, DoubleWritable> {
private DoubleWritable result = new DoubleWritable();
public void reduce(Text key, Iterable<DoubleWritable> values, Context context)
throws IOException, InterruptedException {
double sum = 0;
for (DoubleWritable val : values) {
//這里會(huì)根據(jù)分組的key來(lái)計(jì)算sum
sum += val.get();
}
int yearTotalCount = key.toString().contains("2021") ? lineCount2021 : lineCount2022;
double percentage = sum / yearTotalCount;
result.set(percentage);
context.write(key, result);
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path inputPath = new Path("data/phone.log");
FSDataInputStream inputStream = fs.open(inputPath);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(fs.open(inputPath)))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("2021")) {
lineCount2021++;
} else if (line.contains("2022")) {
lineCount2022++;
}
}
}
// totalCount = Math.max(lineCount2021, lineCount2022);
Job job = Job.getInstance(conf, "market share analysis");
job.setJarByClass(PhoneOSAnalysis.class);
job.setMapperClass(TokenizerMapper.class);
// 設(shè)置自定義分區(qū)器
job.setPartitionerClass(CustomPartitioner.class);
job.setNumReduceTasks(2);
job.setReducerClass(MarketShareReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(DoubleWritable.class);
Path outputPath = new Path("data/result");
if (fs.exists(outputPath)) {
fs.delete(outputPath, true);
}
FileInputFormat.addInputPath(job, new Path("data/phone.log"));
FileOutputFormat.setOutputPath(job, new Path(String.valueOf(outputPath)));
// TextInputFormat.addInputPath(job, new Path("hdfs://192.168.192.100:8020/"));
// TextInputFormat.outInputPath(job, new Path("hdfs://192.168.192.100:8020/"));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
public static class CustomPartitioner extends Partitioner<Text, DoubleWritable> {
@Override
public int getPartition(Text key, DoubleWritable value, int numPartitions) {
// 根據(jù)年份進(jìn)行分區(qū)
if (key.toString().contains("2021")) {
return 0;
} else {
return 1;
}
}
}
}
- 分析2022年手機(jī)運(yùn)營(yíng)商市場(chǎng)占比情況
/**
* @Description
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class OperatorMR {
private static int lineCount2022 = 0;
public static class TokenizerMapper extends Mapper<Object, Text, Text, DoubleWritable> {
private final static DoubleWritable one = new DoubleWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
String[] fields = value.toString().split(",");
if (fields.length >= 3 && fields[1].contains("2022")) {
// 手機(jī)運(yùn)營(yíng)商市場(chǎng)占比
word.set(fields[1].substring(0, 4) + "-Operator-" + getCarrier(fields[2]));
context.write(word, one);
}
}
private String getCarrier(String phoneNumber) {
String prefix = phoneNumber.substring(0, 3);
switch (prefix) {
//"133","153","180","181","189"
case "133":
case "153":
case "180":
case "181":
case "189":
return "電信";
//"130","155","186"
case "130":
case "155":
case "186":
return "聯(lián)通";
default:
return "移動(dòng)";
}
}
}
public static class MarketShareReducer extends Reducer<Text, DoubleWritable, Text, DoubleWritable> {
private DoubleWritable result = new DoubleWritable();
public void reduce(Text key, Iterable<DoubleWritable> values, Context context)
throws IOException, InterruptedException {
double sum = 0;
for (DoubleWritable val : values) {
sum += val.get();
}
double percentage = sum / lineCount2022;
result.set(percentage);
context.write(key, result);
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path inputPath = new Path("data/phone.log");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(fs.open(inputPath)))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("2022")) {
lineCount2022++;
}
}
}
Job job = Job.getInstance(conf, "PhoneOperator");
job.setJarByClass(OperatorMR.class);
job.setMapperClass(TokenizerMapper.class);
job.setReducerClass(MarketShareReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(DoubleWritable.class);
Path outputPath = new Path("data/result-phone");
if (fs.exists(outputPath)) {
fs.delete(outputPath, true);
}
// TextInputFormat.addInputPath(job, new Path("hdfs://192.168.192.100:8020/"));
// TextInputFormat.outInputPath(job, new Path("hdfs://192.168.192.100:8020/"));
FileInputFormat.addInputPath(job, new Path("data/phone.log"));
FileOutputFormat.setOutputPath(job, outputPath);
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
結(jié)果如下
-將分析結(jié)果存儲(chǔ)到Mysql,并進(jìn)行數(shù)據(jù)可視化
package com.yopai.mrmysql;
/**
* @Description
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.db.DBConfiguration;
import org.apache.hadoop.mapreduce.lib.db.DBOutputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
public class OPMysqlMR {
private static int lineCount2022 = 0;
public static class TokenizerMapper extends Mapper<Object, Text, Text, DoubleWritable> {
private final static DoubleWritable one = new DoubleWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
String[] fields = value.toString().split(",");
if (fields.length >= 3 && fields[1].contains("2022")) {
// 手機(jī)運(yùn)營(yíng)商市場(chǎng)占比
word.set(fields[1].substring(0, 4) + "-Operator-" + getCarrier(fields[2]));
context.write(word, one);
}
}
private String getCarrier(String phoneNumber) {
String prefix = phoneNumber.substring(0, 3);
switch (prefix) {
case "133":
case "153":
case "180":
case "181":
case "189":
return "電信";
case "130":
case "155":
case "186":
return "聯(lián)通";
default:
return "移動(dòng)";
}
}
}
public static class MarketShareReducer extends Reducer<Text, DoubleWritable, DBOutputWritable, NullWritable> {
private DoubleWritable result = new DoubleWritable();
public void reduce(Text key, Iterable<DoubleWritable> values, Context context)
throws IOException, InterruptedException {
double sum = 0;
for (DoubleWritable val : values) {
sum += val.get();
}
double percentage = sum / lineCount2022;
result.set(percentage);
context.write(new DBOutputWritable(key.toString(), result.get()), NullWritable.get());
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
// 設(shè)置數(shù)據(jù)庫(kù)連接信息
String dbUrl = "jdbc:mysql://localhost:3306/blog";
String dbUsername = "root";
String dbPassword = "Admin2022!";
DBConfiguration.configureDB(conf, "com.mysql.jdbc.Driver", dbUrl, dbUsername, dbPassword);
try (Connection connection = DriverManager.getConnection(dbUrl, dbUsername, dbPassword)) {
String createTableSql = "CREATE TABLE IF NOT EXISTS operator_market_share(operator VARCHAR(255), market_share DOUBLE)";
PreparedStatement preparedStatement = connection.prepareStatement(createTableSql);
preparedStatement.executeUpdate();
}
FileSystem fs = FileSystem.get(conf);
Path inputPath = new Path("data/phone.log");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(fs.open(inputPath)))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("2022")) {
lineCount2022++;
}
}
}
Job job = Job.getInstance(conf, "PhoneOperator");
job.setJarByClass(OPMysqlMR.class);
job.setMapperClass(TokenizerMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(DoubleWritable.class);
job.setReducerClass(MarketShareReducer.class);
job.setOutputKeyClass(DBOutputWritable.class);
job.setOutputValueClass(NullWritable.class);
// 設(shè)置數(shù)據(jù)庫(kù)輸出
DBOutputFormat.setOutput(job, "operator_market_share", "operator", "market_share");
FileInputFormat.addInputPath(job, new Path("data/phone.log"));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
package com.yopai.mrmysql;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.mapred.lib.db.DBWritable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @Description
*/
public class DBOutputWritable implements Writable, DBWritable {
private String operator;
private double market_share;
public DBOutputWritable() {
}
public DBOutputWritable(String operator, double market_share) {
this.operator = operator;
this.market_share = market_share;
}
@Override
public void readFields(DataInput in) throws IOException {
operator = in.readUTF();
market_share = in.readDouble();
}
@Override
public void write(DataOutput out) throws IOException, IOException {
out.writeUTF(operator);
out.writeDouble(market_share);
}
@Override
public void readFields(ResultSet resultSet) throws SQLException {
// 不需要實(shí)現(xiàn)此方法,因?yàn)槲覀冎粫?huì)寫(xiě)入數(shù)據(jù)到數(shù)據(jù)庫(kù)
}
@Override
public void write(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.setString(1, operator);
preparedStatement.setDouble(2, market_share);
}
}
運(yùn)行結(jié)果如下文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-476897.html
- 可視化操作
package com.yopai.draw;
/**
* @Description
*/
import java.awt.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
public class PieChartExample extends JFrame {
public PieChartExample() {
// 從數(shù)據(jù)庫(kù)獲取數(shù)據(jù)
DefaultPieDataset dataset = new DefaultPieDataset();
try {
String dbUrl = "jdbc:mysql://localhost:3306/blog";
String dbUsername = "root";
String dbPassword = "Admin2022!";
Connection connection = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT operator, market_share FROM operator_market_share");
while (resultSet.next()) {
String operator = resultSet.getString("operator");
double marketShare = resultSet.getDouble("market_share");
dataset.setValue(operator, marketShare);
}
} catch (Exception e) {
e.printStackTrace();
}
// 創(chuàng)建餅圖
JFreeChart pieChart = ChartFactory.createPieChart(
"運(yùn)營(yíng)商市場(chǎng)占比", // 圖表標(biāo)題
dataset, // 數(shù)據(jù)集
true, // 是否顯示圖例
true, // 是否生成工具提示
false // 是否生成URL鏈接
);
// 設(shè)置字體以顯示中文
Font font = new Font("宋體", Font.PLAIN, 12);
pieChart.getTitle().setFont(font);
pieChart.getLegend().setItemFont(font);
PiePlot plot = (PiePlot) pieChart.getPlot();
plot.setLabelFont(font);
// 添加餅圖到面板并顯示
ChartPanel chartPanel = new ChartPanel(pieChart);
setContentPane(chartPanel);
}
public static void main(String[] args) {
PieChartExample pieChartExample = new PieChartExample();
pieChartExample.setSize(600, 600);
pieChartExample.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pieChartExample.setVisible(true);
}
}
結(jié)果如下
本篇文章到這里結(jié)束 需要注意的是每個(gè)人的環(huán)境不用調(diào)用的API會(huì)有所差異。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-476897.html
到了這里,關(guān)于【Hadoop綜合實(shí)踐】手機(jī)賣場(chǎng)大數(shù)據(jù)綜合項(xiàng)目分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!