idmp用户唯一标识
需求出现原因:
现在一般网站所有账号登陆,账号就是用户的唯一标识
但是部分网站也存在一些以游客模式进行浏览消费的事件,
这个时候就需要利用**图计算(graphx)**的方法计算出用户的唯一标识.
图计算逻辑:
将所有数据中产生的的 id码,imsi码,mac码…所有编码汇总起来形成点集合,
将行数不同但是点集合中元素相同的数据 相同编码程度值>阈值的不同行的数据被计算为同一个用户,
并且打上用户的唯一标识 guid
举例论证:
数据(idmapping小型测试数据.txt):
13866778899,刘德华,wx_hz,2000
13866778899,华仔,wx_hz,3000
,刘德华,wx_hz,5000
13812344321,马德华,wx_mdh,12000
13812344321,二师兄,wx_mdh,3500
13812344321,猪八戒,wx_mdh,5600
这是6条数据但是只有两个用户!
1.创建spark环境导入数据
//创建spark环境
val spark: SparkSession = SparkSession.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
.getOrCreate()
spark
//隐式转换
import spark.implicits._
//导入数据
val dt: Dataset[String] = spark.read.textFile("data/graphx/idmapping小型测试数据.txt")
2.创建点集合scala写法
//取出点,每个点我们要放在一个rdd里
val ver: RDD[(Long, String)] = dt.rdd.flatMap(row => {
val fields: Array[String] = row.split(",")
//如果数据如果不为空则参运算
for(ele <-fields if StringUtils.isNotBlank(ele)) yield (ele.hashCode.toLong,ele)
(第二种)创建点集合java写法
//在spark中 点 需要表示成一个tuble(k,v)==> (k:点的唯一标识我们用fields(0).hashcode来表示,v:就是第一个数据fields(0))用数组接受
val ver: RDD[(Long, String)] = dt.rdd.flatMap(row => {
val fields: Array[String] = row.split(",")
Array((fields(0).hashCode.toLong, fields(0)),
(fields(1).hashCode.toLong, fields(1)),
(fields(2).hashCode.toLong, fields(2))
)
3.创建边集合scala写法
//在构造一个边的rdd
//spark中的对边的描述 edge(起始id,目标id,边数据)
val edges: RDD[Edge[String]] = dt.rdd.flatMap(row => {
val fields = row.split(",")
//scala风格 简单 yield本来是个数组返回的还是个数组就不用创建可变的集合来收集数据了
// Edge 的参数一:第一个点. 参数二:下一个点. 参数三:边的数据或者边的属性,这里我们用空串表示
for(i<-0 to fields.length -2 if StringUtils.isNotBlank(fields(i)))yield Edge(fields(i).hashCode.toLong, fields(i + 1).hashCode.toLong, "")
})
(第二种)创建边集合java写法
//在构造一个边的rdd
//spark中的对边的描述 edge(起始id,目标id,边数据)
val edges: RDD[Edge[String]] = dt.rdd.flatMap(row => {
val fields = row.split(",")
//java风格写法先创建一个可变的集合来接手数据
val lst = new ListBuffer[Edge[String]]()
for (i <- 0 to fields.length - 2) {
val edge1 = Edge(fields(i).hashCode.toLong, fields(i + 1).hashCode.toLong, "")
//一条一条的进入到可变的集合中
lst += edge1
}
4.将点集合 和 边集合 结合起来
//用 点集合 和 边集合 构造一张图 (最大连同子图) 使用Graph算法
val graph = Graph(ver,edges)
//用graph.connectedComponents()算法 不传参数就是彻底迭代的 传参数就是限量跌代
val graph2: Graph[VertexId, String] = graph.connectedComponents()
//将组中的每一个元和这一组中的最小的元素结合成一个元组可以将每个元素中最小的元素当成这一组的唯一标识
val vertices2: VertexRDD[VertexId] = graph2.vertices
//打印出来看
vertices2.take(30).foreach(println)
打印结果(hashCode 值,右边为每个组中最小的元素):
(29003441,-774337709)
(-774337709,-774337709)
(20090824,-774337709)
(38771171,-774337709)
(208397334,548618674)
(1537214,548618674)
(8958655,548618674)
5.用我们的计算结果来加工我们的原始数据
//将上面得到点得映射关系rdd,收集到Driver端
val idmpMap = vertices2.collectAsMap()
//广播出去
val bc = spark.sparkContext.broadcast(idmpMap)
//利用映射关系结果来加工我们的额原始数据
val res: Dataset[String] = dt.map(row => {
val bc_map = bc.value
//StringUtils.isNotBlank(_)不能为空
val name = row.split(",").filter(StringUtils.isNotBlank(_))(0)
val gid: VertexId = bc_map.get(name.hashCode.toLong).get
//返回
gid + "," + row
})
res.show(10,false)
代码实现:
+---------------------------------------+
|value |
+---------------------------------------+
|681286,13866778899,刘德华,wx_hz,2000 |
|681286,13866778899,华仔,wx_hz,3000 |
|681286,,刘德华,wx_hz,5000 |
|-774337709,13812344321,马德华,wx_mdh,12000|
|-774337709,13812344321,二师兄,wx_mdh,3500 |
|-774337709,13812344321,猪八戒,wx_mdh,5600 |
+---------------------------------------+
最终我们的条数据成功点被我们计算成立两条数据