分布式文档查重系统实现与思考

前言

为了学习分布式系统,于是做了这个项目来练练手,这篇文章记录了这次实战的思考和踩过的坑。由于刚入门,因而文章可能会有错误,请读者勘误。

简单概述

项目采用 Spark 和 HDFS 做分布式计算和存储,利用 Spring Boot 提供 Web 服务,利用 Redis 存储任务标识符以便于集群扩展。

用户上传包含 Word 文档的压缩文件,Web 服务器所在机器解压压缩文件,接着提取文档内容并分词,然后将结果存储至 HDFS 上,再利用 Spark 进行相似度计算并返回结果。

HDFS 依赖问题

搭建 HDFS 很简单只需做简单配置便可,但问题都出在操作文件的代码编写上。

先是依赖问题,官网及网上都没有具体 Hadoop 依赖说明(也可能自己没找到),导致对需要导入那些依赖包很疑惑,下面是自己测试的操作 HDFS 所需要的最小依赖。

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-common</artifactId>
    <version>${hadoop.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-hdfs-client</artifactId>
    <version>${hadoop.version}</version>
</dependency>

HDFS 配置问题

获取 FileSystem 实例前需要创建一个 Configuration 实例,而在这之前必须设置本地 Hadoop 的目录,和设置远程机器的用户名。虽然这样做才能不报错,但一直不明白为什么操作远程机器的 HDFS,还需要本地安装的 Hadoop 目录。不过官方也提供了 HDFS 的 REST API,可以不依赖本地安装 Hadoop。

System.setProperty("HADOOP_USER_NAME", userName);
System.setProperty("hadoop.home.dir", home);
Configuration conf = new Configuration();
FileSystem.get(new URI("hdfs://host:port"), conf);

Spark 序列化问题

利用 Spark 进行计算时,最主要先获取 JavaSparkContext 的实例,以下为创建其实例的流程。

SparkConf conf = new SparkConf();
conf.setMaster("spark://host:port");
conf.setAppName("demo");
JavaSparkContext context = new JavaSparkContext(conf);

看似挺简单的流程,但问题就出在集群模式上。若是本地模式即指定 conf.setMaster("local") 进行调试,进行计算的代码可以完美运行,但是集群模式上就会出现序列化问题。

由于需要将代码分发给 Slave 节点的 Worker 进行计算,所以会产生代码的网络传输,而为了减少网络传输的延迟,Spark 只会分发部分代码,所以分发的代码若是不能进行序列化就会产生问题。

还有集群模式必须指定计算代码的 Jar 包路径,为了减少 Jar 的大小利于传输,采用了重新建立一个项目方案,然后在将该项目作为依赖导入主项目中,下面为利用计算代码中的 ComputingTask 来获取 Jar 包的路径。

String jarFile = ComputingTask.class.
				getProtectionDomain().getCodeSource().getLocation().getFile();
context.addJar(jarFile);

Spark 数据源问题

数据源问题同样也是集群所导致的,本地模式下运行可以使用本地文件,但若是集群模式,由于 Slave 节点的 Woker 获取不到本地文件就会报错。因而数据源必须选择那些能远程使用的,例如分布式文件系统、数据库或者 FTP 服务器上的文件。

context.textFile("hdfs://host:port/test.txt"); // Don't use local file in cluster mode.

分词组件加载问题

项目中需要中文分词,所以选用了 Word 分词组件,但是每次头次加载都会花费很长时间,于是必须进行预加载,解决方案可以在该项目的 issue 中找到。

相似度计算

由于对该方面的算法了解不过,所以对文档的相似度计算,采用了简单地对两个文档进行杰卡德相似系数的计算,其定义为A与B交集的大小与A与B并集的大小的比值,下面为公式:

J(A,B) = |A ^ B| / |A v B|

项目计划

  • 提供多种相似度的计算算法
  • 提供 Dockerfile 方便环境的搭建
  • 改造项目的简陋前端界面
  • 解决无法清理临时文件问题
  • 解决回收任务标识符问题
  • 提供 Word 文档实时预览

项目地址为 https://github.com/linzhehuang/docdetect,觉得不错的话欢迎 Star !

posted @ 2019-03-27 08:25  ZachLim  阅读(843)  评论(0编辑  收藏  举报