数据清洗(1)-- 使用 Spark 和 Edit Distance 去重合并

需求和场景:

某些数据字段会出现不同的值,比如以下数据

上海白玉兰计算机有限公司
上海市白玉兰计算机有限公司

中国科学院广州地化学研究所
中国科学院广州地球化学研究所

中国科学院广州地球化学研究所
中国科学院广州地化学研究所

吉林省福春木业有限公司
吉林省富春木业有限公司

河北富华康土特环保有限公司
富华康土特环保有限公司

中国科学院地球化学研究所
中国科学院广州地球化学研究所

深圳艾捷科技有限责任公司
深圳艾捷科技有限公司

大连工美企业有限责任公司
大连工美企业有限公司

芜湖市永嘉制衣有限公司
芜湖市永嘉制衣有限责任公司

中国科学院广州地球化学研究所
中国科学院地球化学研究所

这类数据有各特点就是差异很小,这样的数据可以通过字符的 edit distance 来表示相似度,通过过滤排序即可做一些简单处理,edit distance 是指针对字符串 A ,通过 insert , replace, delete 操作后变为 B 的步骤数,数值越低则表示两个字符串越相思,本文使用 commons-text 包中的 LevenshteinDistance 来计算字符串的 edit distance,数据集合内容如下:

sn,title
1,南昌市西湖区桃花医院
2,汉中汉台区宗营信用社公路街分社
3,费县探沂镇中心卫生院
4,广东省邮政公司揭阳市惠来县葵潭邮政局
5,深圳新合程供应链股份有限公司
6,中山市美立电器有限公司
7,青岛钢铁有限公司
8,台州市永耀塑业有限公司
9,永嘉县巨霸鞋业有限公司
10,芜湖市永嘉制衣有限公司
11,陕西天禄堂制药有限公司
...

下载地址:http://orfuc602j.bkt.clouddn.com/data-sets/repeat/repeat-500

解决思路:加载文件后,使用笛卡尔乘积获得任意两个公司数据的集合,然后计算 edit distance, 再排序输出即可,

mavn 依赖:

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>2.1.1</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.mongodb.spark</groupId>
            <artifactId>mongo-spark-connector_2.11</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.11</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-mllib_2.11</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.8</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-text</artifactId>
            <version>1.1</version>
        </dependency>

java 代码如下:

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.similarity.LevenshteinDistance;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;

import java.io.Serializable;

/**  * Created by liangdi on 6/12/17.  */
@Slf4j
public class EditDistanceTest {
    public static void main(String[] args) {
        JavaSparkContext ctx = SparkUtil.createContext();

        /**  * 数据结构  * sn,title  *  1,南昌市西湖区桃花医院  2,汉中汉台区宗营信用社公路街分社  3,费县探沂镇中心卫生院  4,广东省邮政公司揭阳市惠来县葵潭邮政局  5,深圳新合程供应链股份有限公司  6,中山市美立电器有限公司  7,青岛钢铁有限公司  8,台州市永耀塑业有限公司  9,永嘉县巨霸鞋业有限公司  10,芜湖市永嘉制衣有限公司  11,陕西天禄堂制药有限公司  */

        JavaRDD<String> file = ctx.textFile("data-sets/repeat/repeat-500");
        JavaRDD<ComInfo> companyList = file.map(line -> {
            String[] split = line.split(",");
            return new ComInfo(split[0], split[1]);
        });

        // 笛卡尔乘积,建立任意两个公司关联的数据         companyList.cartesian(companyList)
                // 过滤掉 同一个公司的数据                 .filter(tuple -> !tuple._1.sn.equals(tuple._2.sn))
                .map((tuple) -> {
                    LevenshteinDistance levenshteinDistance = new LevenshteinDistance();
                    // 使用 commons-text 包进行字符串 Edit Distance 计算                     Integer distance = levenshteinDistance.apply(tuple._1.title, tuple._2.title);

                    //由于是笛卡尔乘积,所以需要 使用两个公司数据的sn排序后作为 group 字段最终进行分组,不然就会出现重复数据,两公司一前一后出现两次                     String sn;
                    if (tuple._1.sn.compareTo(tuple._2.sn) > 1) {
                        sn = tuple._1.sn + tuple._2.sn;
                    } else {
                        sn = tuple._2.sn + tuple._1.sn;
                    }
                    return new ComDistance(tuple._1.title, tuple._2.title, sn, distance);
                })
                // 选出 Edit Distance 为 (0,5] 之间的数据, 0 的话为相同,这样的数据不需要                 .filter(companyDistance -> companyDistance.distance <= 5 && companyDistance.distance > 0)
                .groupBy(companyDistance -> companyDistance.sn)
                .map(groupTuple -> groupTuple._2.iterator().next())
                // 使用计算好的 Edit Distance 排序                 .sortBy(companyDistance -> companyDistance.distance, true, 0)
                .saveAsTextFile("data-sets/repeat/result.txt");
                /*.foreach(companyDistance -> {  log.info("Edit Distance:{}", companyDistance.distance);  log.info("{}", companyDistance.tital_1);  log.info("{}", companyDistance.tital_2);  });*/




    }

