Spark Java API 计算 Levenshtein 距离

上一篇文章中,完成了Spark开发环境的搭建,最终的目标是对用户昵称信息做聚类分析,找出违规的昵称。聚类分析需要一个距离,用来衡量两个昵称之间的相似度。这里采用levenshtein距离。现在就来开始第一个小目标,用Spark JAVA API 计算字符串之间的Levenshtein距离。

1. 数据准备

样本数据如下:

{"name":"Michael", "nick":"Mich","age":50}

{"name":"Andy", "nick":"Anc","age":30}

{"name":"Anch", "nick":"MmAc","age":19}

把数据保存成文件并上传到hdfs上:./bin/hdfs dfs -put levestein.json /user/panda

2. 代码实现

定义一个类表示样本数据:

    public static class User{
private String name;
private String nick;
private int age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getNick() {
return nick;
} public void setNick(String nick) {
this.nick = nick;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
}

创建SparkSession

SparkSession sparkSession = SparkSession.builder()
.appName("levenshtein example")
.master("spark://172.25.129.170:7077")
.config("spark.some.config.option", "some-value")
.getOrCreate();

在Spark命令行./bin/pyspark 启动Spark时,会默认创建一个名称为 spark 的SparkSession。而这里是写代码,也需要创建SparkSession对象。

The SparkSession instance is the way Spark executes user-defined

manipulations across the cluster. There is a one-to-one correspondence between a SparkSession and

a Spark Application.

定义数据类型

Encoder<User> userEncoder = Encoders.bean(User.class);

JAVA里面定义了一套数据类型,比如java.util.String是字符串类型;类似地,Spark也有自己的数据类型,因此Encoder就定义了如何将Java对象映射成Spark里面的对象。

Used to convert a JVM object of type T to and from the internal Spark SQL representation.

To efficiently support domain-specific objects, an Encoder is required. The encoder maps the domain specific type T to Spark's internal type system. For example, given a class Person with two fields, name (string) and age (int), an encoder is used to tell Spark to generate code at runtime to serialize the Person object into a binary structure. This binary structure often has much lower memory footprint as well as are optimized for efficiency in data processing (e.g. in a columnar format). To understand the internal binary representation for data, use the schema function.

构建Dataset:

Dataset<User> userDataset = sparkSession.read().json(path).as(userEncoder);

说明一下Dataset与DataFrame区别,Dataset是针对Scala和JAVA特有的。Dataset是有类型的,Dataset的每一行是某种类型的数据,比如上面的User类型。

A Dataset is a strongly typed collection of domain-specific objects that can be transformed in parallel using functional or relational operations. Each Dataset also has an untyped view called a DataFrame, which is a Dataset of Row.

而DataFrame的每一行的类型是Row(看官方文档,我就这样理解了,哈哈。。)

DataFrame is represented by a Dataset of Row。While, in Java API, users need to use Dataset<Row> to represent a DataFrame.

这个图就很好地解释了DataFrame和Dataset的区别。

计算levenshtein距离,将之 transform 成一个新DataFrame中:

Column lev_res = functions.levenshtein(userDataset.col("name"), userDataset.col("nick"));
Dataset<Row> leveDataFrame = userDataset.withColumn("distance", lev_res);

完整代码

import org.apache.spark.sql.*;

public class LevenstenDistance {
public static class User{
private String name;
private String nick;
private int age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getNick() {
return nick;
} public void setNick(String nick) {
this.nick = nick;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
} public static void main(String[] args) {
SparkSession sparkSession = SparkSession.builder()
.appName("levenshtein example")
.master("spark://172.25.129.170:7077")
.config("spark.some.config.option", "some-value")
.getOrCreate();
String path = "hdfs://172.25.129.170:9000/user/panda/levestein.json";
Encoder<User> userEncoder = Encoders.bean(User.class);
Dataset<User> userDataset = sparkSession.read().json(path).as(userEncoder);
userDataset.show(); Column lev_res = functions.levenshtein(userDataset.col("name"), userDataset.col("nick"));
Dataset<Row> leveDataFrame = userDataset.withColumn("distance", lev_res);
// userDataset.show();
leveDataFrame.show();
System.out.println(lev_res.toString());
}
}

原来的Dataset:

计算Levenshtein距离后的得到的DataFrame:

根据上面的示例,下面来演示一下一个更实际点的例子:计算昵称和签名之间的levenshtein距离,若levenshtein距离相同,就代表该用户的 昵称 和 签名 是相同的:

数据格式如下:

{"nick":"赖求","uid":123456}

{"details":"时尚是一种态度,时尚第一品牌。看我的。","nick":"冰冷世家@蹦蹦","signature":"轻装时代看我的。艾莱依时尚羽绒服。。","uid":123456}

{"nick":"[潗團軍-6]明 明『招 募』","signature":"我是来擂人的,擂死人不偿命!","uid":123456}

  1. 加载数据

            Dataset<Row> dataset = spark.read().format("json")
    .option("header", "false")
    .load("hdfs://172.25.129.170:9000/user/panda/profile_noempty.json");

  2. 取出昵称和签名

            //空字符串 与 null 是不同的
    Dataset<Row> nickSign = dataset.filter(col("nick").isNotNull())
    .filter(col("signature").isNotNull())
    .select(col("nick"), col("signature"), col("uid"));

  3. 计算昵称和签名的Levenshtein距离

    Column lev_distance = functions.levenshtein(nickSign.col("nick"), nickSign.col("signature"));
    Dataset<Row> nickSignDistance = nickSign.withColumn("distance", lev_distance);

  4. 按距离进行过滤

    Dataset<Row> sameNickSign = nickSignDistance.filter("distance = 0");

这样就能找出昵称和签名完全一样的用户了。

原文:https://www.cnblogs.com/hapjin/p/9954191.html

Spark Java API 计算 Levenshtein 距离的更多相关文章

  1. Spark Java API 之 CountVectorizer

    Spark Java API 之 CountVectorizer 由于在Spark中文本处理与分析的一些机器学习算法的输入并不是文本数据,而是数值型向量.因此,需要进行转换.而将文本数据转换成数值型的 ...

  2. 在 IntelliJ IDEA 中配置 Spark(Java API) 运行环境

    1. 新建Maven项目 初始Maven项目完成后,初始的配置(pom.xml)如下: 2. 配置Maven 向项目里新建Spark Core库 <?xml version="1.0& ...

  3. spark (java API) 在Intellij IDEA中开发并运行

    概述:Spark 程序开发,调试和运行,intellij idea开发Spark java程序. 分两部分,第一部分基于intellij idea开发Spark实例程序并在intellij IDEA中 ...

  4. spark java API 实现二次排序

    package com.spark.sort; import java.io.Serializable; import scala.math.Ordered; public class SecondS ...

  5. spark java api数据分析实战

    1 spark关键包 <!--spark--> <dependency> <groupId>fakepath</groupId> <artifac ...

  6. 【Spark Java API】broadcast、accumulator

    转载自:http://www.jianshu.com/p/082ef79c63c1 broadcast 官方文档描述: Broadcast a read-only variable to the cl ...

  7. 基于OpenStreetMap计算驾车距离(Java)

    最近公司有个项目需要计算6000个点之间的驾车距离,第一时间想到的是利用Google的Distance Matrix API,但是免费Key每天只能计算2500个元素(元素 = 起点数量 * 终点数量 ...

  8. Elasticsearch 2.3.3 JAVA api说明文档

    原文地址:https://www.blog-china.cn/template\documentHtml\1484101683485.html 翻译作者:@青山常在人不老 加入翻译:cdcnsuper ...

  9. Spark基础与Java Api介绍

    原创文章,转载请注明: 转载自http://www.cnblogs.com/tovin/p/3832405.html  一.Spark简介 1.什么是Spark 发源于AMPLab实验室的分布式内存计 ...

随机推荐

  1. PhpStorm 常用插件

    PhpStorm 插件 Dash : Dash 需要配合软件 Dash 使用. IdeaVim IdeaVim 对于习惯于使用 Vim 操作方式的人来说是个大福音. IdeaVim 也有默认配置, 可 ...

  2. Altium Designer 复制和粘贴功能

    在使用Altium Deigner时,很多时候会使用到复制和粘贴功能,Altium Designer复制分为三步:第一步选中要复制的内容(包括点选和框选),第二步,启动COPY命令,这时光标会变成十字 ...

  3. Django【跨域】

    jsonp 方式一:指定返回方法 # 后端 def view(request): callback = request.GET.get('callback') return HttpResponse( ...

  4. 实验吧 who are you

    看到ip,然后提示是要把ip写到数据库里面,就想到了x-forwarded-for注入 扔burp里面试一下 确实有这个问题,从返回信息里面估计出来,应该是盲注,而且基于时间的盲注,试一下吧 测试延迟 ...

  5. 基于element ui的级联选择器组件实现的分类后台接口

    今天在做资产管理系统的时候遇到一个分类的级联选择器,前端是用的element的组件,需要后台提供接口支持.     这个组件需要传入的数据结构大概是这样的,详细的可参考官方案例: [{ value: ...

  6. Activiti开发案例之activiti-app更换数据源

    前言 由于Activiti 默认使用的数据库是H2数据库,重启服务后相关数据会丢失.为了永久保存,所以要配置关系型数据库,这里我们选择 SqlServer ,有钱任性. 环境 Activiti6,Sq ...

  7. 06 Django REST Framework 版本控制

    01-版本控制 对接口进行版本控制只是一种杀死已部署客户端的“礼貌”方式. - 罗伊菲尔丁. 1. API版本控制允许您更改不同客户端之间的行为.REST框架提供了许多不同的版本控制方案. 2. 版本 ...

  8. 用Eclipse中的git提交代码流程

    有更新有提交 Commit到本地,pull,然后再push 提交 Commit到本地 或者直接commit and Push 更新 先对比然后pull或者右键项目直接pull 有冲突时 有冲突的时候优 ...

  9. git revert用法以及与git reset的区别

    git revert用法 git revert 撤销 某次操作,此次操作之前和之后的commit和history都会保留,并且把这次撤销 作为一次最新的提交 * git revert HEAD     ...

  10. 解决PHP乱码

    如果你的PHP页面出现了乱码,之需要在页面的开始处加入下面代码就可以了. <?php header("content-type:text/html;charset=utf-8" ...