Spark读取HDFS中的Zip文件
1. 任务背景
近日有个项目任务,要求读取压缩在Zip中的百科HTML文件,经分析发现,提供的Zip文件有如下特点(=>指代对应解决方案):
(1) 压缩为分卷文件 => 只需将解压缩在同一目录中的一个分卷zip即可解压缩出整个文件
(2) 压缩文件中又包含不同的两个文件夹,且各包含n个小zip文件,小zip文件中包含目录及对应的HTML文本文件
采用第一方案:依次解压缩各小zip文件,存放在一个目录中,然后上传到HDFS中
存在问题:每个小zip都包含上万个小文件,按照第一方案解压缩,耗费的时间太太太多了
(3) 解析的zip存在多文件的情况
(4) 数据总量共计50W
2. 优化方案
直接上传小zip文件,然后让Spark直接从zip文件中读取HTML文本,再使用jsoup解析,并存储至elasticsearch中。
实现过程中有一处需要注意! => 解析zip会遍历的ZipEntry,会识别文件夹和文件夹下的文件,即文件夹和文件在ZipEntry中被当成同类对象来对待。
例1:本地解析zip压缩文件demo
- import java.io.{BufferedInputStream, BufferedReader, FileInputStream, InputStreamReader}
- import java.util.zip.{ZipFile, ZipInputStream}
- import net.sf.json.JSONObject
- import org.jsoup.Jsoup
- import scala.collection.mutable
- object Test {
- def testZip(): Unit = {
- val baseDir = "part2/"
- val path = s"$baseDir\\06.zip"
- val zf = new ZipFile(path)
- val in = new BufferedInputStream(new FileInputStream(path))
- val zin = new ZipInputStream(in)
- var zipEn = zin.getNextEntry
- var count = 0
- try {
- while (zipEn != null) {
- if (!zipEn.isDirectory) {
- val buff = new BufferedReader(new InputStreamReader(zf.getInputStream(zipEn)))
- val sb = new StringBuilder()
- var line = buff.readLine()
- while (line != null) {
- count = count + 1
- if (line.nonEmpty) {
- sb.append(line.trim)
- }
- line = buff.readLine()
- }
- val id = zipEn.getName.substring(zipEn.getName.indexOf("/") + 1, zipEn.getName.indexOf("."))
- val doc = Jsoup.parse(sb.toString())
- val title = doc.select(".lemmaWgt-lemmaTitle-title h1").text()
- val sb1 = new mutable.StringBuilder()
- val eles = doc.select(".para")
- for (i <- 0 until eles.size()) {
- sb1.append(eles.get(i).text().trim).append("\t")
- }
- val json = new JSONObject()
- json.put("id", id)
- json.put("title", title)
- json.put("content", sb1.toString().trim)
- println(json)
- buff.close()
- }
- zipEn = zin.getNextEntry
- }
- zin.closeEntry()
- } catch {
- case _ =>
- }
- println(count)
- }
- }
例2:Spark读取HDFS中的含有多文件的zip文件
- def parseBaike(): Unit ={
- val baseDir = "/work/ws/temp/baike"
- val sc = new SparkContext(new SparkConf().setAppName("parseBaike"))
- val rdd = sc.binaryFiles(s"$baseDir/data/*.zip", 40)
- .flatMap{
- case (zipFilePath: String, content: PortableDataStream) => {
- val zis = new ZipInputStream(content.open())
- Stream.continually(zis.getNextEntry)
- .takeWhile(_ != null)
- .flatMap(zipEn => {
- if(zipEn.isDirectory) None
- else{
- // 基于文件名获取百科词条的id信息
- val id = zipEn.getName.substring(zipEn.getName.indexOf("/")+1, zipEn.getName.indexOf("."))
- val html = scala.io.Source.fromInputStream(zis, "UTF-8").getLines.mkString("")
- if(html.nonEmpty){
- val doc = Jsoup.parse(html)
- // 解析百科中的词条名称
- val title = doc.select(".lemmaWgt-lemmaTitle-title h1").text()
- // 获取词条HTML中的全部正文内容
- val sb = new mutable.StringBuilder()
- val eles = doc.select(".para")
- for(i <- 0 until eles.size()){
- sb.append(eles.get(i).text().trim).append("\t")
- }
- if(title.trim.nonEmpty && sb.toString.trim.nonEmpty){
- val json = new JSONObject()
- json.put("id", id)
- json.put("title", title)
- json.put("content", sb.toString().trim)
- Some(json)
- }else None
- }else None
- }
- })
- }
- }
- rdd.cache()
- rdd.saveAsTextFile(HDFSFileUtil.clean(s"$baseDir/result/json"))
- rdd.foreach(f => {
- // 保存在Es中
- ESHelper.saveToEs("baike", "baike", f, "id")
- })
- rdd.unpersist()
- sc.stop()
- }
注意:如上代码仅供参考,并隐去了部分业务相关代码,如HDFS和Es工具类,如若需要,可留言沟通交流!
3. 参考
(1) https://stackoverflow.com/questions/28569788/how-to-open-stream-zip-files-through-spark
Spark读取HDFS中的Zip文件的更多相关文章
- Spark读取HDFS文件,任务本地化(NODE_LOCAL)
Spark也有数据本地化的概念(Data Locality),这和MapReduce的Local Task差不多,如果读取HDFS文件,Spark则会根据数据的存储位置,分配离数据存储最近的Execu ...
- python读取hdfs上的parquet文件方式
在使用python做大数据和机器学习处理过程中,首先需要读取hdfs数据,对于常用格式数据一般比较容易读取,parquet略微特殊.从hdfs上使用python获取parquet格式数据的方法(当然也 ...
- 基于Python——实现解压文件夹中的.zip文件
[背景]当一个文件夹里存好好多.zip文件需要解压时,手动一个个解压再给文件重命名是一件很麻烦的事情,基于此,今天介绍一种使用python实现批量解压文件夹中的压缩文件并给文件重命名的方法—— [代码 ...
- 点滴积累【C#】---C#实现上传word以流形式保存到数据库和读取数据库中的word文件。
本文修改来源:http://www.cnblogs.com/zmgdpg/archive/2005/03/31/129758.html 效果: 数据库: 思路: 首先保存word到数据库:获取上传文件 ...
- Spark读取HDFS文件,文件格式为GB2312,转换为UTF-8
package iie.udps.example.operator.spark; import scala.Tuple2; import org.apache.hadoop.conf.Configur ...
- spark读取hdfs上的文件和写入数据到hdfs上面
def main(args: Array[String]): Unit = { val conf = new SparkConf() conf.set("spark.master" ...
- Spark 读取HDFS csv文件并写入hive
package com.grady import org.apache.spark.SparkConf import org.apache.spark.sql.{Row, SaveMode, Spar ...
- Spark读取Hbase中的数据
大家可能都知道很熟悉Spark的两种常见的数据读取方式(存放到RDD中):(1).调用parallelize函数直接从集合中获取数据,并存入RDD中:Java版本如下: JavaRDD<Inte ...
- spark读取hdfs数据本地性异常
在分布式计算中,为了提高计算速度,数据本地性是其中重要的一环. 不过有时候它同样也会带来一些问题. 一.问题描述 在分布式计算中,大多数情况下要做到移动计算而非移动数据,所以数据本地性尤其重要,因此我 ...
随机推荐
- git log master..origin/master --oneline | wc -l 怎么知道本地仓库是不是最新的
git log master..origin/master --oneline | wc -l 怎么知道本地仓库是不是最新的 git fetch # 一定要先 fetch git log mast ...
- Eclipse创建Servers没有Apache选项
help->install new software加入网址是http://download.eclipse.org/releases/Neon,最后一个是你eclipse的版本.得到一系列的插 ...
- Mapreduce案例之Pi值估算
题目: 这个程序的原理是这样的.假如有一个边长为1的正方形.以正方形的一个端点为圆心,以1为半径,画一个圆弧,于是在正方形内就有了一个直角扇形.在正方形里随机生成若干的点,则有些点是在扇形内,有些点是 ...
- 灵活部署django缓存,并使用
使用django内置的redis=============>pip3 install django-redisCACHES = { 'default':{ 'BACKEND':'django_r ...
- 读取根目录src下的指定配置properties文件内容
代码如下: package com.chen.system.util; import java.io.File; import java.io.FileInputStream; import java ...
- 字典(dict)
定义 In [4]: dt1 = {'name':'ray','age':18,'height':175} In [5]: dt1 Out[5]: {'name': 'ray', 'age': 18, ...
- SP4546 ANARC08A - Tobo or not Tobo IDA*
题意:
- kubernetes1.11.1 部署prometheus
部署前提:已经安装好了kubernetes的集群,版本是1.11.1,是用kubeadm部署的. 2台虚拟机:master:172.17.1.36 node1:172.17.1.40 pro ...
- css让文字,字母折行
加上如下的CSS设置,就是设定好宽度width,然后设置合适的word-wrap和word-break属性: ul li{ width: 100px; word-wrap: break-word; w ...
- pom标签大全
[原文链接]:Maven POM | 菜鸟教程 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&q ...