    public static class ComInfo implements Serializable {
        String sn;
        String title;

        ComInfo(String sn, String title) {
            this.sn = sn;
            this.title = title;
        }

        @Override
        public String toString() {
            return "ComInfo{" +
                    "sn='" + sn + '\'' +
                    ", title='" + title + '\'' +
                    '}';
        }
    }

    public static class ComDistance implements Serializable {
        String tital_1;
        String tital_2;
        String sn;
        Integer distance;

        ComDistance(String tital_1, String tital_2, String sn, Integer distance) {
            this.tital_1 = tital_1;
            this.tital_2 = tital_2;
            this.sn = sn;
            this.distance = distance;
        }

        @Override
        public String toString() {
            return "Edit Distance " + distance + "\n" +
                    tital_1 + "\n" +
                    tital_2  + "\n";
        }
    }
}

计算结果:

Edit Distance 1
上海白玉兰计算机有限公司
上海市白玉兰计算机有限公司

Edit Distance 1
中国科学院广州地化学研究所
中国科学院广州地球化学研究所

Edit Distance 1
中国科学院广州地球化学研究所
中国科学院广州地化学研究所

Edit Distance 1
吉林省福春木业有限公司
吉林省富春木业有限公司

Edit Distance 1
南通市九色鹿业有限公司
南通九色鹿业有限公司

Edit Distance 1
淮安中洪建设有限公司
淮安市中洪建设有限公司

Edit Distance 1
深圳太立德仁文化传播有限公司
深圳市太立德仁文化传播有限公司

Edit Distance 1
青岛欲太工贸发展有限公司汽车修理厂
青岛裕太工贸发展有限公司汽车修理厂

Edit Distance 1
东台市中微特电机厂
东台中微特电机厂

Edit Distance 1
汕头市金砂中医医院
汕头市金砂中医院

Edit Distance 1
杭州祐康电子商务网络有限公司
杭州佑康电子商务网络有限公司

Edit Distance 1
浙江九康电器有限公司
浙江九康电气有限公司

Edit Distance 1
东台中微特电机厂
东台市中微特电机厂

Edit Distance 1
杭州佑康电子商务网络有限公司
杭州祐康电子商务网络有限公司

Edit Distance 1
莱芜市泰东汽车销售服务有限公司
莱芜泰东汽车销售服务有限公司

Edit Distance 1
青岛裕太工贸发展有限公司汽车修理厂
青岛欲太工贸发展有限公司汽车修理厂

Edit Distance 1
无锡莹佳科技有限公司
无锡市莹佳科技有限公司

Edit Distance 1
湘潭市红楼实业有限公司锦绣红楼酒店
湘谭市红楼实业有限公司锦绣红楼酒店

Edit Distance 1
深圳市太立德仁文化传播有限公司
深圳太立德仁文化传播有限公司

Edit Distance 2
宁波甬达电梯有限公司
宁波博达电气有限公司

Edit Distance 2
交通银行抚顺分行河北支行抚东分理处
交通银行抚顺分行河北支行新城分理处

Edit Distance 2
丹阳市埤城镇胡桥卫生院
丹阳市埤城镇胡桥卫生院本部

Edit Distance 2
芜湖市永嘉制衣有限责任公司
芜湖市永嘉制衣有限公司

Edit Distance 2
交通银行抚顺分行河北支行新城分理处
交通银行抚顺分行河北支行抚东分理处

Edit Distance 2
重庆金凤丝绸集团有限公司
重庆金凤丝绸(集团)有限公司

Edit Distance 2
中国科学院广州地球化学研究所
中国科学院地球化学研究所

Edit Distance 2
费县探沂镇中心卫生院
费县探沂镇中心卫生院本部

