neo4j前端开源代码_Neo4J和开源的力量

neo4j前端开源代码

以下文章来自Neo4j系列,该系列首次出现在maxdemarzi.com (由Neo倡导者Max De Marzi 撰写的博客)上。

开源软件的好处之一是,如果您想更改某件事的完成方式,则可以

新技术 ,我们有一个小团队“现场工程师”谁不真正在产品 ,而是产品的工作。 我们帮助客户解决各种问题,回答问题,提出建议以及我们为使人们的项目成功所需要做的一切。 不久前,我有一张遍历遍历时间比他们希望的更长的支持票。

考虑一下社交网络,您可能想做的一件事就是告诉用户他们朋友网络的规模。 但是为什么要停在那里? 他们的朋友朋友甚至朋友网络的朋友怎么样? 与关系数据库相比,这是图形数据库擅长的问题类型。 让我们看看他们在做什么:

@GET
@Path("/network/{id}")
public Response getNetworkSize(@PathParam("id") Long id, @Context GraphDatabaseService db) throws IOException {
    Node user = db.getNodeById(id);
    final Evaluator depth = Evaluators.toDepth(4);
    final TraversalDescription traversalDescription = new TraversalDescriptionImpl().
             breadthFirst().evaluator(depth).relationships(FRIENDS, Direction.OUTGOING);
     
    final Integer[] sizes = new Integer[] { 0, 0, 0, 0, 0 };
 
    for (final org.neo4j.graphdb.Path path : traversalDescription.traverse(user))
         sizes[path.length()]++;
    }
 
    return Response.ok().entity(objectMapper.writeValueAsString(sizes)).build();
}

您正在查看的是一个非托管扩展 ,该扩展使用一个节点id参数并将该节点用作遍历的起点。 遍历将首先沿FRIENDS关系遍历广度,直至深度为4跳,并且在路径的每一步将递增size数组内的计数器。 这里不是很明显,但是Neo4j遍历中的默认“唯一性”是“ 全局唯一性” ,因此,如果我们已经看过节点,则不会两次访问该节点。

为了测试这一点,我创建了一个具有一百万个节点的图形,并在它们之间随机创建了1,450万个唯一关系。 我可以通过REST查询它,它看起来像这样:

http> get /example/service/network/1
==> 200 OK
==> [1,20,230,3446,48444]
那有多快? 我转向久经考验的真正的加特林工具,并为它添加20秒钟的节点ID列表,并重复测试几次:
import com.excilys.ebi.gatling.core.Predef._
import com.excilys.ebi.gatling.http.Predef._
import akka.util.duration._
import bootstrap._
 
class NetworkSize extends Simulation {
  val httpConf = httpConfig
    .baseURL("http://localhost:7474")
    .acceptHeader("application/json")
 
  val testfile = csv("test-data.txt").circular
 
  val scn = scenario("Network Size")
    .during(20) {
    feed(testfile)
    .exec(
      http("Test Network Size")
        .get("/example/service/network/${id}")
        .check(status.is(200)))
      .pause(0 milliseconds, 1 milliseconds)
  }
 
  setUp(
    scn.users(8).protocolConfig(httpConf)
  )
}

…和最好的结果:

每秒大约60个请求,平均延迟为135ms,最大延迟为640ms。 不错,但是可以更快吗? 我做了一些挖掘工作,以了解幕后情况,并发现了一些有关如何维护节点的全局唯一性的有趣信息。

class GloballyUnique extends AbstractUniquenessFilter
{
    private final Set<Long> visited = new HashSet<Long>();
     
    GloballyUnique( PrimitiveTypeFetcher type )
    {
        super( type );
    }
 
    public boolean check( TraversalBranch branch )
    {
        return visited.add( type.getId( branch ) );
    }
...

在代码中,我们有一组Longs,可以帮助我们判断是否已经看到一个节点。 这是有道理的,可以工作,但是如果我们采用不同的方式会怎样。 除了存储Longs之外,我们还可以使用BitSet来存储true或false,无论是否看到节点ID。 但是遇到一个小问题……标准的Java BitSet被限制为2,147,483,647(一个int),我们可以拥有数百亿个节点。 但是不要担心, OpenBitSet可以解救。 Lucene的这个小类最多可以处理64 * 2 ** 32-1位,我将给您一点时间做数学……这是274,877,906,943位。 完善。

所以我从github的Neo4j存储库中拉出1.9分支进行了编辑

class GloballyUnique extends AbstractUniquenessFilter
{
    private final OpenBitSet visited = new OpenBitSet();
  
    GloballyUnique( PrimitiveTypeFetcher type )
    {
        super( type );
    }
  
    public boolean check( TraversalBranch branch )
    {
        if ( visited.get( type.getId( branch ) ) ) {
            return false;
        } else {
            visited.set( type.getId( branch ) );
            return true;
        }
    }
...

我还向LICENSES.txt和NOTICES.txt文件添加了“ Lucene Core”,并修改了pom.xml文件:

<properties>
...
  <lucene.version>3.6.2</lucene.version>
</properties>
...
<dependency>
  <groupId>org.apache.lucene</groupId>
   <artifactId>lucene-core</artifactId>
   <version>${lucene.version}</version>
</dependency>

然后在/ neo4j / community / kernel目录中运行:

mvn clean install -DminimalBuild -Dlicense.skip=true

并将target / neo4j-kernel-1.9.5.jar复制到我的neo4j / lib目录中,以覆盖现有内核并重新运行测试:

现在,我们每秒可处理近100个请求,平均时间为81毫秒,最大为420毫秒,几乎是我们以前的性能数字的两倍。 几行代码还不错。 因此,请看一下Neo4j的内幕,如果发现不喜欢的东西,请对其进行更改……并向我们发送您的拉取请求!

顺便说一句……如果需要,您可以走得更快,但这并不漂亮。 我称它为OpenBitSet Dance:

@GET
@Path("/network/{id}")
public Response getNetworkSize(@PathParam("id") Long id, @Context GraphDatabaseService db) throws IOException {
    Node user = db.getNodeById(id);
 
    final Long[] sizes = new Long[] { 1L, 0L, 0L, 0L, 0L };
    OpenBitSet[] seen = new OpenBitSet[]{new OpenBitSet(),new OpenBitSet(),new OpenBitSet(),new OpenBitSet(),new OpenBitSet() };
    seen[0].set(user.getId());
 
    for(Relationship level1 : user.getRelationships(Direction.OUTGOING, FRIENDS )){
        Node friend = level1.getEndNode();
        seen[1].set(friend.getId());
    }
 
    for (int i = seen[1].nextSetBit(0); i >= 0; i = seen[1].nextSetBit(i+1)) {
        Node friend = db.getNodeById((long)i);
        for(Relationship level2 : friend.getRelationships(Direction.OUTGOING, FRIENDS )){
            Node fof = level2.getEndNode();
            seen[2].set(fof.getId());
        }
    }
 
    for (int i = seen[2].nextSetBit(0); i >= 0; i = seen[2].nextSetBit(i+1)) {
        Node friend = db.getNodeById((long)i);
        for(Relationship level2 : friend.getRelationships(Direction.OUTGOING, FRIENDS )){
            Node fof = level2.getEndNode();
            seen[3].set(fof.getId());
        }
    }
 
    for (int i = seen[3].nextSetBit(0); i >= 0; i = seen[3].nextSetBit(i+1)) {
        Node friend = db.getNodeById((long)i);
        for(Relationship level2 : friend.getRelationships(Direction.OUTGOING, FRIENDS )){
            Node fof = level2.getEndNode();
            seen[4].set(fof.getId());
        }
 
    }
    seen[1].andNot(seen[0]);
    seen[2].andNot(seen[1]);
    seen[2].andNot(seen[0]);
    seen[3].andNot(seen[2]);
    seen[3].andNot(seen[1]);
    seen[3].andNot(seen[0]);
    seen[4].andNot(seen[3]);
    seen[4].andNot(seen[2]);
    seen[4].andNot(seen[1]);
    seen[4].andNot(seen[0]);
    sizes[0] = seen[0].cardinality();
    sizes[1] = seen[1].cardinality();
    sizes[2] = seen[2].cardinality();
    sizes[3] = seen[3].cardinality();
    sizes[4] = seen[4].cardinality();
 
    return Response.ok().entity(objectMapper.writeValueAsString(sizes)).build();
}

如果您找到进一步提高速度的方法,请告诉我!

-

通过Shutterstock 打开标志照片


翻译自: https://jaxenter.com/neo4j-and-the-power-of-open-source-108097.html

neo4j前端开源代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值