前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[大规模数据分析场景下的ClickHous...]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
转载文章
...实际应用中广泛应用于数据分析、预测模型构建以及分类问题解决。随着技术发展,决策树算法不断优化与扩展,如集成学习中的随机森林(Random Forest)和梯度提升决策树(Gradient Boosting Decision Tree, GBDT),它们通过构建并结合多个决策树来提高预测准确率和稳定性。 最近的研究进展显示,决策树在处理大规模数据集时表现出了新的潜力。2021年,《Pattern Recognition Letters》期刊上的一项研究探讨了如何改进决策树算法以适应流式大数据环境,提出了实时更新的增量决策树算法,能够在连续接收新数据的同时进行高效地模型更新与优化。 此外,信息增益这一核心指标也在理论与实践中得到深化。有学者针对信息增益存在的偏好属性数量多的问题,提出了信息增益比(Information Gain Ratio)等改进措施,进一步提升了决策树对特征重要性的判断能力。同时,基于熵的决策树算法在强化学习、深度学习等领域也有所融合创新,例如深度决策树网络的设计,尝试将决策树的可解释性优势与神经网络的非线性表达能力相结合,以应对更复杂的决策问题。 而在实际应用方面,决策树在医疗诊断、金融风控、推荐系统等多个场景下发挥关键作用。例如,最新的研究成果中,科研团队利用改进型决策树算法对新冠病毒患者临床数据进行分析,有效识别出影响病情发展的关键因素,为制定诊疗方案提供了有力支持。 总之,尽管经典的ID3、C4.5、CART算法奠定了决策树的基础,但决策树算法的研究并未止步,其在理论优化、与其他AI技术融合以及解决现实世界复杂问题等方面展现出了持续的生命力与广阔的应用前景。
2023-08-27 21:53:08
284
转载
Mongo
NoSQL数据库 , 一种非关系型数据库管理系统,不遵循传统的关系型数据库范式,通常用于处理大规模数据集,具有高可扩展性、高可用性和高性能的特点。NoSQL数据库适用于处理非结构化和半结构化数据,常用于互联网应用、大数据分析等领域。 索引 , 在数据库管理系统中,索引是一种数据结构,用于提高数据查询的效率。它允许数据库快速定位到数据记录,减少了搜索时间。索引通常通过在数据库表的某一列或某些列上建立树状结构实现,使得查询时可以直接跳转到所需记录的位置,极大地提升了数据检索的速度。 指针 , 在计算机科学中,指针是一种特殊类型的变量,用来存储另一个变量的地址。在编程语言中,指针可以用来间接访问内存中的数据,从而实现高效的内存操作和数据结构的实现。在文章语境中,指针可能隐含地与数据库中索引的引用机制相关联,即通过索引的指针快速定位到数据的存储位置。
2024-10-14 15:51:43
88
心灵驿站
Spark
随着大数据时代的到来,Apache Spark作为高效的大规模数据处理引擎,其应用日益广泛,特别是在人工智能、机器学习等领域发挥着关键作用。然而,面对海量数据和复杂业务场景,Spark应用的稳定性和性能优化成为亟待解决的问题。本文将深入探讨如何通过优化日志记录策略、引入自动化监控工具、实施精准性能调优等方法,全面提升Spark应用的稳定性和性能,从而更好地支撑大数据时代的业务需求。 一、日志记录优化:从被动到主动 传统的日志记录方式往往侧重于问题发生后的记录和事后分析,缺乏事前预警和预防机制。为了提升Spark应用的稳定性,应采用主动监控和预测性分析相结合的日志记录策略: - 日志级别调整:根据应用不同阶段的需求动态调整日志级别,既能保证关键信息的完整记录,又能避免无谓的性能开销。 - 日志聚合与分析:利用现代大数据分析工具(如ELK Stack、Logstash、Kibana等),实现日志的实时聚合、分析与可视化,便于快速识别异常模式和性能瓶颈。 - 自定义告警规则:基于历史数据和业务特性,设定合理的异常阈值和告警规则,实现异常的即时发现和响应。 二、自动化监控工具的引入 自动化监控工具能够持续跟踪Spark应用的运行状况,及时发现潜在问题并采取措施: - 实时监控:通过集成Prometheus、Grafana等监控工具,实现对应用性能、资源使用、任务执行时间等关键指标的实时监控。 - 自动扩展:利用Kubernetes等容器化平台的自动扩展功能,根据负载变化动态调整集群规模,确保资源高效利用。 - 故障恢复:通过HDFS、Zookeeper等组件提供的容错机制,实现任务失败时的自动重试或数据冗余备份,提升应用的高可用性。 三、精准性能调优策略 针对Spark应用的特定场景,实施精准的性能调优策略,可以从以下几个方面入手: - 参数优化:根据具体工作负载,调整Spark配置参数,如executor内存分配、shuffle操作的并行度等,以达到最优性能。 - 数据倾斜处理:采用数据预洗、分桶等技术,减少数据倾斜对任务执行效率的影响。 - 任务调度优化:合理规划任务执行顺序和依赖关系,避免不必要的等待时间,提高任务执行效率。 结论 通过优化日志记录策略、引入自动化监控工具、实施精准性能调优,可以显著提升Apache Spark应用的稳定性和性能,有效应对大数据时代面临的挑战。结合实时数据分析、故障预测与自动恢复等现代技术手段,企业能够构建更加可靠、高效的Spark生态系统,支持复杂业务场景下的数据驱动决策。
2024-09-07 16:03:18
141
秋水共长天一色
转载文章
...告点击综合案例 需求分析和技术架构 广告点击系统实时分析 广告来自于广告或者移动App等,广告需要设定在具体的广告位,当用户点击广告的时候,一般都会通过ajax或Socket往后台发送日志数据,在这里我们是要做基于SparkStreaming做实时在线统计。那么数据就需要放进消息系统(Kafka)中,我们的Spark Streaming应用程序就会去Kafka中Pull数据过来进行计算和消费,并把计算后的数据放入到持久化系统中(MySQL) 广告点击系统实时分析的意义:因为可以在线实时的看见广告的投放效果,就为广告的更大规模的投入和调整打下了坚实的基础,从而为公司带来最大化的经济回报。 核心需求: 1、实时黑名单动态过滤出有效的用户广告点击行为:因为黑名单用户可能随时出现,所以需要动态更新; 2、在线计算广告点击流量; 3、Top3热门广告; 4、每个广告流量趋势; 5、广告点击用户的区域分布分析 6、最近一分钟的广告点击量; 7、整个广告点击Spark Streaming处理程序724小时运行; 数据格式: 时间、用户、广告、城市等 技术细节: 在线计算用户点击的次数分析,屏蔽IP等; 使用updateStateByKey或者mapWithState进行不同地区广告点击排名的计算; Spark Streaming+Spark SQL+Spark Core等综合分析数据; 使用Window类型的操作; 高可用和性能调优等等; 流量趋势,一般会结合DB等; Spark Core / /package com.tom.spark.SparkApps.sparkstreaming;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.Properties;import java.util.Random;import kafka.javaapi.producer.Producer;import kafka.producer.KeyedMessage;import kafka.producer.ProducerConfig;/ 数据生成代码,Kafka Producer产生数据/public class MockAdClickedStat {/ @param args/public static void main(String[] args) {final Random random = new Random();final String[] provinces = new String[]{"Guangdong", "Zhejiang", "Jiangsu", "Fujian"};final Map<String, String[]> cities = new HashMap<String, String[]>();cities.put("Guangdong", new String[]{"Guangzhou", "Shenzhen", "Dongguan"});cities.put("Zhejiang", new String[]{"Hangzhou", "Wenzhou", "Ningbo"});cities.put("Jiangsu", new String[]{"Nanjing", "Suzhou", "Wuxi"});cities.put("Fujian", new String[]{"Fuzhou", "Xiamen", "Sanming"});final String[] ips = new String[] {"192.168.112.240","192.168.112.239","192.168.112.245","192.168.112.246","192.168.112.247","192.168.112.248","192.168.112.249","192.168.112.250","192.168.112.251","192.168.112.252","192.168.112.253","192.168.112.254",};/ Kafka相关的基本配置信息/Properties kafkaConf = new Properties();kafkaConf.put("serializer.class", "kafka.serializer.StringEncoder");kafkaConf.put("metadeta.broker.list", "Master:9092,Worker1:9092,Worker2:9092");ProducerConfig producerConfig = new ProducerConfig(kafkaConf);final Producer<Integer, String> producer = new Producer<Integer, String>(producerConfig);new Thread(new Runnable() {public void run() {while(true) {//在线处理广告点击流的基本数据格式:timestamp、ip、userID、adID、province、cityLong timestamp = new Date().getTime();String ip = ips[random.nextInt(12)]; //可以采用网络上免费提供的ip库int userID = random.nextInt(10000);int adID = random.nextInt(100);String province = provinces[random.nextInt(4)];String city = cities.get(province)[random.nextInt(3)];String clickedAd = timestamp + "\t" + ip + "\t" + userID + "\t" + adID + "\t" + province + "\t" + city;producer.send(new KeyedMessage<Integer, String>("AdClicked", clickedAd));try {Thread.sleep(50);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} }} }).start();} } package com.tom.spark.SparkApps.sparkstreaming;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import java.util.concurrent.LinkedBlockingQueue;import kafka.serializer.StringDecoder;import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaPairRDD;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.api.java.JavaSparkContext;import org.apache.spark.api.java.function.Function;import org.apache.spark.api.java.function.Function2;import org.apache.spark.api.java.function.PairFunction;import org.apache.spark.api.java.function.VoidFunction;import org.apache.spark.sql.DataFrame;import org.apache.spark.sql.Row;import org.apache.spark.sql.RowFactory;import org.apache.spark.sql.hive.HiveContext;import org.apache.spark.sql.types.DataTypes;import org.apache.spark.sql.types.StructType;import org.apache.spark.streaming.Durations;import org.apache.spark.streaming.api.java.JavaDStream;import org.apache.spark.streaming.api.java.JavaPairDStream;import org.apache.spark.streaming.api.java.JavaPairInputDStream;import org.apache.spark.streaming.api.java.JavaStreamingContext;import org.apache.spark.streaming.api.java.JavaStreamingContextFactory;import org.apache.spark.streaming.kafka.KafkaUtils;import com.google.common.base.Optional;import scala.Tuple2;/ 数据处理,Kafka消费者/public class AdClickedStreamingStats {/ @param args/public static void main(String[] args) {// TODO Auto-generated method stub//好处:1、checkpoint 2、工厂final SparkConf conf = new SparkConf().setAppName("SparkStreamingOnKafkaDirect").setMaster("hdfs://Master:7077/");final String checkpointDirectory = "hdfs://Master:9000/library/SparkStreaming/CheckPoint_Data";JavaStreamingContextFactory factory = new JavaStreamingContextFactory() {public JavaStreamingContext create() {// TODO Auto-generated method stubreturn createContext(checkpointDirectory, conf);} };/ 可以从失败中恢复Driver,不过还需要指定Driver这个进程运行在Cluster,并且在提交应用程序的时候制定--supervise;/JavaStreamingContext javassc = JavaStreamingContext.getOrCreate(checkpointDirectory, factory);/ 第三步:创建Spark Streaming输入数据来源input Stream: 1、数据输入来源可以基于File、HDFS、Flume、Kafka、Socket等 2、在这里我们指定数据来源于网络Socket端口,Spark Streaming连接上该端口并在运行的时候一直监听该端口的数据 (当然该端口服务首先必须存在),并且在后续会根据业务需要不断有数据产生(当然对于Spark Streaming 应用程序的运行而言,有无数据其处理流程都是一样的) 3、如果经常在每间隔5秒钟没有数据的话不断启动空的Job其实会造成调度资源的浪费,因为并没有数据需要发生计算;所以 实际的企业级生成环境的代码在具体提交Job前会判断是否有数据,如果没有的话就不再提交Job;///创建Kafka元数据来让Spark Streaming这个Kafka Consumer利用Map<String, String> kafkaParameters = new HashMap<String, String>();kafkaParameters.put("metadata.broker.list", "Master:9092,Worker1:9092,Worker2:9092");Set<String> topics = new HashSet<String>();topics.add("SparkStreamingDirected");JavaPairInputDStream<String, String> adClickedStreaming = KafkaUtils.createDirectStream(javassc, String.class, String.class, StringDecoder.class, StringDecoder.class,kafkaParameters, topics);/因为要对黑名单进行过滤,而数据是在RDD中的,所以必然使用transform这个函数; 但是在这里我们必须使用transformToPair,原因是读取进来的Kafka的数据是Pair<String,String>类型, 另一个原因是过滤后的数据要进行进一步处理,所以必须是读进的Kafka数据的原始类型 在此再次说明,每个Batch Duration中实际上讲输入的数据就是被一个且仅被一个RDD封装的,你可以有多个 InputDStream,但其实在产生job的时候,这些不同的InputDStream在Batch Duration中就相当于Spark基于HDFS 数据操作的不同文件来源而已罢了。/JavaPairDStream<String, String> filteredadClickedStreaming = adClickedStreaming.transformToPair(new Function<JavaPairRDD<String,String>, JavaPairRDD<String,String>>() {public JavaPairRDD<String, String> call(JavaPairRDD<String, String> rdd) throws Exception {/ 在线黑名单过滤思路步骤: 1、从数据库中获取黑名单转换成RDD,即新的RDD实例封装黑名单数据; 2、然后把代表黑名单的RDD的实例和Batch Duration产生的RDD进行Join操作, 准确的说是进行leftOuterJoin操作,也就是说使用Batch Duration产生的RDD和代表黑名单的RDD实例进行 leftOuterJoin操作,如果两者都有内容的话,就会是true,否则的话就是false 我们要留下的是leftOuterJoin结果为false; /final List<String> blackListNames = new ArrayList<String>();JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();jdbcWrapper.doQuery("SELECT FROM blacklisttable", null, new ExecuteCallBack() {public void resultCallBack(ResultSet result) throws Exception {while(result.next()){blackListNames.add(result.getString(1));} }});List<Tuple2<String, Boolean>> blackListTuple = new ArrayList<Tuple2<String,Boolean>>();for(String name : blackListNames) {blackListTuple.add(new Tuple2<String, Boolean>(name, true));}List<Tuple2<String, Boolean>> blacklistFromListDB = blackListTuple; //数据来自于查询的黑名单表并且映射成为<String, Boolean>JavaSparkContext jsc = new JavaSparkContext(rdd.context());/ 黑名单的表中只有userID,但是如果要进行join操作的话就必须是Key-Value,所以在这里我们需要 基于数据表中的数据产生Key-Value类型的数据集合/JavaPairRDD<String, Boolean> blackListRDD = jsc.parallelizePairs(blacklistFromListDB);/ 进行操作的时候肯定是基于userID进行join,所以必须把传入的rdd进行mapToPair操作转化成为符合格式的RDD/JavaPairRDD<String, Tuple2<String, String>> rdd2Pair = rdd.mapToPair(new PairFunction<Tuple2<String,String>, String, Tuple2<String, String>>() {public Tuple2<String, Tuple2<String, String>> call(Tuple2<String, String> t) throws Exception {// TODO Auto-generated method stubString userID = t._2.split("\t")[2];return new Tuple2<String, Tuple2<String,String>>(userID, t);} });JavaPairRDD<String, Tuple2<Tuple2<String, String>, Optional<Boolean>>> joined = rdd2Pair.leftOuterJoin(blackListRDD);JavaPairRDD<String, String> result = joined.filter(new Function<Tuple2<String,Tuple2<Tuple2<String,String>,Optional<Boolean>>>, Boolean>() {public Boolean call(Tuple2<String, Tuple2<Tuple2<String, String>, Optional<Boolean>>> tuple)throws Exception {// TODO Auto-generated method stubOptional<Boolean> optional = tuple._2._2;if(optional.isPresent() && optional.get()){return false;} else {return true;} }}).mapToPair(new PairFunction<Tuple2<String,Tuple2<Tuple2<String,String>,Optional<Boolean>>>, String, String>() {public Tuple2<String, String> call(Tuple2<String, Tuple2<Tuple2<String, String>, Optional<Boolean>>> t)throws Exception {// TODO Auto-generated method stubreturn t._2._1;} });return result;} });//广告点击的基本数据格式:timestamp、ip、userID、adID、province、cityJavaPairDStream<String, Long> pairs = filteredadClickedStreaming.mapToPair(new PairFunction<Tuple2<String,String>, String, Long>() {public Tuple2<String, Long> call(Tuple2<String, String> t) throws Exception {String[] splited=t._2.split("\t");String timestamp = splited[0]; //YYYY-MM-DDString ip = splited[1];String userID = splited[2];String adID = splited[3];String province = splited[4];String city = splited[5]; String clickedRecord = timestamp + "_" +ip + "_"+userID+"_"+adID+"_"+province +"_"+city;return new Tuple2<String, Long>(clickedRecord, 1L);} });/ 第4.3步:在单词实例计数为1基础上,统计每个单词在文件中出现的总次数/JavaPairDStream<String, Long> adClickedUsers= pairs.reduceByKey(new Function2<Long, Long, Long>() {public Long call(Long i1, Long i2) throws Exception{return i1 + i2;} });/判断有效的点击,复杂化的采用机器学习训练模型进行在线过滤 简单的根据ip判断1天不超过100次;也可以通过一个batch duration的点击次数判断是否非法广告点击,通过一个batch来判断是不完整的,还需要一天的数据也可以每一个小时来判断。/JavaPairDStream<String, Long> filterClickedBatch = adClickedUsers.filter(new Function<Tuple2<String,Long>, Boolean>() {public Boolean call(Tuple2<String, Long> v1) throws Exception {if (1 < v1._2){//更新一些黑名单的数据库表return false;} else { return true;} }});//filterClickedBatch.print();//写入数据库filterClickedBatch.foreachRDD(new Function<JavaPairRDD<String,Long>, Void>() {public Void call(JavaPairRDD<String, Long> rdd) throws Exception {rdd.foreachPartition(new VoidFunction<Iterator<Tuple2<String,Long>>>() {public void call(Iterator<Tuple2<String, Long>> partition) throws Exception {//使用数据库连接池的高效读写数据库的方式将数据写入数据库mysql//例如一次插入 1000条 records,使用insertBatch 或 updateBatch//插入的用户数据信息:userID,adID,clickedCount,time//这里面有一个问题,可能出现两条记录的key是一样的,此时需要更新累加操作List<UserAdClicked> userAdClickedList = new ArrayList<UserAdClicked>();while(partition.hasNext()) {Tuple2<String, Long> record = partition.next();String[] splited = record._1.split("\t");UserAdClicked userClicked = new UserAdClicked();userClicked.setTimestamp(splited[0]);userClicked.setIp(splited[1]);userClicked.setUserID(splited[2]);userClicked.setAdID(splited[3]);userClicked.setProvince(splited[4]);userClicked.setCity(splited[5]);userAdClickedList.add(userClicked);}final List<UserAdClicked> inserting = new ArrayList<UserAdClicked>();final List<UserAdClicked> updating = new ArrayList<UserAdClicked>();JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();//表的字段timestamp、ip、userID、adID、province、city、clickedCountfor(final UserAdClicked clicked : userAdClickedList) {jdbcWrapper.doQuery("SELECT clickedCount FROM adclicked WHERE"+ " timestamp =? AND userID = ? AND adID = ?",new Object[]{clicked.getTimestamp(), clicked.getUserID(),clicked.getAdID()}, new ExecuteCallBack() {public void resultCallBack(ResultSet result) throws Exception {// TODO Auto-generated method stubif(result.next()) {long count = result.getLong(1);clicked.setClickedCount(count);updating.add(clicked);} else {inserting.add(clicked);clicked.setClickedCount(1L);} }});}//表的字段timestamp、ip、userID、adID、province、city、clickedCountList<Object[]> insertParametersList = new ArrayList<Object[]>();for(UserAdClicked insertRecord : inserting) {insertParametersList.add(new Object[] {insertRecord.getTimestamp(),insertRecord.getIp(),insertRecord.getUserID(),insertRecord.getAdID(),insertRecord.getProvince(),insertRecord.getCity(),insertRecord.getClickedCount()});}jdbcWrapper.doBatch("INSERT INTO adclicked VALUES(?, ?, ?, ?, ?, ?, ?)", insertParametersList);//表的字段timestamp、ip、userID、adID、province、city、clickedCountList<Object[]> updateParametersList = new ArrayList<Object[]>();for(UserAdClicked updateRecord : updating) {updateParametersList.add(new Object[] {updateRecord.getTimestamp(),updateRecord.getIp(),updateRecord.getUserID(),updateRecord.getAdID(),updateRecord.getProvince(),updateRecord.getCity(),updateRecord.getClickedCount() + 1});}jdbcWrapper.doBatch("UPDATE adclicked SET clickedCount = ? WHERE"+ " timestamp =? AND ip = ? AND userID = ? AND adID = ? "+ "AND province = ? AND city = ?", updateParametersList);} });return null;} });//再次过滤,从数据库中读取数据过滤黑名单JavaPairDStream<String, Long> blackListBasedOnHistory = filterClickedBatch.filter(new Function<Tuple2<String,Long>, Boolean>() {public Boolean call(Tuple2<String, Long> v1) throws Exception {//广告点击的基本数据格式:timestamp,ip,userID,adID,province,cityString[] splited = v1._1.split("\t"); //提取key值String date =splited[0];String userID =splited[2];String adID =splited[3];//查询一下数据库同一个用户同一个广告id点击量超过50次列入黑名单//接下来 根据date、userID、adID条件去查询用户点击广告的数据表,获得总的点击次数//这个时候基于点击次数判断是否属于黑名单点击int clickedCountTotalToday = 81 ;if (clickedCountTotalToday > 50) {return true;}else {return false ;} }});//map操作,找出用户的idJavaDStream<String> blackListuserIDBasedInBatchOnhistroy =blackListBasedOnHistory.map(new Function<Tuple2<String,Long>, String>() {public String call(Tuple2<String, Long> v1) throws Exception {// TODO Auto-generated method stubreturn v1._1.split("\t")[2];} });//有一个问题,数据可能重复,在一个partition里面重复,这个好办;//但多个partition不能保证一个用户重复,需要对黑名单的整个rdd进行去重操作。//rdd去重了,partition也就去重了,一石二鸟,一箭双雕// 找出了黑名单,下一步就写入黑名单数据库表中JavaDStream<String> blackListUniqueuserBasedInBatchOnhistroy = blackListuserIDBasedInBatchOnhistroy.transform(new Function<JavaRDD<String>, JavaRDD<String>>() {public JavaRDD<String> call(JavaRDD<String> rdd) throws Exception {// TODO Auto-generated method stubreturn rdd.distinct();} });// 下一步写入到数据表中blackListUniqueuserBasedInBatchOnhistroy.foreachRDD(new Function<JavaRDD<String>, Void>() {public Void call(JavaRDD<String> rdd) throws Exception {rdd.foreachPartition(new VoidFunction<Iterator<String>>() {public void call(Iterator<String> t) throws Exception {// TODO Auto-generated method stub//插入的用户信息可以只包含:useID//此时直接插入黑名单数据表即可。//写入数据库List<Object[]> blackList = new ArrayList<Object[]>();while(t.hasNext()) {blackList.add(new Object[]{t.next()});}JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();jdbcWrapper.doBatch("INSERT INTO blacklisttable values (?)", blackList);} });return null;} });/广告点击累计动态更新,每个updateStateByKey都会在Batch Duration的时间间隔的基础上进行广告点击次数的更新, 更新之后我们一般都会持久化到外部存储设备上,在这里我们存储到MySQL数据库中/JavaPairDStream<String, Long> updateStateByKeyDSteam = filteredadClickedStreaming.mapToPair(new PairFunction<Tuple2<String,String>, String, Long>() {public Tuple2<String, Long> call(Tuple2<String, String> t)throws Exception {String[] splited=t._2.split("\t");String timestamp = splited[0]; //YYYY-MM-DDString ip = splited[1];String userID = splited[2];String adID = splited[3];String province = splited[4];String city = splited[5]; String clickedRecord = timestamp + "_" +ip + "_"+userID+"_"+adID+"_"+province +"_"+city;return new Tuple2<String, Long>(clickedRecord, 1L);} }).updateStateByKey(new Function2<List<Long>, Optional<Long>, Optional<Long>>() {public Optional<Long> call(List<Long> v1, Optional<Long> v2)throws Exception {// v1:当前的Key在当前的Batch Duration中出现的次数的集合,例如{1,1,1,。。。,1}// v2:当前的Key在以前的Batch Duration中积累下来的结果;Long clickedTotalHistory = 0L; if(v2.isPresent()){clickedTotalHistory = v2.get();}for(Long one : v1) {clickedTotalHistory += one;}return Optional.of(clickedTotalHistory);} });updateStateByKeyDSteam.foreachRDD(new Function<JavaPairRDD<String,Long>, Void>() {public Void call(JavaPairRDD<String, Long> rdd) throws Exception {rdd.foreachPartition(new VoidFunction<Iterator<Tuple2<String,Long>>>() {public void call(Iterator<Tuple2<String, Long>> partition) throws Exception {//使用数据库连接池的高效读写数据库的方式将数据写入数据库mysql//例如一次插入 1000条 records,使用insertBatch 或 updateBatch//插入的用户数据信息:timestamp、adID、province、city//这里面有一个问题,可能出现两条记录的key是一样的,此时需要更新累加操作List<AdClicked> AdClickedList = new ArrayList<AdClicked>();while(partition.hasNext()) {Tuple2<String, Long> record = partition.next();String[] splited = record._1.split("\t");AdClicked adClicked = new AdClicked();adClicked.setTimestamp(splited[0]);adClicked.setAdID(splited[1]);adClicked.setProvince(splited[2]);adClicked.setCity(splited[3]);adClicked.setClickedCount(record._2);AdClickedList.add(adClicked);}final List<AdClicked> inserting = new ArrayList<AdClicked>();final List<AdClicked> updating = new ArrayList<AdClicked>();JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();//表的字段timestamp、ip、userID、adID、province、city、clickedCountfor(final AdClicked clicked : AdClickedList) {jdbcWrapper.doQuery("SELECT clickedCount FROM adclickedcount WHERE"+ " timestamp = ? AND adID = ? AND province = ? AND city = ?",new Object[]{clicked.getTimestamp(), clicked.getAdID(),clicked.getProvince(), clicked.getCity()}, new ExecuteCallBack() {public void resultCallBack(ResultSet result) throws Exception {// TODO Auto-generated method stubif(result.next()) {long count = result.getLong(1);clicked.setClickedCount(count);updating.add(clicked);} else {inserting.add(clicked);clicked.setClickedCount(1L);} }});}//表的字段timestamp、ip、userID、adID、province、city、clickedCountList<Object[]> insertParametersList = new ArrayList<Object[]>();for(AdClicked insertRecord : inserting) {insertParametersList.add(new Object[] {insertRecord.getTimestamp(),insertRecord.getAdID(),insertRecord.getProvince(),insertRecord.getCity(),insertRecord.getClickedCount()});}jdbcWrapper.doBatch("INSERT INTO adclickedcount VALUES(?, ?, ?, ?, ?)", insertParametersList);//表的字段timestamp、ip、userID、adID、province、city、clickedCountList<Object[]> updateParametersList = new ArrayList<Object[]>();for(AdClicked updateRecord : updating) {updateParametersList.add(new Object[] {updateRecord.getClickedCount(),updateRecord.getTimestamp(),updateRecord.getAdID(),updateRecord.getProvince(),updateRecord.getCity()});}jdbcWrapper.doBatch("UPDATE adclickedcount SET clickedCount = ? WHERE"+ " timestamp =? AND adID = ? AND province = ? AND city = ?", updateParametersList);} });return null;} });/ 对广告点击进行TopN计算,计算出每天每个省份Top5排名的广告 因为我们直接对RDD进行操作,所以使用了transfomr算子;/updateStateByKeyDSteam.transform(new Function<JavaPairRDD<String,Long>, JavaRDD<Row>>() {public JavaRDD<Row> call(JavaPairRDD<String, Long> rdd) throws Exception {JavaRDD<Row> rowRDD = rdd.mapToPair(new PairFunction<Tuple2<String,Long>, String, Long>() {public Tuple2<String, Long> call(Tuple2<String, Long> t)throws Exception {// TODO Auto-generated method stubString[] splited=t._1.split("_");String timestamp = splited[0]; //YYYY-MM-DDString adID = splited[3];String province = splited[4];String clickedRecord = timestamp + "_" + adID + "_" + province;return new Tuple2<String, Long>(clickedRecord, t._2);} }).reduceByKey(new Function2<Long, Long, Long>() {public Long call(Long v1, Long v2) throws Exception {// TODO Auto-generated method stubreturn v1 + v2;} }).map(new Function<Tuple2<String,Long>, Row>() {public Row call(Tuple2<String, Long> v1) throws Exception {// TODO Auto-generated method stubString[] splited=v1._1.split("_");String timestamp = splited[0]; //YYYY-MM-DDString adID = splited[3];String province = splited[4];return RowFactory.create(timestamp, adID, province, v1._2);} });StructType structType = DataTypes.createStructType(Arrays.asList(DataTypes.createStructField("timestamp", DataTypes.StringType, true),DataTypes.createStructField("adID", DataTypes.StringType, true),DataTypes.createStructField("province", DataTypes.StringType, true),DataTypes.createStructField("clickedCount", DataTypes.LongType, true)));HiveContext hiveContext = new HiveContext(rdd.context());DataFrame df = hiveContext.createDataFrame(rowRDD, structType);df.registerTempTable("topNTableSource");DataFrame result = hiveContext.sql("SELECT timestamp, adID, province, clickedCount, FROM"+ " (SELECT timestamp, adID, province,clickedCount, "+ "ROW_NUMBER() OVER(PARTITION BY province ORDER BY clickeCount DESC) rank "+ "FROM topNTableSource) subquery "+ "WHERE rank <= 5");return result.toJavaRDD();} }).foreachRDD(new Function<JavaRDD<Row>, Void>() {public Void call(JavaRDD<Row> rdd) throws Exception {// TODO Auto-generated method stubrdd.foreachPartition(new VoidFunction<Iterator<Row>>() {public void call(Iterator<Row> t) throws Exception {// TODO Auto-generated method stubList<AdProvinceTopN> adProvinceTopN = new ArrayList<AdProvinceTopN>();while(t.hasNext()) {Row row = t.next();AdProvinceTopN item = new AdProvinceTopN();item.setTimestamp(row.getString(0));item.setAdID(row.getString(1));item.setProvince(row.getString(2));item.setClickedCount(row.getLong(3));adProvinceTopN.add(item);}// final List<AdProvinceTopN> inserting = new ArrayList<AdProvinceTopN>();// final List<AdProvinceTopN> updating = new ArrayList<AdProvinceTopN>();JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();Set<String> set = new HashSet<String>();for(AdProvinceTopN item: adProvinceTopN){set.add(item.getTimestamp() + "_" + item.getProvince());}//表的字段timestamp、adID、province、clickedCountArrayList<Object[]> deleteParametersList = new ArrayList<Object[]>();for(String deleteRecord : set) {String[] splited = deleteRecord.split("_");deleteParametersList.add(new Object[]{splited[0],splited[1]});}jdbcWrapper.doBatch("DELETE FROM adprovincetopn WHERE timestamp = ? AND province = ?", deleteParametersList);//表的字段timestamp、ip、userID、adID、province、city、clickedCountList<Object[]> insertParametersList = new ArrayList<Object[]>();for(AdProvinceTopN insertRecord : adProvinceTopN) {insertParametersList.add(new Object[] {insertRecord.getClickedCount(),insertRecord.getTimestamp(),insertRecord.getAdID(),insertRecord.getProvince()});}jdbcWrapper.doBatch("INSERT INTO adprovincetopn VALUES (?, ?, ?, ?)", insertParametersList);} });return null;} });/ 计算过去半个小时内广告点击的趋势 广告点击的基本数据格式:timestamp、ip、userID、adID、province、city/filteredadClickedStreaming.mapToPair(new PairFunction<Tuple2<String,String>, String, Long>() {public Tuple2<String, Long> call(Tuple2<String, String> t)throws Exception {String splited[] = t._2.split("\t");String adID = splited[3];String time = splited[0]; //Todo:后续需要重构代码实现时间戳和分钟的转换提取。此处需要提取出该广告的点击分钟单位return new Tuple2<String, Long>(time + "_" + adID, 1L);} }).reduceByKeyAndWindow(new Function2<Long, Long, Long>() {public Long call(Long v1, Long v2) throws Exception {// TODO Auto-generated method stubreturn v1 + v2;} }, new Function2<Long, Long, Long>() {public Long call(Long v1, Long v2) throws Exception {// TODO Auto-generated method stubreturn v1 - v2;} }, Durations.minutes(30), Durations.milliseconds(5)).foreachRDD(new Function<JavaPairRDD<String,Long>, Void>() {public Void call(JavaPairRDD<String, Long> rdd) throws Exception {// TODO Auto-generated method stubrdd.foreachPartition(new VoidFunction<Iterator<Tuple2<String,Long>>>() {public void call(Iterator<Tuple2<String, Long>> partition)throws Exception {List<AdTrendStat> adTrend = new ArrayList<AdTrendStat>();// TODO Auto-generated method stubwhile(partition.hasNext()) {Tuple2<String, Long> record = partition.next();String[] splited = record._1.split("_");String time = splited[0];String adID = splited[1];Long clickedCount = record._2;/ 在插入数据到数据库的时候具体需要哪些字段?time、adID、clickedCount; 而我们通过J2EE技术进行趋势绘图的时候肯定是需要年、月、日、时、分这个维度的,所以我们在这里需要 年月日、小时、分钟这些时间维度;/AdTrendStat adTrendStat = new AdTrendStat();adTrendStat.setAdID(adID);adTrendStat.setClickedCount(clickedCount);adTrendStat.set_date(time); //Todo:获取年月日adTrendStat.set_hour(time); //Todo:获取小时adTrendStat.set_minute(time);//Todo:获取分钟adTrend.add(adTrendStat);}final List<AdTrendStat> inserting = new ArrayList<AdTrendStat>();final List<AdTrendStat> updating = new ArrayList<AdTrendStat>();JDBCWrapper jdbcWrapper = JDBCWrapper.getJDBCInstance();//表的字段timestamp、ip、userID、adID、province、city、clickedCountfor(final AdTrendStat trend : adTrend) {final AdTrendCountHistory adTrendhistory = new AdTrendCountHistory();jdbcWrapper.doQuery("SELECT clickedCount FROM adclickedtrend WHERE"+ " date =? AND hour = ? AND minute = ? AND AdID = ?",new Object[]{trend.get_date(), trend.get_hour(), trend.get_minute(),trend.getAdID()}, new ExecuteCallBack() {public void resultCallBack(ResultSet result) throws Exception {// TODO Auto-generated method stubif(result.next()) {long count = result.getLong(1);adTrendhistory.setClickedCountHistoryLong(count);updating.add(trend);} else { inserting.add(trend);} }});}//表的字段date、hour、minute、adID、clickedCountList<Object[]> insertParametersList = new ArrayList<Object[]>();for(AdTrendStat insertRecord : inserting) {insertParametersList.add(new Object[] {insertRecord.get_date(),insertRecord.get_hour(),insertRecord.get_minute(),insertRecord.getAdID(),insertRecord.getClickedCount()});}jdbcWrapper.doBatch("INSERT INTO adclickedtrend VALUES(?, ?, ?, ?, ?)", insertParametersList);//表的字段date、hour、minute、adID、clickedCountList<Object[]> updateParametersList = new ArrayList<Object[]>();for(AdTrendStat updateRecord : updating) {updateParametersList.add(new Object[] {updateRecord.getClickedCount(),updateRecord.get_date(),updateRecord.get_hour(),updateRecord.get_minute(),updateRecord.getAdID()});}jdbcWrapper.doBatch("UPDATE adclickedtrend SET clickedCount = ? WHERE"+ " date =? AND hour = ? AND minute = ? AND AdID = ?", updateParametersList);} });return null;} });;/ Spark Streaming 执行引擎也就是Driver开始运行,Driver启动的时候是位于一条新的线程中的,当然其内部有消息循环体,用于 接收应用程序本身或者Executor中的消息,/javassc.start();javassc.awaitTermination();javassc.close();}private static JavaStreamingContext createContext(String checkpointDirectory, SparkConf conf) {// If you do not see this printed, that means the StreamingContext has been loaded// from the new checkpointSystem.out.println("Creating new context");// Create the context with a 5 second batch sizeJavaStreamingContext ssc = new JavaStreamingContext(conf, Durations.seconds(10));ssc.checkpoint(checkpointDirectory);return ssc;} }class JDBCWrapper {private static JDBCWrapper jdbcInstance = null;private static LinkedBlockingQueue<Connection> dbConnectionPool = new LinkedBlockingQueue<Connection>();static {try {Class.forName("com.mysql.jdbc.Driver");} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} }public static JDBCWrapper getJDBCInstance() {if(jdbcInstance == null) {synchronized (JDBCWrapper.class) {if(jdbcInstance == null) {jdbcInstance = new JDBCWrapper();} }}return jdbcInstance; }private JDBCWrapper() {for(int i = 0; i < 10; i++){try {Connection conn = DriverManager.getConnection("jdbc:mysql://Master:3306/sparkstreaming","root", "root");dbConnectionPool.put(conn);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} } }public synchronized Connection getConnection() {while(0 == dbConnectionPool.size()){try {Thread.sleep(20);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} }return dbConnectionPool.poll();}public int[] doBatch(String sqlText, List<Object[]> paramsList){Connection conn = getConnection();PreparedStatement preparedStatement = null;int[] result = null;try {conn.setAutoCommit(false);preparedStatement = conn.prepareStatement(sqlText);for(Object[] parameters: paramsList) {for(int i = 0; i < parameters.length; i++){preparedStatement.setObject(i + 1, parameters[i]);} preparedStatement.addBatch();}result = preparedStatement.executeBatch();conn.commit();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if(preparedStatement != null) {try {preparedStatement.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} }if(conn != null) {try {dbConnectionPool.put(conn);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} }}return result; }public void doQuery(String sqlText, Object[] paramsList, ExecuteCallBack callback){Connection conn = getConnection();PreparedStatement preparedStatement = null;ResultSet result = null;try {preparedStatement = conn.prepareStatement(sqlText);for(int i = 0; i < paramsList.length; i++){preparedStatement.setObject(i + 1, paramsList[i]);} result = preparedStatement.executeQuery();try {callback.resultCallBack(result);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} } catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if(preparedStatement != null) {try {preparedStatement.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} }if(conn != null) {try {dbConnectionPool.put(conn);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} }} }}interface ExecuteCallBack {void resultCallBack(ResultSet result) throws Exception;}class UserAdClicked {private String timestamp;private String ip;private String userID;private String adID;private String province;private String city;private Long clickedCount;public String getTimestamp() {return timestamp;}public void setTimestamp(String timestamp) {this.timestamp = timestamp;}public String getIp() {return ip;}public void setIp(String ip) {this.ip = ip;}public String getUserID() {return userID;}public void setUserID(String userID) {this.userID = userID;}public String getAdID() {return adID;}public void setAdID(String adID) {this.adID = adID;}public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public Long getClickedCount() {return clickedCount;}public void setClickedCount(Long clickedCount) {this.clickedCount = clickedCount;} }class AdClicked {private String timestamp;private String adID;private String province;private String city;private Long clickedCount;public String getTimestamp() {return timestamp;}public void setTimestamp(String timestamp) {this.timestamp = timestamp;}public String getAdID() {return adID;}public void setAdID(String adID) {this.adID = adID;}public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public Long getClickedCount() {return clickedCount;}public void setClickedCount(Long clickedCount) {this.clickedCount = clickedCount;} }class AdProvinceTopN {private String timestamp;private String adID;private String province;private Long clickedCount;public String getTimestamp() {return timestamp;}public void setTimestamp(String timestamp) {this.timestamp = timestamp;}public String getAdID() {return adID;}public void setAdID(String adID) {this.adID = adID;}public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public Long getClickedCount() {return clickedCount;}public void setClickedCount(Long clickedCount) {this.clickedCount = clickedCount;} }class AdTrendStat {private String _date;private String _hour;private String _minute;private String adID;private Long clickedCount;public String get_date() {return _date;}public void set_date(String _date) {this._date = _date;}public String get_hour() {return _hour;}public void set_hour(String _hour) {this._hour = _hour;}public String get_minute() {return _minute;}public void set_minute(String _minute) {this._minute = _minute;}public String getAdID() {return adID;}public void setAdID(String adID) {this.adID = adID;}public Long getClickedCount() {return clickedCount;}public void setClickedCount(Long clickedCount) {this.clickedCount = clickedCount;} }class AdTrendCountHistory{private Long clickedCountHistoryLong;public Long getClickedCountHistoryLong() {return clickedCountHistoryLong;}public void setClickedCountHistoryLong(Long clickedCountHistoryLong) {this.clickedCountHistoryLong = clickedCountHistoryLong;} } 本篇文章为转载内容。原文链接:https://blog.csdn.net/tom_8899_li/article/details/71194434。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-02-14 19:16:35
297
转载
MySQL
...OUNT函数统计一列数据个数的基础上,进一步探讨数据库管理与数据分析的实际应用。近期,随着大数据和云计算技术的发展,数据库优化与深度统计分析的需求日益凸显。例如,在电商领域,企业需要精准统计用户行为数据以优化商品推荐策略;而在金融行业,实时统计交易数据对风险控制至关重要。 实际工作中,除了基本的计数操作,MySQL还提供了GROUP BY、HAVING等高级功能,结合COUNT函数可用于实现更复杂的业务逻辑,如按类别统计商品销售数量、筛选出特定条件下的用户活跃度等。另外,对于海量数据处理,可以借助于诸如分区表、索引优化等技术手段提升COUNT查询性能。 值得注意的是,现代数据库系统如Google BigQuery、Amazon Redshift等云数据库服务,不仅提供了对大规模数据高效计算COUNT值的能力,还支持SQL标准的扩展特性,便于进行更深层次的数据挖掘和分析工作。因此,掌握MySQL统计函数的同时,紧跟行业发展趋势,了解并熟练运用新型数据库技术,是当前数据从业者提高工作效率、满足业务需求的重要路径。
2023-03-09 20:28:54
148
诗和远方_t
Hive
...接数超限问题及其解决方案后,我们不难发现,在大数据处理实践中,优化资源配置与管理策略的重要性日益凸显。近期,Apache社区针对Hive的性能瓶颈问题持续进行深度优化。例如,Apache Hive 3.0版本引入了LLAP(Live Long and Process)服务,这是一种混合执行模式,能够在减少内存占用的同时提高查询速度,并通过智能连接管理机制降低连接数超限的风险。 另外,随着云原生技术的发展,许多企业选择将大数据平台迁移至云端,如阿里云、AWS等提供的托管Hive服务。这些云服务通常提供了弹性伸缩和按需分配资源的能力,可以根据实际负载动态调整Hive连接数上限,有效避免因连接数限制导致的任务阻塞问题。 此外,对于大规模数据处理场景下的连接管理,业界专家建议结合使用更先进的数据处理框架,如Spark SQL或Flink SQL,它们能够更好地整合计算资源,通过分布式任务调度机制,有效缓解单一系统中连接数的压力,进一步提升大数据分析处理效率。 综上所述,解决Hive连接数超限问题不仅需要关注配置参数调优,还需要紧跟技术发展趋势,结合最新的大数据处理框架和服务,实现更高效的数据管理和分析能力。
2023-02-16 22:49:34
455
素颜如水-t
Datax
一、引言 在大数据处理的过程中,我们经常需要使用到数据抽取工具Datax来进行数据源之间的数据同步和交换。不过在实际动手操作的时候,咱们可能会遇到一些让人头疼的问题,就比如SQL查询老是超时这种情况。本文将通过实例分析,帮助你更好地理解和解决这个问题。 二、SQL查询超时的原因 1. 数据量过大 当我们在执行SQL查询语句的时候,如果数据量过大,那么查询时间就会相应增加,从而导致查询超时。 2. SQL语句复杂 如果SQL语句包含复杂的关联查询或者嵌套查询,那么查询的时间也会相应的增加,从而可能导致超时。 3. 硬件资源不足 如果我们的硬件资源(如CPU、内存等)不足,那么查询的速度就会降低,从而可能导致超时。 三、如何解决SQL查询超时的问题 1. 优化SQL语句 首先,我们可以尝试优化SQL语句,比如简化查询语句,减少关联查询的数量等,这样可以有效地提高查询速度,避免超时。 sql -- 原始的复杂查询 SELECT FROM tableA JOIN tableB ON tableA.id = tableB.id AND tableA.name = tableB.name; -- 优化后的查询 SELECT FROM tableA JOIN tableB ON tableA.id = tableB.id; 2. 分批查询 对于大规模的数据,我们可以尝试分批进行查询,这样可以减轻单次查询的压力,避免超时。 java for (int i = 0; i < totalRows; i += batchSize) { String sql = "SELECT FROM table WHERE id > ? LIMIT ?"; List> results = jdbcTemplate.query(sql, new Object[]{i, batchSize}, new RowMapper>() { @Override public Map mapRow(ResultSet rs, int rowNum) throws SQLException { return toMap(rs); } }); } 3. 提高硬件资源 最后,我们还可以考虑提高硬件资源,比如增加CPU核心数,增加内存容量等,这样可以提供更多的计算能力,从而提高查询速度。 四、总结 总的来说,SQL查询超时是一个常见的问题,我们需要从多个方面来考虑解决方案。不论是手写SQL语句,还是真正去执行这些命令的时候,我们都得留个心眼儿,注意做好优化工作,别让查询超时这种尴尬情况出现。同时呢,我们也得接地气,瞅准实际情况,灵活调配硬件设施,确保有充足的运算能力。这样一来,才能真正让数据处理跑得既快又稳,不掉链子。希望这篇文章能对你有所帮助。
2023-06-23 23:10:05
231
人生如戏-t
JSON
在实际的数据处理与分析工作中,格式转换的需求日益增多,尤其在大数据时代背景下,不同系统间的数据交换、迁移以及进一步的数据挖掘和可视化需求催生了对高效格式转换工具的依赖。近期,Python社区不断优化和完善pandas库的功能,使其在处理json、csv等常见数据格式时更加得心应手。 实际上,除了json转csv之外,pandas还支持从Excel、SQL数据库等多种数据源进行读取,并可将数据导出为包括HTML、JSON、Feather等多种格式。例如,最新版本的pandas已经增强了对Apache Arrow的支持,使得在Parquet或Feather格式之间的高速转换成为可能,这对于大规模数据分析项目来说无疑是一大利好。 此外,随着AI和机器学习的发展,对于非结构化数据如json的处理要求越来越高。许多研究者开始探索如何结合诸如Dask这样的并行计算库,利用pandas接口实现对大型json文件的分布式读取和转换,从而有效提升json到csv或其他格式的转换效率。 值得注意的是,在执行格式转换的过程中,不仅要关注速度和便利性,还需兼顾数据完整性和准确性。特别是在处理嵌套复杂结构的json数据时,需要精心设计转换逻辑以确保信息无损。因此,深入理解目标格式特性以及熟练运用相关工具库显得尤为重要。 综上所述,数据格式转换是现代数据分析工作中的基础技能之一,而Python生态下的pandas库正以其强大且灵活的功能持续满足着这一领域的各种需求,与时俱进地推动着数据分析技术的发展。
2024-01-01 14:07:21
433
代码侠
Apache Pig
在大数据处理领域,Apache Pig作为Hadoop生态系统中的关键组件,其数据分区和分桶功能对于提升分析效率至关重要。实际上,近年来随着技术的不断演进,不仅Apache Pig在持续优化其内置函数以适应更复杂的数据处理需求,其他大数据处理框架如Spark SQL、Hive等也对数据分区与分桶策略进行了深度支持。 例如,Apache Spark通过DataFrame API提供了灵活且高效的分区操作,并结合其强大的内存计算能力,在处理大规模数据时可以显著提升性能。Spark中通过partitionBy方法进行数据分桶,用户可以根据业务需求定制分区列和数量,实现数据在集群内的均衡分布和快速访问。 同时,Hive作为基于Hadoop的数据仓库工具,其表设计阶段就允许用户指定分区列和桶列,进一步细化数据组织结构,便于执行SQL查询时能快速定位所需数据块,减少I/O开销。近期发布的Hive 3.x版本更是增强了动态分区裁剪功能,使得数据分区的利用更为高效。 值得注意的是,尽管数据分区和分桶能够有效提高数据处理性能,但在实际应用中仍需谨慎考虑数据倾斜问题和存储成本。因此,在设计数据分区策略时应结合业务场景,合理选择分区键和桶的数量,确保性能优化的同时兼顾系统的稳定性和资源利用率。 此外,随着云原生时代的到来,诸如AWS Glue、Azure Data Factory等云服务也集成了类似的数据分区和管理功能,这些服务不仅能简化大数据处理流程,还为用户提供了自动化的数据优化方案,进一步推动了大数据处理技术的发展与进步。
2023-06-07 10:29:46
431
雪域高原-t
Greenplum
...了Greenplum数据库中数据类型转换的问题与解决方案后,我们发现正确处理数据类型是确保数据分析准确性和系统稳定性的重要环节。近期,随着大数据和云计算技术的快速发展,数据类型的管理与转换在实际应用场景中的重要性日益凸显。 2022年5月,PostgreSQL(Greenplum基于其构建)发布了最新版本14,其中包含了对数据类型转换功能的重大改进与优化。例如,新版本增强了JSON和JSONB类型与其他数据类型间的转换能力,并引入了更灵活的类型转换函数,有助于降低用户在处理复杂数据结构时遭遇类型转换错误的风险。 此外,业内专家强调,在进行大规模分布式计算时,尤其是在使用如Apache Spark或Flink等现代大数据处理框架对接Greenplum时,了解并掌握数据类型转换的最佳实践至关重要。有研究指出,通过预处理阶段的数据清洗、类型检查以及合理利用数据库内置的转换机制,可有效预防因类型不匹配引发的问题,进一步提升整体系统的性能与效率。 因此,对于Greenplum使用者来说,持续关注数据库系统的发展动态,结合实际业务需求深入了解和应用不同类型转换的方法,将极大地助力于实现高效精准的数据分析和决策支持。同时,参考相关的最佳实践文档和社区案例分享,也是提升技术水平、避免潜在问题的良好途径。
2023-11-08 08:41:06
598
彩虹之上-t
Datax
在大数据领域,Datax作为阿里云开源的数据同步工具,因其高效稳定的数据迁移能力广受业界认可。然而,在实际运维过程中,类似“读取HDFS文件时NameNode联系不上”的问题并非孤立事件。随着分布式存储和计算技术的不断发展,如何确保关键服务如NameNode的高可用性成为大数据从业者关注的重点。 近期,Apache Hadoop社区发布了最新的3.3.x版本,对HDFS的稳定性及容错性进行了显著提升,包括改进NameNode的故障切换机制、优化网络通信协议等,从而降低此类连接失败的风险。此外,对于复杂网络环境下的防火墙策略配置,有专家建议采用SDN(Software-Defined Networking)技术进行智能管理,以自动适应不同服务间的端口需求,避免因人为误配导致的服务中断。 同时,针对大规模数据迁移场景下的挑战,业内研究者正积极探索基于容器化和Kubernetes编排技术的新一代数据同步解决方案,旨在通过灵活调度和资源优化进一步提高Datax等工具的性能表现和容错能力。这些前沿动态和实践经验为我们解决类似Datax与HDFS交互中出现的问题提供了新的思路和方法论,值得广大技术人员深入学习和借鉴。
2023-02-22 13:53:57
551
初心未变-t
Hadoop
...Hadoop在现代大数据处理领域的实际应用和最新发展动态显得尤为重要。Apache Hadoop作为开源大数据处理平台的核心组件,近年来不断优化升级,新版本中对YARN资源管理器的强化、安全性能的提升以及对云原生环境的更好适应,使其在实时分析、机器学习及AI领域展现更强大的实力。 例如,Hadoop 3.3.0版本引入了多项改进,包括支持可插拔的存储层以满足不同场景下的存储需求,以及改进NameNode的高可用性设计,显著提升了整个集群的稳定性和数据恢复效率。同时,随着Kubernetes等容器编排系统的普及,Hadoop生态系统也正在积极拥抱云原生技术,通过如Kubernetes on Hadoop(KoP)项目实现与K8s的深度融合,为用户提供更加灵活、高效的资源管理和部署方案。 此外,值得注意的是,在企业级应用场景中,Hadoop不仅需要正确配置和管理,还需要结合诸如Hive、Spark、Flink等周边工具进行复杂的数据处理和分析任务,并且在运维层面关注日志监控、故障排查、性能调优等问题。因此,深入研究和实践Hadoop生态体系,对于任何希望从海量数据中挖掘价值的企业或个人来说,都是不可或缺的关键步骤。
2023-06-02 09:39:44
477
月影清风-t
Kibana
...ful 风格的搜索和数据分析引擎,基于 Apache Lucene 构建,能够实现近实时搜索,并且支持 PB 级别的数据。在本文语境中,Kibana 作为 Elasticsearch 的一个重要组成部分,主要用于对存储在 Elasticsearch 中的数据进行可视化展示和分析。 Kibana , Kibana 是一款开源的数据可视化工具,与 Elasticsearch 结合使用,可以将复杂的数据转化为易于理解的图表、仪表板等形式,帮助用户快速洞察大规模数据集中的模式、趋势和相关性。在文章中,作者详细阐述了当 Kibana 显示数据不准确或错误时,应如何从数据源、配置问题及数据质量三个方面查找原因并提供解决方案。 数据质量管理 , 数据质量管理是一种系统化的方法论,旨在确保组织内所有数据的质量、一致性和准确性。它涵盖了数据生命周期的全过程,包括数据收集、清洗、整合、存储、分析以及使用等多个阶段。在本文中,作者强调了数据质量管理的重要性,指出如果数据质量差,那么即便是在强大的数据分析工具如 Kibana 上展示的结果也会出现偏差,因此建议用户要重视原始数据的校验、清洗和异常值处理等环节,以提高数据分析结果的真实性和有效性。
2023-06-30 08:50:55
317
半夏微凉-t
SeaTunnel
在当今大数据时代,数据处理与分析工具的重要性日益凸显。SeaTunnel作为一款受到业界广泛认可的大数据处理工具,其性能优化及使用体验的提升一直是开发者和用户关注的重点。近期,SeaTunnel团队正积极研发新版本,针对界面响应速度、资源占用效率等方面进行深度优化,旨在解决大文件读取延迟、内存管理效能低下等问题。 同时,随着云计算技术的发展,SeaTunnel也积极探索云端部署的可能性,通过整合云服务的弹性伸缩能力,可以有效应对大规模数据处理场景下的硬件资源配置难题。此外,借助容器化和微服务架构,SeaTunnel有望实现更高效的数据并行处理能力和网络传输效率,进一步改善用户体验。 实践中,企业用户可以根据自身业务需求选择合适的硬件环境、网络配置以及数据处理策略。例如,在面对超大数据集时,除了采用分批处理的方式外,还可以结合实时流处理技术,对数据进行实时或近实时的增量处理,降低系统压力的同时保证数据分析的时效性。 总之,理解并解决影响SeaTunnel等大数据工具性能的因素,既需要紧跟软件更新的步伐,不断优化技术栈,又需结合实际业务场景灵活运用多种策略和技术手段。未来,随着技术持续演进,我们期待SeaTunnel能为企业级用户提供更加流畅、高效的海量数据处理解决方案。
2023-12-06 13:39:08
205
凌波微步-t
DorisDB
...入了解DorisDB数据库SQL语句性能调优的基础策略后,近期的一篇技术博客进一步阐述了DorisDB在大规模数据处理和实时分析场景中的实际应用案例。作者分享了某大型互联网公司如何通过深度定制索引策略与分区优化,成功将关键业务查询速度提升了30%以上,极大地提高了数据分析效率和用户体验。 同时,随着Apache Doris社区的持续发展,其最新版本中引入了更多高级特性以降低磁盘I/O操作。例如,动态分区选择功能可以根据查询条件自动定位所需分区,减少不必要的数据读取;而Bloom Filter的实现也更加成熟,支持用户自定义配置,并已在某些复杂过滤条件下显著减少了无效磁盘访问。 另外,值得关注的是,DorisDB团队正在积极探索并行计算、列式存储等前沿技术在系统内部的整合应用,旨在进一步提升海量数据下的查询性能。近期的技术白皮书详细解读了这些新特性的设计理念和技术路线图,为数据库管理员和开发者提供了更为丰富且深入的性能调优思路。 综上所述,无论是实践经验的总结还是技术创新的前瞻,都表明DorisDB在SQL语句性能调优方面的潜力巨大,值得广大数据库从业者深入研究和实践。与时俱进地关注社区动态与技术革新,将有助于我们在实际工作中更好地驾驭这一强大的开源数据库系统,应对日益增长的数据挑战。
2023-05-04 20:31:52
524
雪域高原-t
Datax
在处理大数据传输和交换任务时,Datax作为一款高效的数据同步工具,其最大行数限制问题的解决方案具有广泛的应用价值。近期,随着数据量爆炸式增长,越来越多的企业和团队在使用Datax进行大规模数据迁移或整合过程中,可能会频繁遭遇此类问题。因此,深入理解和灵活应对这一限制显得尤为重要。 在实际操作中,不仅需要根据数据量合理分批处理,还应关注Datax的并发配置优化以及数据库表结构设计,如MySQL、Oracle等目标库可能存在的max insert row count参数设置。同时,通过实时监控系统性能与资源占用情况,可以更精准地调整Datax作业参数,以适应不断变化的数据处理需求。 此外,随着技术的发展,不少云服务商也针对此类场景推出了更高级别的数据迁移服务,支持自动分片、动态扩容等功能,从而有效避免单次操作的数据量限制问题。例如,阿里云推出的DTS(Data Transmission Service)就提供了超大数据量下的稳定、高效迁移方案,用户无需过于关注底层细节,即可实现大规模数据的无缝迁移。 总之,在面对Datax或其他数据同步工具的最大行数限制挑战时,一方面要掌握并运用现有工具的高级配置技巧,另一方面也要关注业界最新的数据迁移服务和技术趋势,以提升整体数据处理效率和可靠性,更好地满足业务发展对数据处理能力的需求。
2023-08-21 19:59:32
525
青春印记-t
Flink
... FlinkJob数据冷启动可重用性问题 大家好,我是你们的老朋友,今天要和大家聊聊一个我最近在项目中遇到的技术难题——FlinkJob数据冷启动的可重用性问题。这可是个让我头疼的问题,但经过一番折腾后,我发现了解决方案。废话不多说,让我们直接进入正题吧! 1. 理解问题背景 首先,我们得明白什么是数据冷启动。简单来说,就是当你的应用刚启动或者重启时,没有任何历史状态可以用来快速恢复。遇到这种情况,系统就得从零开始处理所有数据,这过程就像蜗牛爬行一样慢,还可能拖累整个系统的运行速度。 在Flink中,这个问题尤为突出。Flink是个流处理框架,要保证不出错和跑得快,就得靠状态管理帮忙。如果每次启动都需要重新初始化所有状态,那效率肯定不高。所以啊,怎么能让Flink任务在数据刚“醒过来”时迅速找回自己的状态,就成了我们急需搞定的大难题。 2. 探索解决方案 2.1 使用Checkpoint机制 Flink提供了一种叫Checkpoint的机制,它可以定期保存应用程序的状态到外部存储(比如HDFS)。这样一来,就算应用重启了,也能从最近的存档点恢复状态,这样就能快点儿恢复正常,不用让咱们干等着了。 java StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); env.enableCheckpointing(5000); // 每隔5秒做一次Checkpoint 这段代码开启了Checkpoint机制,并且每隔5秒钟保存一次状态。这样,即使应用重启,也可以从最近的Checkpoint快速恢复状态。 2.2 利用Savepoint 除了Checkpoint,Flink还提供了Savepoint的功能。Savepoint就像是给应用设的一个书签,当你点击它时,就能把当前的应用状态整个保存下来。这样,如果你想尝试新版本,但又担心出现问题,就可以用这个书签把应用恢复到你设置它时的样子。简单来说,它就是一个让你随时回到“原点”的神奇按钮! java env.saveCheckpoint("hdfs://path/to/savepoint"); 通过这段代码,我们可以手动创建一个Savepoint。以后如果需要恢复状态,可以直接从这个Savepoint启动应用。 2.3 状态后端选择 Flink支持多种状态后端(如RocksDB、FsStateBackend等),不同的状态后端对性能和持久性有不同的影响。在选择状态后端时,需要根据具体的应用场景来决定。 java env.setStateBackend(new RocksDBStateBackend("hdfs://path/to/state/backend")); 例如,上面的代码指定了使用RocksDB作为状态后端,并且配置了一个HDFS路径来保存状态数据。RocksDB是一个高效的键值存储引擎,非常适合大规模状态存储。 3. 实际案例分析 为了更好地理解这些概念,我们来看一个实际的例子。想象一下,我们有个应用能即时追踪用户的每个动作,那可真是数据狂潮啊,每一秒都涌来成堆的信息!如果我们不使用Checkpoint或Savepoint,每次重启应用都要从头开始处理所有历史数据,那可真是太折腾了,肯定不行啊。 java DataStream input = env.addSource(new KafkaConsumer<>("topic", new SimpleStringSchema())); input .map(new MapFunction>() { @Override public Tuple2 map(String value) throws Exception { return new Tuple2<>(value.split(",")[0], Integer.parseInt(value.split(",")[1])); } }) .keyBy(0) .sum(1) .addSink(new PrintSinkFunction<>()); env.enableCheckpointing(5000); env.setStateBackend(new FsStateBackend("hdfs://path/to/state/backend")); 在这个例子中,我们使用了Kafka作为数据源,然后对输入的数据进行简单的映射和聚合操作。通过开启Checkpoint并设置好状态后端,我们确保应用即使重启,也能迅速恢复状态,继续处理新数据。这样就不用担心重启时要从头再来啦! 4. 总结与反思 通过上述讨论,我们可以看到,Flink提供的Checkpoint和Savepoint机制极大地提升了数据冷启动的可重用性。选择合适的状态后端也是关键因素之一。当然啦,这些办法也不是一用就万事大吉的,还得根据实际情况不断调整和优化呢。 希望这篇文章能帮助你更好地理解和解决FlinkJob数据冷启动的可重用性问题。如果你有任何疑问或者有更好的解决方案,欢迎在评论区留言交流!
2024-12-27 16:00:23
37
彩虹之上
Datax
随着大数据时代的到来,数据集成和同步工具的重要性日益凸显。DataX作为阿里巴巴开源的数据传输利器,在实际业务场景中发挥着关键作用。近期,阿里云官方持续优化DataX的功能,以适应更复杂多变的数据处理需求。例如,新增对更多数据源的支持,如Kafka、MongoDB等,使得用户可以更方便地进行实时流数据的采集与迁移。 同时,为了提升大规模数据同步的性能和稳定性,DataX在任务调度、错误重试策略等方面也进行了深度优化。结合阿里云的其他服务,比如MaxCompute(原ODPS)的大数据计算能力,企业能够构建起从数据获取、清洗、转换到分析的一体化解决方案,大大提升了数据驱动决策的效率。 此外,对于日志数据的处理和分析,业界也有不少新的趋势和实践。例如,通过AI和机器学习技术,可以实现对海量日志的智能解析和异常检测,从而挖掘出更有价值的信息。而DataX在这个过程中扮演了“桥梁”角色,将各类日志数据高效地汇集至统一的数据平台,为后续的深度分析和应用打下坚实基础。 因此,了解并掌握DataX这类强大的数据集成工具,不仅有助于解决眼前的数据同步问题,更能顺应时代发展,为企业数字化转型提供有力支持。建议读者关注阿里云DataX的最新动态和技术文档,同时深入研究相关的大数据处理和分析方法,以应对不断涌现的新挑战。
2023-09-12 20:53:09
514
彩虹之上-t
Greenplum
在当今快速发展的大数据领域,Greenplum作为一款基于MPP架构的开源大数据平台,持续吸引着业界的关注。近期,Pivotal公司(Greenplum的主要开发和维护者)宣布了其最新版本的Greenplum数据库,进一步优化了大规模数据处理性能,并增强了对实时分析任务的支持,这无疑为那些需要深度挖掘数据价值的企业提供了更为强大的武器。 此外,随着云原生技术的普及,Greenplum也积极拥抱这一趋势,支持在各大公有云平台上部署,实现弹性扩展和按需使用,有效降低了企业的运维成本。同时,Greenplum还集成了机器学习、AI等先进技术,用户能够直接在数据库层面进行复杂的数据模型训练和预测分析,大大提升了数据分析的工作效率。 值得关注的是,由于Greenplum与PostgreSQL的紧密关系,用户可以享受到PostgreSQL生态系统的丰富资源,包括各类插件、工具以及庞大的开发者社区支持。最近一篇来自《Database Trends and Applications》的深度报道中,详细解读了Greenplum如何通过借鉴和融合PostgreSQL的技术优势,实现了在海量数据处理场景下的卓越表现。 综上所述,无论是从最新的技术更新,还是从行业发展趋势来看,Greenplum都在持续巩固其在大数据处理领域的领先地位,对于寻求高效、灵活且具有前瞻性的数据解决方案的企业来说,深入研究和应用Greenplum将是一个极具价值的选择。
2023-11-11 13:10:42
460
寂静森林-t
Kylin
在大数据分析领域,Apache Kylin与ZooKeeper的高效协同工作至关重要。近期,Apache Kylin社区发布了新版本更新,针对项目稳定性及与ZooKeeper通信效率进行了深度优化,不仅提升了对大规模数据处理能力,还增强了对异常情况的自愈和诊断功能。用户在部署和使用最新版Kylin时,可以参考官方文档进行配置检查和更新,确保其与ZooKeeper之间的通信更为稳定可靠。 此外,随着云原生技术的发展,业内也在探索如何将Apache Kylin更好地融入Kubernetes等容器化环境,并借助Service Mesh等新型微服务架构改善服务间通信,包括与ZooKeeper的交互方式。例如,在某大型互联网公司的实践案例中,通过Istio实现服务网格管理后,显著减少了由于网络波动等因素造成的Kylin与ZooKeeper通信故障,进一步提高了实时数据分析系统的可用性和响应速度。 同时,对于ZooKeeper自身的运维和优化也不容忽视。相关研究指出,通过对ZooKeeper集群进行合理的负载均衡、监控预警以及数据持久化策略调整,能够有效预防服务器故障带来的影响,从而为上层应用如Apache Kylin提供更加稳定的服务支撑。因此,在解决Kylin与ZooKeeper通信问题的同时,也需关注底层基础设施的持续优化和升级。
2023-09-01 14:47:20
107
人生如戏-t
MySQL
...一步探索其在实际应用场景中的最新发展和优化策略。近年来,随着Elasticsearch 7.x版本的发布,对join查询的支持有了显著变化。Elasticsearch官方推荐使用Nested数据类型或Parent-Child关系来替代传统的SQL式join,以适应分布式搜索引擎的架构特性,提高大规模数据处理下的性能表现。 例如,在电商领域,用户行为日志、商品信息和订单数据往往分散存储在不同的索引中。借助Elasticsearch的Nested数据类型,可以在单个索引内部实现类似join的效果,减少跨索引查询带来的延迟和资源消耗。同时,Elasticsearch团队不断优化内存管理和查询执行计划,使得处理复杂关联查询的效率得到提升。 另外,针对大数据时代下对实时性要求极高的场景,如实时风控和智能推荐,业界开始采用更先进的技术方案,如图数据库与Elasticsearch结合的方式,通过图形模型表达实体间的关系,从而实现实时高效的多表关联查询。 综上所述,尽管Elasticsearch的join类型在特定场景下存在局限性,但通过持续的技术创新和最佳实践的应用,我们能够有效克服这些挑战,并充分利用Elasticsearch的优势服务于多元化的企业级搜索与分析需求。对于广大开发者和数据工程师而言,紧跟Elasticsearch的最新发展趋势,灵活运用各种查询方式,将有助于提升系统的整体性能和用户体验。
2023-12-03 22:57:33
46
笑傲江湖_t
ElasticSearch
在实际应用中,将关系数据库的数据迁移至ElasticSearch并不仅仅是创建索引、批量导入数据以及执行搜索查询那么简单。随着技术的不断迭代更新,ElasticSearch在近年来推出了更多的高级功能与优化策略,如实时数据分析、机器学习集成等。例如,配合Elastic Stack中的Logstash工具,可以实现对关系数据库日志的实时抓取和结构化处理,然后无缝导入到ElasticSearch中进行复杂查询与分析。 2021年,Elasticsearch 7.13版本推出了一项名为“Transforms”的新功能,它允许用户直接在Elasticsearch内部定义数据管道,从原始索引中提取、转换并加载数据到新的索引,极大地简化了数据预处理流程。这意味着,在从关系数据库迁移到ElasticSearch的过程中,可以直接在目标系统内完成数据清洗和转换工作,不仅减少了数据传输延迟,还提升了整体系统的稳定性和效率。 此外,对于大规模数据迁移项目,还需要考虑性能调优、分布式架构下的数据一致性问题以及安全性等方面的挑战。近期的一篇来自InfoQ的技术文章《Elasticsearch实战:从关系数据库迁移数据的最佳实践》深入探讨了这些话题,并结合实际案例给出了详细的解决方案和最佳实践建议。 因此,对于想要深入了解如何高效、安全地将关系数据库数据迁移至ElasticSearch的读者来说,紧跟最新的技术动态,研读相关实战经验和行业白皮书,将有助于更好地应对大数据时代下复杂的数据管理和分析需求。
2023-06-25 20:52:37
456
梦幻星空-t
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
!$
- 引用上一条命令的最后一个参数。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"