Edit Distance 2
中国电信股份有限公司广东东莞高埗分公司
中国电信股份有限公司东莞高埗分公司

Edit Distance 2
潞城市翟店镇卫生院
潞城市翟店镇卫生院本部

Edit Distance 2
承德钢铁集团有限公司
承德钢铁股份有限公司

Edit Distance 2
包家乡卫生院本部
包家乡卫生院

Edit Distance 2
河北富华康土特环保有限公司
富华康土特环保有限公司

Edit Distance 2
中国科学院地球化学研究所
中国科学院广州地球化学研究所

Edit Distance 2
深圳艾捷科技有限责任公司
深圳艾捷科技有限公司

Edit Distance 2
大连工美企业有限责任公司
大连工美企业有限公司

Edit Distance 2
芜湖市永嘉制衣有限公司
芜湖市永嘉制衣有限责任公司

Edit Distance 2
中国科学院广州地球化学研究所
中国科学院地球化学研究所

Edit Distance 2
慈溪市坎墩街道社区卫生服务中心直塘村服务站
慈溪市坎墩街道社区卫生服务中心直塘村服务站本部

Edit Distance 2
慈溪市坎墩街道社区卫生服务中心直塘村服务站本部
慈溪市坎墩街道社区卫生服务中心直塘村服务站

Edit Distance 2
山东阳光体育设施有限公司
阳光体育设施有限公司

Edit Distance 2
中国银行青海省分行西宁市五四支行
中国银行青海省分行西宁市五四大街支行

Edit Distance 2
北京美大星巴克咖啡有限公司方庄贵友店
北京美大星巴克咖啡有限公司贵友店

Edit Distance 2
承德钢铁股份有限公司
承德钢铁集团有限公司

Edit Distance 2
大足县宝兴卫生院
大足县宝兴卫生院本部

Edit Distance 2
重庆金凤丝绸(集团)有限公司
重庆金凤丝绸集团有限公司

Edit Distance 2
平顺县龙溪镇卫生院本部
平顺县龙溪镇卫生院

Edit Distance 2
庆元县百山祖乡中心小学本部
庆元县百山祖乡中心小学

Edit Distance 2
竞业律师事务所
辽宁竞业律师事务所

Edit Distance 3
中国工商银行怀化市怀兴支行学院分理处
中国工商银行怀兴支行学院分理处

Edit Distance 3
宝山区邮政局
广水市邮政局

Edit Distance 3
广东省增城市华阳汽车换热器有限公司
增城市华阳汽车换热器有限公司

Edit Distance 3
北京市北华顺加油站有限责任公司
北京北华顺加油站有限公司

Edit Distance 3
中国农业银行甘肃省分行兰州市西固区支行福利路储蓄所
中国农业银行甘肃省分行兰州市西固区支行福利路分理处

Edit Distance 3
中国工商银行吉林省四平市分行铁东区平东支行
中国工商银行吉林省四平市分行平东支行

Edit Distance 3
中国科学院广州地化学研究所
中国科学院地球化学研究所

Edit Distance 3
包家乡卫生院
泉源卫生院

Edit Distance 3
郓城县仙纹染织有限公司
仙纹染织有限公司

Edit Distance 3
中国科学院广州地化学研究所
中国科学院地球化学研究所

Edit Distance 3
肇庆甘洒镇卫生院
怀集县甘洒镇卫生院

Edit Distance 3
淮安淮阴区新华书店
淮阴县新华书店

Edit Distance 3
中国工商银行吉林省四平市分行平东支行
中国工商银行吉林省四平市分行铁东区平东支行

Edit Distance 3
泉源卫生院
包家乡卫生院

Edit Distance 3
宁波市发展和改革委员会
浙江省宁波市发展和改革委员会

Edit Distance 3
中国农业银行湖南省株洲市分行炎陵县支行鹿原营业所
中国农业银行湖南省株洲市炎陵支行鹿原营业所

Edit Distance 3
和县历阳镇卫生院
歙县街口镇卫生院

Edit Distance 4
和县历阳镇卫生院
肇庆甘洒镇卫生院

Edit Distance 4
步阳集团
南京日报

Edit Distance 4
安溪县第三医院本部
如东县丁店医院本部

...
...

Edit Distance 4
丹阳市埤城镇胡桥卫生院本部
丹阳市蒋墅镇卫生院本部

Edit Distance 4
沈丘县邮电局
宝山区邮政局

Edit Distance 4
肇庆甘洒镇卫生院
歙县街口镇卫生院

