maven依赖
<!--这个比较全-->
<dependency>
<groupId>org.janusgraph</groupId>
<artifactId>janusgraph-all</artifactId>
<version>0.3.3</version>
</dependency>
或者
<!-- janusgraph 可能还会缺少其他的,只能自己找了-->
<dependency>
<groupId>org.janusgraph</groupId>
<artifactId>janusgraph-core</artifactId>
<version>0.3.3</version>
</dependency>
<dependency>
<groupId>org.apache.tinkerpop</groupId>
<artifactId>gremlin-driver</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>org.janusgraph</groupId>
<artifactId>janusgraph-hbase</artifactId>
<version>0.3.3</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-shaded-client</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-shaded-server</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>org.janusgraph</groupId>
<artifactId>janusgraph-es</artifactId>
<version>0.3.3</version>
</dependency>
gremlin语法
参考: http://tinkerpop-gremlin.cn/
一、创建schema和Index
package com.bj58.javautils;
import org.apache.tinkerpop.gremlin.driver.Cluster;
import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0;
import org.apache.tinkerpop.gremlin.driver.ser.Serializers;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoMapper;
import org.janusgraph.core.*;
import org.janusgraph.core.schema.JanusGraphManagement;
import org.janusgraph.core.schema.Mapping;
import org.janusgraph.core.schema.SchemaAction;
import org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry;
import java.util.ArrayList;
import java.util.List;
public class JanusGraphUtil {
//属性列表
private final static String[] PROPERTYKEYLIST = {"event_cname","event_id","event_id_index","page_type","template_id","path_id","client","nodetype","date","name","count","path_type","tid","uv"};
//事件顶点属性列表
private final static List<String> EVENTPROPERTYKEYLIST = new ArrayList<String>();
//结束顶点属性列表
private final static List<String> ENDPROPERTYKEYLIST = new ArrayList<String>();
//关系属性列表
private final static List<String> EPROPERTYKEYLIST = new ArrayList<String>();
static {
EVENTPROPERTYKEYLIST.add("tid");
EVENTPROPERTYKEYLIST.add("event_cname");
EVENTPROPERTYKEYLIST.add("event_id");
EVENTPROPERTYKEYLIST.add("event_id_index");
EVENTPROPERTYKEYLIST.add("page_type");
EVENTPROPERTYKEYLIST.add("template_id");
EVENTPROPERTYKEYLIST.add("path_id");
EVENTPROPERTYKEYLIST.add("client");
EVENTPROPERTYKEYLIST.add("nodetype");
EVENTPROPERTYKEYLIST.add("date");
EVENTPROPERTYKEYLIST.add("count");
EVENTPROPERTYKEYLIST.add("uv");
ENDPROPERTYKEYLIST.add("tid");
ENDPROPERTYKEYLIST.add("event_cname");
ENDPROPERTYKEYLIST.add("nodetype");
ENDPROPERTYKEYLIST.add("date");
ENDPROPERTYKEYLIST.add("count");
ENDPROPERTYKEYLIST.add("uv");
EPROPERTYKEYLIST.add("tid");
EPROPERTYKEYLIST.add("name");
EPROPERTYKEYLIST.add("count");
EPROPERTYKEYLIST.add("path_id");
EPROPERTYKEYLIST.add("path_type");
EPROPERTYKEYLIST.add("date");
}
public static JanusGraph getJanusGraph(){
JanusGraphFactory.Builder builder = JanusGraphFactory.build()
.set("storage.hostname", "test1.host,test2.host,test3.host") //zk节点host
.set("storage.hbase.ext.zookeeper.znode.parent","/hbase") //zk管理文件夹路径
.set("storage.backend", "hbase") //后端数据存储类型
.set("storage.hbase.ext.hbase.zookeeper.property.clientPort",2181)
.set("storage.hbase.table", "hdp_lbg_ectech:lm_app_luna_intelligentpath") //hbase tablename
.set("gremlin.graph","org.janusgraph.core.JanusGraphFactory")
.set("storage.batch-loading",true)
.set("storage.hbase.ext.zookeeper.znode.parent","/hbase")
.set("index.search.backend", "elasticsearch")
.set("index.search.hostname", "test01.es.org,test02.es.org,test03.es.org")
.set("index.search.port",9299)
.set("index.search.elasticsearch.http.auth.basic.username","test_user")
.set("index.search.elasticsearch.http.auth.basic.password","test_user")
.set("index.search.elasticsearch.http.auth.type","basic")
;
JanusGraph graph = builder.open();
return graph;
}
/**
创建图Schema
*/
public static void buildGraphSchema() {
JanusGraph graph = JanusGraphUtil.getJanusGraph();
try{
JanusGraphManagement management = graph.openManagement();
//创建顶点标签
VertexLabel event_node = management.makeVertexLabel("event_node").make();
VertexLabel endpoint = management.makeVertexLabel("endpoint").make();
management.getVertexLabels();
//创建边标签
management.makeEdgeLabel("point").make();
management.getRelationTypes(EdgeLabel.class);
List<PropertyKey> event_pro_keys = new ArrayList<PropertyKey>();
List<PropertyKey> end_pro_keys = new ArrayList<PropertyKey>();
List<PropertyKey> e_pro_keys = new ArrayList<PropertyKey>();
PropertyKey tempropertyKey = null;
//创建属性
for(String event_propertyKey:PROPERTYKEYLIST){
tempropertyKey = management.makePropertyKey(event_propertyKey).dataType(String.class).make();
if(EVENTPROPERTYKEYLIST.contains(event_propertyKey)){
event_pro_keys.add(tempropertyKey);
}
if(ENDPROPERTYKEYLIST.contains(event_propertyKey)){
end_pro_keys.add(tempropertyKey);
}
if(EPROPERTYKEYLIST.contains(event_propertyKey)){
e_pro_keys.add(tempropertyKey);
}
}
//关联顶点标签与属性标签
for(PropertyKey propertyKey:event_pro_keys){
management.addProperties(event_node,propertyKey);
}
for(PropertyKey propertyKey:end_pro_keys){
management.addProperties(endpoint,propertyKey);
}
//关联边标签与属性标签
for(PropertyKey propertyKey:e_pro_keys){
management.addProperties(event_node,propertyKey);
}
management.commit();
System.out.println("+++++++++++success+++++++++++++");
} catch (Exception e){
System.out.println("Build Graph Schema Failed. Caused by: "+e);
} finally {
if(null != graph){
graph.close();
}
}
}
public static void bulidIndex(){
JanusGraph graph = JanusGraphUtil.getJanusGraph();
try{
JanusGraphManagement management = graph.openManagement();
VertexLabel vertexLabel = management.getVertexLabel("event_node");
PropertyKey tid = management.getPropertyKey("tid");
PropertyKey date = management.getPropertyKey("date");
PropertyKey event_id = management.getPropertyKey("event_id");
PropertyKey client = management.getPropertyKey("client");
//复合索引,不需要后端存储,精确索引
management.buildIndex("composite_index_tid",Vertex.class).addKey(tid).buildCompositeIndex();
//混合索引,需要后端存储(ES),注意"search"是一个前缀.并非随便取的字符串
management.buildIndex("mixed_index_date",Vertex.class).addKey(date,Mapping.STRING.asParameter()).buildMixedIndex("search");
management.buildIndex("mixed_index_date_event_id",Vertex.class).addKey(date,Mapping.STRING.asParameter()).addKey(event_id,Mapping.STRING.asParameter()).indexOnly(vertexLabel).buildMixedIndex("search");
management.buildIndex("mixed_index_date_event_id_client",Vertex.class).addKey(date,Mapping.STRING.asParameter()).addKey(client,Mapping.STRING.asParameter()).addKey(event_id,Mapping.STRING.asParameter()).indexOnly(vertexLabel).buildMixedIndex("search");
management.commit();
} catch (Exception e){
System.out.println("Build Index Failed. Caused by: "+e);
} finally {
if(null != graph){
graph.close();
}
}
}
public static void main(String[] args) {
if(args[0].equals("schema")){
JanusGraphUtil.buildGraphSchema();
}
if(args[0].equals("index")){
JanusGraphUtil.bulidIndex();
}
}
}
二、spark写入JanusGraph
/**
* 前面是自己处理rdd的逻辑
*/
//写入顶点到JanusGraph
resdata.repartition(100).foreachPartition(iter=>{
val janusGraph = JanusGraphUtil.getJanusGraph
val cluster = Cluster.build("10.10.10.10").port(8182).serializer(Serializers.GRYO_V3D0).create()//这里是server部署的机器和端口,根据自己的版本选择序列化的累
val g = janusGraph.traversal().withRemote(DriverRemoteConnection.using(cluster,"g"))
var counts = 0L
try{
iter.foreach(line=>{
val linejson = JSON.parseObject(line)
val projson = linejson.getJSONObject("properties")
//写入前先删除点和边
//这里的tid是我自己定义的一个唯一不重复的id通过索引快速查询和删除某个顶点和边 g.V().has("tid",linejson.getString("id")).outE().drop().iterate()
g.V().has("tid",linejson.getString("id")).drop().iterate()
//事件节点
if(linejson.getString("label").equals("event_node")){
g.addV(linejson.getString("label"))
.property("tid",linejson.getString("id"))
.property("date",projson.getString("date"))
.property("event_cname",projson.getString("event_cname"))
.property("event_id",projson.getString("event_id"))
.property("nodetype",projson.getString("nodetype"))
.property("page_type",projson.getString("page_type"))
.property("path_id",projson.getString("path_id"))
.property("client",projson.getString("client"))
.property("count",projson.getString("count"))
.property("template_id",projson.getString("template_id"))
.property("event_id_index",projson.getString("event_id_index"))
.next()
} else{
g.addV(linejson.getString("label"))
.property("tid",linejson.getString("id"))
.property("date",projson.getString("date"))
.property("count",projson.getString("count"))
.property("event_cname",projson.getString("event_cname"))
.property("nodetype",projson.getString("nodetype"))
.next()
}
counts = counts + 1
if(counts == 3000){//每三千个节点commit一次
g.tx().commit()
}
})
} catch {
case e:Exception => println("Write V Fild. Cause by:"+e)
} finally {
g.tx().commit()
g.close()
cluster.close()
janusGraph.close()
}
}
)
//写入边到JanusGraph
resdata.repartition(100).foreachPartition(iter=>{
val janusGraph = JanusGraphUtil.getJanusGraph
val builder = GryoMapper.build.addRegistry(JanusGraphIoRegistry.getInstance)
val serializer = new GryoMessageSerializerV3d0(builder)
val cluster = Cluster.build("10.132.98.109").port(8182).serializer(serializer).create()
val g = janusGraph.traversal().withRemote(DriverRemoteConnection.using(cluster,"g"))
println("+++++++++++++++++++g is open:"+g.tx().isOpen)
var counts = 0L
try{
iter.foreach(line=>{
val linejson = JSON.parseObject(line)
val outE = linejson.getJSONObject("outE")
//事件节点
if(linejson.getString("label").equals("event_node")){
val from = g.V().has("tid",linejson.getString("id"))
val to = g.V().has("tid",outE.getString("inV"))
g.addE("point")
.from(from)
.to(to)
.property("tid",Md5Util.encode(linejson.getString("id")+outE.getString("inV")))
.property("count",outE.getString("count"))
.property("date",outE.getString("date"))
.property("name",outE.getString("name"))
.property("path_id",outE.getString("path_id"))
.property("path_type",outE.getString("path_type"))
.next()
counts = counts + 1
}
if(counts == 3000){//每三千次commit一次
g.tx().commit()
}
})
} catch {
case e:Exception => println("Write Edge Fild. Cause by:"+e)
} finally {
g.tx().commit()
g.close()
cluster.close()
janusGraph.close()
}
}
)
spark.stop()
三、查询路径数据
导入import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*;可以直接使用客户端的类似sql的语言查询
public static void main(String[] args) {
JanusGraph graph = JanusGraphUtil.getJanusGraph();
GryoMapper.Builder builder = GryoMapper.build().addRegistry(JanusGraphIoRegistry.getInstance());GryoMessageSerializerV3d0 serializer = new GryoMessageSerializerV3d0(builder);
GraphTraversalSource g = graph.traversal().withRemote(DriverRemoteConnection.using(Cluster.build("10.10.10.10").port(8182).serializer(serializer).create(),"g"));
try{
List<Path> paths = g.V()
.hasLabel("event_node")
.has("date","20210810")
.has("event_id","4-0-8516-0")
//.limit(10)
.repeat(out()).until(has("event_cname", "endpoint"))
.path()
.by(
choose(
has("event_cname","endpoint")
,valueMap().select("event_cname","count","date")
,valueMap().select("event_cname","count","path_id")
)
).toList()
;
//{event_cname=[详情页-0-房屋维修/防水-页面展示], count=[43], path_id=[e897144617188c0eda700a89a7fe0efb]}
Pattern p = Pattern.compile("\\[(.*?)\\]");
JSONArray nodes = new JSONArray();
JSONArray links = new JSONArray();
Set<String> nodeSet = new HashSet<String>();
Map<String,Map<String,Long>> s_t_num = new HashMap<String,Map<String,Long>>();
Integer index = 0;
for(Path path : paths){
Matcher m2 = p.matcher(path.get(0).toString().split(",")[2]);
String path_id = m2.find()?m2.group(1):"";
Long uv = uvMap.get(path_id);
Matcher m1 = p.matcher(path.get(0).toString().split(",")[1]);
Long pv = m1.find()?Long.valueOf(m1.group(1)):0L;
int pathSize = path.size();
for(int j = 0 ; j < pathSize ;j++){
Matcher m0 = p.matcher(path.get(j).toString().split(",")[0]);
String node = m0.find()?m0.group(1)+"["+j+"]":"";
nodeSet.add(node);
if(j < pathSize - 1){
String source = node;
Matcher m = p.matcher(path.get(j+1).toString().split(",")[0]);
String target = m.find()?m.group(1)+"["+(j+1)+"]":"";
String key = source+"\001"+target;
if(s_t_num.keySet().contains(key)){
Long oldPV = s_t_num.get(key).get("pv");
Map<String,Long> value = new HashMap<String, Long>();
value.put("pv",oldPV+pv);
s_t_num.remove(key);
s_t_num.put(key,value);
} else{
Map<String,Long> value = new HashMap<String, Long>();
value.put("pv",pv);
s_t_num.put(key,value);
}
}
}
index++;
}
for(String node:nodeSet){
nodes.add(new JSONObject().fluentPut("name",node));
}
for(String key:s_t_num.keySet()){
String[] s_t = key.split("\001");
links.add(new JSONObject()
.fluentPut("pv",s_t_num.get(key).get("pv").toString())
.fluentPut("source",s_t[0])
.fluentPut("target",s_t[1])
);
}
nodes.sort(Comparator.comparing
(obj ->
Integer.valueOf(
((JSONObject)obj).getString("name").split("\\[")[1].replace("]","")
)
)
);
links.sort(Comparator.comparing
(obj ->
Integer.valueOf(
((JSONObject)obj).getString("source").split("\\[")[1].replace("]","")
)
)
);
JSONObject data = new JSONObject();
data.put("nodes",nodes);
data.put("links",links);
System.out.println(data);
} catch (Exception e){
System.out.println("+++++++++++Exception:" + e);
} finally {
graph.close();
}
}
结果:
{"nodes":[{"name":"详情页-0-房屋维修/防水-页面展示[0]"},{"name":"详情页-0-房屋维修/防水-电话[1]"},{"name":"详情页-0-保洁清洗-页面展示[1]"},{"name":"列表页-0-本地服务-页面展示[1]"},{"name":"详情页-0-房屋维修/防水-微聊[1]"},{"name":"列表页-0-房屋维修/防水-页面展示[1]"},{"name":"详情页-0-保姆/月嫂-页面展示[1]"},{"name":"详情页-0-房屋维修/防水-帖子[1]"},{"name":"详情页-0-搬家-页面展示[1]"},{"name":"endpoint[1]"},{"name":"详情页-0-管道疏通/清洗-页面展示[2]"},{"name":"详情页-0-生活配送-页面展示[2]"},{"name":"列表页-0-房屋维修/防水-帖子[2]"},{"name":"详情页-0-房屋维修/防水-页面展示[2]"},{"name":"endpoint[2]"},{"name":"列表页-0-本地服务-页面展示[2]"},{"name":"列表页-0-搬家-页面展示[2]"},{"name":"详情页-0-房屋维修/防水-微聊[2]"},{"name":"列表页-0-保姆/月嫂-页面展示[2]"},{"name":"详情页-0-电脑维修-页面展示[2]"},{"name":"详情页-0-开锁/换锁/修锁-页面展示[2]"},{"name":"详情页-0-搬家-页面展示[2]"},{"name":"列表页-0-房屋维修/防水-页面展示[2]"},{"name":"列表页-0-房屋维修/防水-页面展示[3]"},{"name":"详情页-0-开锁/换锁/修锁-帖子[3]"},{"name":"详情页-0-搬家-帖子[3]"},{"name":"详情页-0-电脑维修-帖子[3]"},{"name":"endpoint[3]"},{"name":"详情页-0-搬家-页面展示[3]"},{"name":"详情页-0-管道疏通/清洗-帖子[3]"},{"name":"详情页-0-生活配送-帖子[3]"},{"name":"详情页-0-房屋维修/防水-页面展示[3]"},{"name":"详情页-0-房屋维修/防水-电话[4]"},{"name":"endpoint[4]"},{"name":"详情页-0-房屋维修/防水-页面展示[4]"},{"name":"列表页-0-搬家-页面展示[4]"},{"name":"列表页-0-房屋维修/防水-页面展示[5]"},{"name":"endpoint[5]"},{"name":"详情页-0-房屋维修/防水-帖子[5]"},{"name":"详情页-0-搬家-页面展示[5]"},{"name":"endpoint[6]"},{"name":"详情页-0-管道疏通/清洗-页面展示[6]"},{"name":"详情页-0-生活配送-页面展示[6]"},{"name":"详情页-0-房屋维修/防水-页面展示[6]"},{"name":"列表页-0-搬家-页面展示[6]"},{"name":"详情页-0-电脑维修-页面展示[6]"},{"name":"详情页-0-开锁/换锁/修锁-页面展示[6]"},{"name":"详情页-0-搬家-页面展示[6]"},{"name":"列表页-0-房屋维修/防水-页面展示[7]"},{"name":"endpoint[7]"},{"name":"详情页-0-搬家-页面展示[7]"},{"name":"endpoint[8]"},{"name":"详情页-0-房屋维修/防水-页面展示[8]"},{"name":"列表页-0-搬家-页面展示[8]"},{"name":"详情页-0-搬家-页面展示[9]"},{"name":"列表页-0-房屋维修/防水-页面展示[9]"},{"name":"endpoint[9]"},{"name":"详情页-0-房屋维修/防水-页面展示[10]"},{"name":"endpoint[10]"},{"name":"列表页-0-搬家-页面展示[10]"},{"name":"endpoint[11]"}],"links":[{"uv":"5651","pv":"5651","source":"详情页-0-房屋维修/防水-页面展示[0]","target":"详情页-0-房屋维修/防水-帖子[1]"},{"uv":"187","pv":"187","source":"详情页-0-房屋维修/防水-页面展示[0]","target":"详情页-0-房屋维修/防水-微聊[1]"},{"uv":"636","pv":"636","source":"详情页-0-房屋维修/防水-页面展示[0]","target":"列表页-0-本地服务-页面展示[1]"},{"uv":"4482","pv":"4482","source":"详情页-0-房屋维修/防水-页面展示[0]","target":"详情页-0-搬家-页面展示[1]"},{"uv":"60","pv":"60","source":"详情页-0-房屋维修/防水-页面展示[0]","target":"详情页-0-保洁清洗-页面展示[1]"},{"uv":"13955","pv":"13961","source":"详情页-0-房屋维修/防水-页面展示[0]","target":"endpoint[1]"},{"uv":"83","pv":"83","source":"详情页-0-房屋维修/防水-页面展示[0]","target":"详情页-0-保姆/月嫂-页面展示[1]"},{"uv":"7400","pv":"7402","source":"详情页-0-房屋维修/防水-页面展示[0]","target":"列表页-0-房屋维修/防水-页面展示[1]"},{"uv":"3190","pv":"3193","source":"详情页-0-房屋维修/防水-页面展示[0]","target":"详情页-0-房屋维修/防水-电话[1]"},{"uv":"2751","pv":"2754","source":"详情页-0-房屋维修/防水-电话[1]","target":"endpoint[2]"},{"uv":"100","pv":"100","source":"详情页-0-房屋维修/防水-帖子[1]","target":"详情页-0-生活配送-页面展示[2]"},{"uv":"209","pv":"211","source":"列表页-0-房屋维修/防水-页面展示[1]","target":"列表页-0-房屋维修/防水-帖子[2]"},{"uv":"60","pv":"60","source":"详情页-0-保洁清洗-页面展示[1]","target":"endpoint[2]"},{"uv":"2559","pv":"2559","source":"列表页-0-房屋维修/防水-页面展示[1]","target":"endpoint[2]"},{"uv":"4136","pv":"4136","source":"详情页-0-搬家-页面展示[1]","target":"列表页-0-搬家-页面展示[2]"},{"uv":"452","pv":"452","source":"详情页-0-房屋维修/防水-帖子[1]","target":"详情页-0-电脑维修-页面展示[2]"},{"uv":"46","pv":"46","source":"详情页-0-房屋维修/防水-帖子[1]","target":"endpoint[2]"},{"uv":"636","pv":"636","source":"列表页-0-本地服务-页面展示[1]","target":"endpoint[2]"},{"uv":"1025","pv":"1025","source":"详情页-0-房屋维修/防水-帖子[1]","target":"详情页-0-搬家-页面展示[2]"},{"uv":"96","pv":"96","source":"详情页-0-房屋维修/防水-电话[1]","target":"列表页-0-本地服务-页面展示[2]"},{"uv":"234","pv":"234","source":"详情页-0-房屋维修/防水-电话[1]","target":"详情页-0-房屋维修/防水-微聊[2]"},{"uv":"83","pv":"83","source":"详情页-0-保姆/月嫂-页面展示[1]","target":"列表页-0-保姆/月嫂-页面展示[2]"},{"uv":"1919","pv":"1919","source":"详情页-0-房屋维修/防水-帖子[1]","target":"详情页-0-开锁/换锁/修锁-页面展示[2]"},{"uv":"4632","pv":"4632","source":"列表页-0-房屋维修/防水-页面展示[1]","target":"详情页-0-房屋维修/防水-页面展示[2]"},{"uv":"109","pv":"109","source":"详情页-0-房屋维修/防水-电话[1]","target":"列表页-0-房屋维修/防水-页面展示[2]"},{"uv":"2109","pv":"2109","source":"详情页-0-房屋维修/防水-帖子[1]","target":"详情页-0-管道疏通/清洗-页面展示[2]"},{"uv":"346","pv":"346","source":"详情页-0-搬家-页面展示[1]","target":"endpoint[2]"},{"uv":"187","pv":"187","source":"详情页-0-房屋维修/防水-微聊[1]","target":"endpoint[2]"},{"uv":"194","pv":"194","source":"详情页-0-电脑维修-页面展示[2]","target":"endpoint[3]"},{"uv":"1010","pv":"1010","source":"详情页-0-管道疏通/清洗-页面展示[2]","target":"详情页-0-管道疏通/清洗-帖子[3]"},{"uv":"652","pv":"652","source":"详情页-0-房屋维修/防水-页面展示[2]","target":"endpoint[3]"},{"uv":"83","pv":"83","source":"列表页-0-保姆/月嫂-页面展示[2]","target":"endpoint[3]"},{"uv":"109","pv":"109","source":"列表页-0-房屋维修/防水-页面展示[2]","target":"endpoint[3]"},{"uv":"878","pv":"878","source":"详情页-0-开锁/换锁/修锁-页面展示[2]","target":"详情页-0-开锁/换锁/修锁-帖子[3]"},{"uv":"258","pv":"258","source":"详情页-0-电脑维修-页面展示[2]","target":"详情页-0-电脑维修-帖子[3]"},{"uv":"96","pv":"96","source":"列表页-0-本地服务-页面展示[2]","target":"endpoint[3]"},{"uv":"234","pv":"234","source":"详情页-0-房屋维修/防水-微聊[2]","target":"endpoint[3]"},{"uv":"842","pv":"842","source":"列表页-0-搬家-页面展示[2]","target":"endpoint[3]"},{"uv":"209","pv":"211","source":"列表页-0-房屋维修/防水-帖子[2]","target":"详情页-0-房屋维修/防水-页面展示[3]"},{"uv":"1041","pv":"1041","source":"详情页-0-开锁/换锁/修锁-页面展示[2]","target":"endpoint[3]"},{"uv":"572","pv":"572","source":"详情页-0-搬家-页面展示[2]","target":"endpoint[3]"},{"uv":"1099","pv":"1099","source":"详情页-0-管道疏通/清洗-页面展示[2]","target":"endpoint[3]"},{"uv":"3294","pv":"3294","source":"列表页-0-搬家-页面展示[2]","target":"详情页-0-搬家-页面展示[3]"},{"uv":"50","pv":"50","source":"详情页-0-生活配送-页面展示[2]","target":"详情页-0-生活配送-帖子[3]"},{"uv":"3980","pv":"3980","source":"详情页-0-房屋维修/防水-页面展示[2]","target":"列表页-0-房屋维修/防水-页面展示[3]"},{"uv":"453","pv":"453","source":"详情页-0-搬家-页面展示[2]","target":"详情页-0-搬家-帖子[3]"},{"uv":"50","pv":"50","source":"详情页-0-生活配送-页面展示[2]","target":"endpoint[3]"},{"uv":"878","pv":"878","source":"详情页-0-开锁/换锁/修锁-帖子[3]","target":"详情页-0-房屋维修/防水-页面展示[4]"},{"uv":"258","pv":"258","source":"详情页-0-电脑维修-帖子[3]","target":"详情页-0-房屋维修/防水-页面展示[4]"},{"uv":"165","pv":"165","source":"详情页-0-房屋维修/防水-页面展示[3]","target":"endpoint[4]"},{"uv":"2977","pv":"2977","source":"详情页-0-搬家-页面展示[3]","target":"列表页-0-搬家-页面展示[4]"},{"uv":"50","pv":"50","source":"详情页-0-生活配送-帖子[3]","target":"详情页-0-房屋维修/防水-页面展示[4]"},{"uv":"453","pv":"453","source":"详情页-0-搬家-帖子[3]","target":"详情页-0-房屋维修/防水-页面展示[4]"},{"uv":"317","pv":"317","source":"详情页-0-搬家-页面展示[3]","target":"endpoint[4]"},{"uv":"1010","pv":"1010","source":"详情页-0-管道疏通/清洗-帖子[3]","target":"详情页-0-房屋维修/防水-页面展示[4]"},{"uv":"44","pv":"46","source":"详情页-0-房屋维修/防水-页面展示[3]","target":"详情页-0-房屋维修/防水-电话[4]"},{"uv":"3006","pv":"3006","source":"列表页-0-房屋维修/防水-页面展示[3]","target":"详情页-0-房屋维修/防水-页面展示[4]"},{"uv":"974","pv":"974","source":"列表页-0-房屋维修/防水-页面展示[3]","target":"endpoint[4]"},{"uv":"1884","pv":"1884","source":"详情页-0-房屋维修/防水-页面展示[4]","target":"详情页-0-房屋维修/防水-帖子[5]"},{"uv":"1193","pv":"1193","source":"详情页-0-房屋维修/防水-页面展示[4]","target":"endpoint[5]"},{"uv":"2160","pv":"2160","source":"列表页-0-搬家-页面展示[4]","target":"详情页-0-搬家-页面展示[5]"},{"uv":"817","pv":"817","source":"列表页-0-搬家-页面展示[4]","target":"endpoint[5]"},{"uv":"2578","pv":"2578","source":"详情页-0-房屋维修/防水-页面展示[4]","target":"列表页-0-房屋维修/防水-页面展示[5]"},{"uv":"44","pv":"46","source":"详情页-0-房屋维修/防水-电话[4]","target":"endpoint[5]"},{"uv":"1945","pv":"1945","source":"详情页-0-搬家-页面展示[5]","target":"列表页-0-搬家-页面展示[6]"},{"uv":"694","pv":"694","source":"详情页-0-房屋维修/防水-帖子[5]","target":"详情页-0-开锁/换锁/修锁-页面展示[6]"},{"uv":"215","pv":"215","source":"详情页-0-搬家-页面展示[5]","target":"endpoint[6]"},{"uv":"50","pv":"50","source":"详情页-0-房屋维修/防水-帖子[5]","target":"详情页-0-生活配送-页面展示[6]"},{"uv":"929","pv":"929","source":"列表页-0-房屋维修/防水-页面展示[5]","target":"endpoint[6]"},{"uv":"366","pv":"366","source":"详情页-0-房屋维修/防水-帖子[5]","target":"详情页-0-搬家-页面展示[6]"},{"uv":"1649","pv":"1649","source":"列表页-0-房屋维修/防水-页面展示[5]","target":"详情页-0-房屋维修/防水-页面展示[6]"},{"uv":"194","pv":"194","source":"详情页-0-房屋维修/防水-帖子[5]","target":"详情页-0-电脑维修-页面展示[6]"},{"uv":"580","pv":"580","source":"详情页-0-房屋维修/防水-帖子[5]","target":"详情页-0-管道疏通/清洗-页面展示[6]"},{"uv":"194","pv":"194","source":"详情页-0-电脑维修-页面展示[6]","target":"endpoint[7]"},{"uv":"50","pv":"50","source":"详情页-0-生活配送-页面展示[6]","target":"endpoint[7]"},{"uv":"580","pv":"580","source":"详情页-0-管道疏通/清洗-页面展示[6]","target":"endpoint[7]"},{"uv":"1221","pv":"1221","source":"详情页-0-房屋维修/防水-页面展示[6]","target":"列表页-0-房屋维修/防水-页面展示[7]"},{"uv":"1149","pv":"1149","source":"列表页-0-搬家-页面展示[6]","target":"详情页-0-搬家-页面展示[7]"},{"uv":"694","pv":"694","source":"详情页-0-开锁/换锁/修锁-页面展示[6]","target":"endpoint[7]"},{"uv":"796","pv":"796","source":"列表页-0-搬家-页面展示[6]","target":"endpoint[7]"},{"uv":"366","pv":"366","source":"详情页-0-搬家-页面展示[6]","target":"endpoint[7]"},{"uv":"428","pv":"428","source":"详情页-0-房屋维修/防水-页面展示[6]","target":"endpoint[7]"},{"uv":"337","pv":"337","source":"详情页-0-搬家-页面展示[7]","target":"endpoint[8]"},{"uv":"575","pv":"575","source":"列表页-0-房屋维修/防水-页面展示[7]","target":"详情页-0-房屋维修/防水-页面展示[8]"},{"uv":"646","pv":"646","source":"列表页-0-房屋维修/防水-页面展示[7]","target":"endpoint[8]"},{"uv":"812","pv":"812","source":"详情页-0-搬家-页面展示[7]","target":"列表页-0-搬家-页面展示[8]"},{"uv":"290","pv":"290","source":"列表页-0-搬家-页面展示[8]","target":"详情页-0-搬家-页面展示[9]"},{"uv":"522","pv":"522","source":"列表页-0-搬家-页面展示[8]","target":"endpoint[9]"},{"uv":"308","pv":"308","source":"详情页-0-房屋维修/防水-页面展示[8]","target":"endpoint[9]"},{"uv":"267","pv":"267","source":"详情页-0-房屋维修/防水-页面展示[8]","target":"列表页-0-房屋维修/防水-页面展示[9]"},{"uv":"144","pv":"144","source":"详情页-0-搬家-页面展示[9]","target":"列表页-0-搬家-页面展示[10]"},{"uv":"146","pv":"146","source":"详情页-0-搬家-页面展示[9]","target":"endpoint[10]"},{"uv":"64","pv":"64","source":"列表页-0-房屋维修/防水-页面展示[9]","target":"详情页-0-房屋维修/防水-页面展示[10]"},{"uv":"203","pv":"203","source":"列表页-0-房屋维修/防水-页面展示[9]","target":"endpoint[10]"},{"uv":"144","pv":"144","source":"列表页-0-搬家-页面展示[10]","target":"endpoint[11]"},{"uv":"64","pv":"64","source":"详情页-0-房屋维修/防水-页面展示[10]","target":"endpoint[11]"}]}
配合前端展示一个智能路径就做好了: