在网络分析中使用Neo4j用户自定义函数与过程

Jean

有经验的人们说,埋首赶路前,先要抬头看看天,脚踏实地的时候也不要忘了仰望星空。打开门窗看世界,先把世界看清楚,后面的路不管怎样走,就踏实了。<div>上一篇文章<a href="https://www.meipian.cn/451a6tnz?share_depth=1" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>《机场航线环路分析》</a>用比较先进的开源软件组合搭建了有向图(网络)可视化分析的APP平台,然后用Cypher查询定制了稳定强环路这样一个要进一步考察分析的目标载荷,简单有效,作为个人的探讨尝试,属于抛砖引玉,向读者诸君说明一下。</div><div>那么在各行各业实际落地应用的网络分析中,作为载荷的目标子网是千变万化的,从图数据库中选择目标子网就要使用一些过滤结点或边或路径的方法或算法,Neo4j中有很多这样的机制,不过不一定能满足各种应用场景的需求,所以它提供了用户<a href="https://neo4j.com/docs/java-reference/current/extending-neo4j/customized-code/" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>自定义函数与过程</a>的机制。比如在机场航线稳定强环路查找的例子中,对于查询经过源机场的环路,用了<a href="https://neo4j.com/labs/apoc/4.1/overview/" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>APOC插件</a>的三个函数apoc.coll.avg()、apoc.coll.min()、apoc.coll.max()来过滤出稳定强环路。假如要用中位数而不是平均值(更符合实际),就没有现成的函数可用,需要自己写了。本篇介绍一下Neo4j用户自定义函数,作为网络分析APP的结篇。用户自定义过程在前面开发<a href="https://www.meipian.cn/3gj6iqhz?share_depth=1" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>K最小生成树</a>及<a href="https://www.meipian.cn/3h8zhgm6?share_depth=1" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>最小树形图用户自定义过程</a>时已经介绍过了,不再赘述。</div><div>一、<a href="https://neo4j.com/docs/java-reference/current/extending-neo4j/customized-code/" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>Neo4j的用户自定义函数与过程</a></div><div>用户自定义过程与函数的区别是,自定义过程返回一个Stream流序列,在Cypher中引用时要用YIELD逐组提取。比如<a href="https://github.com/neo4j-examples/neo4j-procedure-template" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>Neo4j自定义过程样板项目</a>中的用户自定义过程<a href="https://github.com/neo4j-examples/neo4j-procedure-template/blob/4.4/src/main/java/example/GetRelationshipTypes.java" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>GetRelationshipTypes.java</a>,<a href="https://github.com/neo4j-examples/neo4j-procedure-template/blob/4.4/src/test/java/example/GetRelationshipTypesTests.java" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>它的Junit测试</a>中是这样引用的:</div> 看看<a href="https://github.com/neo4j-examples/neo4j-procedure-template/blob/4.4/src/main/java/example/GetRelationshipTypes.java" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>它的源码</a>,通过Java Annotation @Procedure定义为用户自定义过程及规定它的调用名字example.getRelationshipTypes,然后返回Stream类型。 用户自定义函数则返回一个单一的值,又分为标量函数与聚合函数两种,它们的Java Annotation与API都不同。<div>这个是APOC中<a href="https://github.com/neo4j-contrib/neo4j-apoc-procedures/blob/4.4/core/src/main/java/apoc/agg/Median.java" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>apoc.agg.median()函数的源码</a>,它是一个聚合函数,通过@UserAggregationFunction定义,通过@Description定义函数调用的方式,要实现由Java Annotation指定的aggregate()与result()接口:</div> 这个函数为什么在稳定强环路查询中不能使用呢?因为它是对查询中的所有结点或边求中位数,而上面的查询需要对特定路径中边的权重(集合)求中位数,即按path分组,所以要自己写一个。<div>这个是APOC中<a href="https://github.com/neo4j-contrib/neo4j-apoc-procedures/blob/4.4/core/src/main/java/apoc/coll/Coll.java" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>apoc.coll.avg()函数的源码</a>,通过@UserFunction定义,也通过@Description定义函数调用的方式,是一个标量函数,它不需要实现特定的接口。</div> <a href="https://neo4j.com/docs/java-reference/current/extending-neo4j/customized-code/" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>用户自定义函数与过程的主要区别</a>总结如下: 二、建立用户自定义函数Maven项目<div>可以参考<a href="https://neo4j.com/docs/java-reference/current/extending-neo4j/project-setup/" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>Neo4j的文档来自行建立Maven项目</a>的pom.xml项目描述文件,我直接拷贝<a href="https://github.com/neo4j-examples/neo4j-procedure-template" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>Neo4j的样板项目</a>稍作修改,因为它已经配好了编译与Junit测试的依赖,修改依赖的Neo4j服务器版本号等即可。</div> 三、开发apoc.coll.median()函数<div>参考上面apoc.agg.median()的源码,实现很简单。</div> 四、Junit单元测试<div>需要编写一个单元测试程序,测试时需要加载一个嵌入式的Neo4j Server并连接到它执行Cypher语句,Neo4j样板项目中的<a href="https://github.com/neo4j-examples/neo4j-procedure-template/blob/4.4/src/test/java/example/JoinTest.java" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>JoinTest.java</a>稍为修改一下即可,上图可见单元测试的结果。</div> 五、打包发布<div>在项目根目录上右键->Run As->Maven Install,会在项目的target目录下生成打包好的jar文件,见上两图。拷贝到服务器的plugins目录下,重启服务器加载,然后在Neo4j Browser中访问测试。</div> 六、在Python函数中引用<div>替代原来引用的apoc.coll.avg()函数即可。</div> <div>七、在 Shiny APP中调用</div><div>具体见上篇文章<a href="https://www.meipian.cn/451a6tnz?share_depth=1" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>《机场航线环路分析》</a>,可以访问<a href="https://124.223.110.20:8443/testNeo4j/indexRings.jsp" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>我的演示网页</a>了解一下,这个APP经过性能优化后已经达到了实际使用的标准,本例机场航线网络查找给定国内机场5跳以内的稳定强环路,3分钟以内就可以完成。</div><div>八、小结</div><div>通过这个小例子可以看到,开发测试Neo4j用户自定义函数是比较简单方便的,这个机制可以解决很多应用场景中过滤结点、边和路径的特殊需要,有效的选出目标子网进一步分析。</div><div><a href="https://neo4j.com/product/neo4j-graph-database/" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>Neo4j</a>(<a href="https://we-yun.com/blog/prod-56.html" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>中文社区版</a>)目前是世界上最先进的开源图数据库平台,<a href="https://neo4j.com/developer/cypher/" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>Cypher</a>是图数据库查询语言<a href="https://www.gqlstandards.org/" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>国际标准GQL</a>(<a href="https://en.wikipedia.org/wiki/Graph_Query_Language" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>参阅WIKI</a>)的主要贡献方(图查询语言的历史可以参阅<a href="https://segmentfault.com/a/1190000039829662" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>这篇文章</a>),<a href="https://neo4j.com/labs/apoc/4.1/" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>APOC</a>(<a href="https://github.com/neo4j-contrib/neo4j-apoc-procedures" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>GitHub项目</a>)与<a href="https://neo4j.com/developer/graph-data-science/graph-algorithms/" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>GDSL</a>(<a href="https://github.com/neo4j/graph-data-science" target="_blank" class="link"><i class="iconfont icon-iconfontlink"> </i>GitHub项目</a>)都是比较强大和有参考价值的开源图算法库资源。源码都可以随便下载随便分析随便改随便用,人们至少应该了解一下这些领先和有价值的开源资源,好好学习参考一下,可以少走很多弯路。从机场航线稳定强环路查找的小例子就可以看到它的强大和方便,一个十几行的Cypher查询语句就搞定了其它方案很难搞定的问题了。</div>