Edit Distance 4
中国工商银行包头分行
宁德中国工商银行霞浦分行

Edit Distance 4
沈丘县邮电局
沾益县公安局

Edit Distance 4
费县探沂镇中心卫生院
博罗县石湾镇中心卫生院

Edit Distance 4
上海华联电器集团有限公司
浙江卓力电器集团有限公司

Edit Distance 4
三光科技有限公司
深圳艾捷科技有限公司

Edit Distance 4
费县探沂镇中心卫生院本部
燕矶镇中心卫生院本部

Edit Distance 4
程四酒家
步阳集团

Edit Distance 4
金坛市金城镇卫生院本部
德兴市银城卫生院本部

Edit Distance 4
仙纹染织有限公司
三光科技有限公司

Edit Distance 4
垣曲县蒲掌中心卫生院
昭觉县四开中心卫生院

Edit Distance 4
东莞德利信电子有限公司
东莞吉凯电器有限公司

Edit Distance 4
德兴市银城卫生院本部
金坛市金城镇卫生院本部

Edit Distance 4
金坛市金城镇卫生院本部
费县费城镇卫生院本部

Edit Distance 4
和县历阳镇卫生院
平顺县龙溪镇卫生院

Edit Distance 4
潞城市翟店镇卫生院本部
丰城市尚庄卫生院本部

Edit Distance 4
宁波博达电气有限公司
浙江九康电气有限公司

Edit Distance 4
广东省邮政公司揭阳市揭西县龙潭邮政支局
广东省邮政公司揭阳市惠来县葵潭邮政局

Edit Distance 4
汕头经济特区国际货运代理公司
汕头市国际货运代理公司

Edit Distance 4
东莞吉凯电器有限公司
东莞德利信电子有限公司

Edit Distance 4
青岛钢铁有限公司
承德钢铁股份有限公司

Edit Distance 4
衢州诚信汽车有限公司
苏州金信制衣有限公司

Edit Distance 4
程四酒家
南京日报

Edit Distance 4
昭觉县四开中心卫生院
垣曲县蒲掌中心卫生院

Edit Distance 4
无锡莹佳科技有限公司
三光科技有限公司

Edit Distance 4
青岛武晓集团有限公司
承德钢铁集团有限公司

Edit Distance 4
青岛钢铁有限公司
三光科技有限公司

Edit Distance 4
鹤壁供电公司
江西印刷公司

Edit Distance 4
城南拼线厂
南京日报

Edit Distance 4
南京日报
城南拼线厂

Edit Distance 4
三光科技有限公司
无锡莹佳科技有限公司

Edit Distance 4
广东省邮政公司揭阳市惠来县葵潭邮政局
广东省邮政公司揭阳市揭西县龙潭邮政支局

Edit Distance 4
和县历阳镇卫生院
怀集县甘洒镇卫生院

Edit Distance 4
苏州金信制衣有限公司
衢州诚信汽车有限公司

Edit Distance 4
浙江省烟草公司丽水市公司
河南省烟草公司新郑市公司

Edit Distance 4
江苏省范群干燥设备有限公司
江苏省范群干燥设备厂

Edit Distance 4
连州中医院
泉源卫生院

Edit Distance 4
九江酒厂有限公司
三光科技有限公司

Edit Distance 4
丰城市尚庄卫生院本部
德兴市银城卫生院本部

Edit Distance 4
青冈县第三医院
会宁县中医医院

Edit Distance 4
无锡莹佳科技有限公司
深圳艾捷科技有限公司

Edit Distance 4
博罗县石湾镇中心卫生院
费县探沂镇中心卫生院

Edit Distance 4
怀集县甘洒镇卫生院
歙县街口镇卫生院

Edit Distance 4
金鹰超市
程四酒家

Edit Distance 4
青岛钢铁有限公司
承德钢铁集团有限公司

Edit Distance 4
宝山区邮政局
沈丘县邮电局

Edit Distance 4
仙纹染织有限公司
九江酒厂有限公司

Edit Distance 4
浙江恒林椅业股份有限公司
浙江中达特钢股份有限公司

Edit Distance 4
平顺县龙溪镇卫生院
歙县街口镇卫生院

Edit Distance 4
乐山金口河区和平分社
金口河区和平小学

Edit Distance 4
广水市邮政局
沈丘县邮电局

Edit Distance 4
沾益县公安局
虹口公安分局

Edit Distance 4
沾益县公安局
沈丘县邮电局

Edit Distance 4
中国建设银行河北省唐山市分行缸窑路分理处
中国建设银行河北省唐山市分行缸窑支行

Edit Distance 4
苏州金信制衣有限公司
辽宁永兴制衣有限公司

Edit Distance 4
丹阳市蒋墅镇卫生院本部
丹阳市埤城镇胡桥卫生院本部

Edit Distance 4
安溪县第三医院本部
青冈县第三医院

Edit Distance 4
启东市海东中心卫生院(本部)
启东市海东中心卫生院

Edit Distance 4
南京金鹰国际集团
南京金鹰国际集团有限公司

Edit Distance 5
程四酒家
泉源卫生院

Edit Distance 5
教育部高教司
江西印刷公司

Edit Distance 5
九江酒厂有限公司
浙江九康电器有限公司

Edit Distance 5
程四酒家
北京四环宾馆

Edit Distance 5
肇庆甘洒镇卫生院
包家乡卫生院

Edit Distance 5
达州市精神病医院
宁波市康宁医院

Edit Distance 5
浙江九康电器有限公司
宁波博达电气有限公司

Edit Distance 5
交通银行温州分行车站大道支行
交通银行苏州分行张家港支行

Edit Distance 5
丰城市尚庄卫生院本部
大足县宝兴卫生院本部

Edit Distance 5
如东玉晟布业有限公司
龙南礼顿袜业有限公司

Edit Distance 5
安徽省古井集团有限责任公司
安徽古井酒店(集团)有限责任公司

Edit Distance 5
六五二职工医院
宁波市康宁医院

Edit Distance 5
歙县街口镇卫生院
大足县宝兴卫生院

Edit Distance 5
佛山市松川企业有限公司
河间市金桥铜业有限公司

Edit Distance 5
苏州金信制衣有限公司
明亮玻璃制品有限公司

Edit Distance 5
连州中医院
汕头市金砂中医院

Edit Distance 5
城南拼线厂
泉源卫生院

Edit Distance 5
古田县凤埔乡卫生院
大足县宝兴卫生院

Edit Distance 5
仙纹染织有限公司
威海艾迪姆有限公司

Edit Distance 5
河北省景县邮政局
宝山区邮政局

Edit Distance 5
德兴市银城卫生院本部
包家乡卫生院本部

Edit Distance 5
城南拼线厂
宏开木制品厂

Edit Distance 5
大足县智凤镇弥陀卫生院本部
大足县宝兴卫生院本部

Edit Distance 5
程四酒家
黑土地家常菜

Edit Distance 5
上海华联电器集团有限公司
上海马克电机阀门有限公司

Edit Distance 5
衢州诚信汽车有限公司
广州彩兴印刷有限公司

Edit Distance 5
无锡市莹佳科技有限公司
深圳艾捷科技有限公司

Edit Distance 5
宁波甬达电梯有限公司
东莞吉凯电器有限公司

Edit Distance 5
九江酒厂有限公司
内江隆昌农药有限公司

Edit Distance 5
南通市九色鹿业有限公司
辛集市鑫熙皮业有限公司

Edit Distance 5
金鹰超市
世纪杂志社

Edit Distance 5
城南拼线厂
程四酒家

Edit Distance 5
浙江九康电器有限公司
九江酒厂有限公司

Edit Distance 5
包家乡卫生院本部
费县费城镇卫生院本部

Edit Distance 5
北京美大星巴克咖啡有限公司天津开发区名都咖啡店
北京星巴克咖啡有限公司天津名都咖啡店

...

结果集下载:http://orfuc602j.bkt.clouddn.com/data-sets/repeat/part-00000

可以看到当 edit distance 比较 ( >4 )的时候数据处理的质量已经不能保证,因此需要从其他方面解决。

未解决的问题和新的挑战:

1. 默认的 Edit Distance 算法没法解决中文分词问题

2. 同义词/近义词/中英文 相关的问题未考虑

3. 目前只进行了 1 :1 的比较,应该实现 1 对多的比较

除了去重,该方法也适用于数据关联,不同表之间进行数据关联,同理也是用 Edit Distance ,改进方法也如上,同时可以加入更多字段进行处理。

提供两个测试数据集合:

http://orfuc602j.bkt.clouddn.com/data-sets/match/master

http://orfuc602j.bkt.clouddn.com/data-sets/match/input

    原文作者:吴亮弟
    原文地址: https://zhuanlan.zhihu.com/p/27365621
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