<转>Neo4j结合Spring Data Graph的例子

 

原文地址:http://www.openfetion.com/category/neo4j.aspx

在spring中使用neo4j

 四月 19, 2010 08:07 by    Terry

从neo4j官方网站http://neo4j.org/下载neo4j-apoc包,或者自己获取源码自行打包也可。
我使用的是java开发工具是Spring Tool Suite,新建一个spring web mvc项目,模板引擎使用velocity(velocity.apache.org),web.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="attentiondb" version="2.5">
    <display-name>attentiondb</display-name>

    <!--
        Enables clean URLs with JSP views e.g. /welcome instead of
        /app/welcome
    -->
    <filter>
        <filter-name>UrlRewriteFilter</filter-name>
        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>UrlRewriteFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- Handles all requests into the application -->
    <servlet>
        <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/spring/app-config.xml
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
        <url-pattern>/attentiondb/*</url-pattern>
    </servlet-mapping>

</web-app>
在/WEB-INF/spring/app-config.xml中配置neo4j bean(这里需要注意spring 2.5与3.0的区别,3.0中使用map元素代替util:map元素):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!--
        Scans the classpath of this application for @Components to deploy as
        beans
    -->
    <context:component-scan base-package="attentiondb" />
    
    <bean id="graphDbService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
        init-method="enableRemoteShell" destroy-method="shutdown">
        <constructor-arg index="0" value="d://attentiondb" />
        <constructor-arg index="1">
            <map>
                <entry key="create" value="false"/>
                <entry key="neostore.nodestore.db.mapped_memory" value="20M"/>
                <entry key="neostore.propertystore.db.mapped_memory" value="90M"/>
                <entry key="neostore.nodestore.db.mapped_memory" value="1M"/>
                <entry key="neostore.nodestore.db.mapped_memory" value="1M"/>
                <entry key="neostore.nodestore.db.mapped_memory" value="130M"/>
                <entry key="neostore.nodestore.db.mapped_memory" value="100M"/>
            </map>
        </constructor-arg>
    </bean>
    <bean id="indexService" class="org.neo4j.index.lucene.LuceneIndexService"
        destroy-method="shutdown">
        <constructor-arg index="0" ref="graphDbService" />
    </bean>

    <bean id="velocityConfig"
        class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
        <property name="resourceLoaderPath" value="/WEB-INF/views/" />
    </bean>

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
        <property name="cache" value="true" />
        <property name="prefix" value="" />
        <property name="suffix" value=".vm" />
    </bean>

    <!-- Application Message Bundle -->
    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="/WEB-INF/messages/messages" />
        <property name="cacheSeconds" value="0" />
    </bean>

    <!-- Configures Spring MVC -->
    <import resource="mvc-config.xml" />

</beans>

第一个打分



neo4j处理好友关系

 四月 1, 2010 16:44 by    Terry

在实际业务中,我们经常遇到这样的场景,比如查找好友的好友。处理此类业务,neo4j体现出了方便快捷强大的功能。
比如我们有九个人:
Id Name
1  梁1
2  梁2
3  梁3
4  梁4
5  梁5
6  梁6
7  梁7
8  梁8
9  梁9

其中:梁1、梁2认识所有的人,梁9认识梁1、梁2、梁8
我们要实现查找梁9的好友的好友(不包括自身和直接好友)。
首先定义好友关系枚举:
public enum FriendRelationTypes implements RelationshipType {
        KNOWS
    }
创建上述好友关系graph database:
ArrayList<Node> nodes = new ArrayList<Node>(9);

        Map<String, String> props = new HashMap<String, String>();
        // props.put("create", "false");

        GraphDatabaseService graphDb = new EmbeddedGraphDatabase("var/base",
                props);
        
        Transaction tx = graphDb.beginTx();

        try {
            for (int i = 0; i < 9; i++) {
                Node node = graphDb.createNode();
                node.setProperty("Id", i + 1);
                node.setProperty("Name", "梁" + i);

                nodes.add(node);
            }

            Node node1 = nodes.get(0);
            Node node2 = nodes.get(1);
            Node node9 = nodes.get(8);

            for (int i = 2; i < 9; i++) {
                Node node = nodes.get(i);

                node.createRelationshipTo(node1, FriendRelationTypes.KNOWS);
                node.createRelationshipTo(node2, FriendRelationTypes.KNOWS);
            }

            nodes.get(7).createRelationshipTo(node9, FriendRelationTypes.KNOWS);

            tx.success();

        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            tx.finish();
            graphDb.shutdown();
        }
显示所有的好友,查找梁9的好友并显示:
Map<String, String> props = new HashMap<String, String>();
        props.put("create", "false");

        GraphDatabaseService graphDb = new EmbeddedGraphDatabase("var/base",
                props);

        Transaction tx = graphDb.beginTx();

        try {
            Iterable<Node> nodes = graphDb.getAllNodes();

            for (Node node : nodes) {
                if (node.hasProperty("Id")) {
                    System.out.println("NodeId: " + node.getId() + " Id: "
                            + node.getProperty("Id") + " Name:"
                            + node.getProperty("Name"));
                }
            }

            Node node = graphDb.getNodeById(9);

            Traverser friends = node.traverse(Traverser.Order.BREADTH_FIRST,
                    StopEvaluator.END_OF_GRAPH, new ReturnableEvaluator() {
                        public boolean isReturnableNode(TraversalPosition pos) {
                            System.out.println(pos.depth());

                            return pos.depth() != 1 && pos.notStartNode();
                        }
                    }, FriendRelationTypes.KNOWS, Direction.BOTH);

            for (Node friend : friends) {
                System.out.println("Id:" + friend.getProperty("Id") + " Name:"
                        + friend.getProperty("Name"));
            }

            tx.success();

        } finally {
            tx.finish();
            graphDb.shutdown();
        }
在这里我们可以看到Traverser的简单应用。在neo4j查找中,需要先找到一个根节点,然后再这个根节点上创建Traverser来进行各种查询。

第一个打分



neo4j初体验

 三月 31, 2010 03:51 by    Terry

neo4j(http://neo4j.org/)一个开源的图数据库graph database。neo4j是基于磁盘文件、内嵌、支持java事务JTS,用于存储图结构数据的数据库引擎。具体的资料可以查看官方网站。
neo4j的存储结构中重点的就是Node(节点)和Relationship(关系)。Node与Node之间通过Relationship连接,Node与Node之间可以具有多种关系,但是两个Node不能相同。
下面通过一个具体的业务来演示一下neo4j的简单使用。
我们需要来存储用户与用户之间都有过什么关系,关系之间有什么样的权重,这样通过用户之间的关系和关系的权重,在此基础上我们可以分析用户之间的关注度。在数据中是这样存储的:
relation关系表,用来枚举用户之间可能存在的关系,及关系的自定义权重
1    发表文章评论    3
2    回复文章评论    1
3    喜欢文章    1
4    文章点名    50
5    留言    10
6    回复留言    3
7    评论留言飞语    5
8    回复留言飞语评论    5
9    收藏留言飞语    3
10    评论图片    3
11    回复图片评论    3
12    图片圈人    20
13    分享     20
14    站内信    2
15    回复站内信    2
graphs用户关系系表,存储两个用户之间都具有什么样的关系。有三个字段:BeginUserId开始用户Id、EndUserId结束用户Id、Reason原因。其中Reason是xml格式数据,记录了用户Id为EndUserId对用户Id为BeginUserId发生过什么行为,产生过什么样的关系,如1490578    18129607    21    <a t="3" e="1" /><a t="13" e="20" />,表明用户18129607对用户1490578曾经回复留言、喜欢文章,e可以次数以表示权重。
以下是如何通过neo4j来创建此业务的graph database,实际graphs表中有600万左右的数据,我们为了演示只取前1000条,并且只是通过neo4j kernel核心包来创建。
创建AttentionRelationTypes枚举,实现接口RelationshipType,这是必须的。节点直接的Relationship是通过RelationshipType的不同名称来定义并区分的。
package easynet.neo4j;

import org.neo4j.graphdb.RelationshipType;

/*
 * 关注关系
 */
public enum AttentionRelationTypes implements RelationshipType {
    PublishedComments, ReplyToComment, FavoriteArticle, ArticleMention, Message, ReplyToMessage, CommentOnMood, ReplyToMoodComments, FavoriteMood, CommentOnPicture, ReplyToPictureComments, CirclePicture, Share, SiteMessage, ReplyToSiteMessage
}
很重要的一点,由于neo4j是自己维护Node的Id,我们不能把UserId当作Node的Id,而只能作为一个Node的Property。但是因为我们在业务上需要保证作为用户Node的唯一性,所以创建一个用来维护UserId与NodeId的对应关系表:usernode(有两个字段UserId、NodeId)。定义一个类NodeStore用来分装此操作。
package easynet.neo4j;

import java.sql.*;

import net.sourceforge.jtds.jdbcx.*;

public class NodeStore {
    private JtdsDataSource dataSource = null;
    private String insertQuery = "{call [UserNode_Create](?,?)}";
    private String getNodeIdQuery = "{call [UserNode_GetNodeIdByUserId](?)}";

    public NodeStore(JtdsDataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void store(int userId, long nodeId) throws SQLException {
        Connection con = dataSource.getConnection();
        CallableStatement cst = con.prepareCall(insertQuery);

        cst.setInt(1, userId);
        cst.setLong(2, nodeId);

        cst.execute();

        cst.close();
    }

    public long getNodeIdByUserId(int userId) throws SQLException {
        int nodeId = 0;

        Connection con = dataSource.getConnection();
        CallableStatement cst = con.prepareCall(getNodeIdQuery);

        cst.setInt(1, userId);

        ResultSet rs = cst.executeQuery();

        while (rs.next()) {
            nodeId = rs.getInt("NodeId");
        }

        cst.close();

        return nodeId;
    }
}
下面就是具体通过neo4j创建graph database的代码了:
package easynet.neo4j;

import java.io.*;
import java.sql.*;
import java.util.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.*;

import net.sourceforge.jtds.jdbcx.*;

import org.neo4j.graphdb.*;
import org.neo4j.graphdb.Node;
import org.neo4j.kernel.*;
import org.neo4j.kernel.impl.traversal.*;

public class AttentionRelationShell {

    /**
     * 处理关注关系
     * 
     * @throws SQLException
     */
    public static void main(String[] args) {
        JtdsDataSource dataSource = new JtdsDataSource();
        dataSource.setServerName("192.168.1.100");
        dataSource.setPortNumber(1433);
        dataSource.setDatabaseName("yadong_temp");
        dataSource.setUser("sa");
        dataSource.setPassword("devterry");

        NodeStore nodeStore = new NodeStore(dataSource);

        long beginTime = System.currentTimeMillis();
        System.out.println("开始创建...");

        Map<String, String> props = new HashMap<String, String>();
        // props.put("create", "false");

        GraphDatabaseService graphDb = new EmbeddedGraphDatabase("var/base",
                props);

        try {

            Connection con = dataSource.getConnection();
            Statement st = con.createStatement();
            ResultSet rs = st
                    .executeQuery("SELECT [BeginUserId],[EndUserId],[Reason] FROM [graphs]");

            while (rs.next()) {
                int beginUserId = rs.getInt("BeginUserId");
                int endUserId = rs.getInt("EndUserId");
                String reason = rs.getString("Reason");

                System.out.println("beginUserId:" + beginUserId
                        + " endUserId:" + endUserId);

                Node beginUserNode = null;
                Node endUserNode = null;

                Transaction tx = graphDb.beginTx();

                try {
                    long beginNodeId = nodeStore.getNodeIdByUserId(beginUserId);
                    long endNodeId = nodeStore.getNodeIdByUserId(endUserId);

                    if (beginNodeId != 0) {
                        beginUserNode = graphDb.getNodeById(beginNodeId);
                    } else {
                        beginUserNode = graphDb.createNode();
                        beginUserNode.setProperty("UserId", beginUserId);

                        nodeStore.store(beginUserId, beginUserNode.getId());
                    }

                    if (endNodeId != 0) {
                        endUserNode = graphDb.getNodeById(endNodeId);
                    } else {
                        endUserNode = graphDb.createNode();
                        endUserNode.setProperty("UserId", endUserId);

                        nodeStore.store(endUserId, endUserNode.getId());
                    }

                    try {
                        DocumentBuilderFactory factory = DocumentBuilderFactory
                                .newInstance();
                        DocumentBuilder builder = factory.newDocumentBuilder();
                        StringReader sr = new StringReader("<relation>"
                                + reason + "</relation>");
                        InputSource is = new InputSource(sr);
                        Document doc = builder.parse(is);
                        NodeList nodes = doc.getElementsByTagName("a");

                        // 创建用户Node之间的Relationship
                        for (int i = 0; i < nodes.getLength(); i++) {
                            org.w3c.dom.Node node = nodes.item(i);

                            NamedNodeMap attributes = node.getAttributes();

                            int realtionTypeId = Integer.parseInt(attributes
                                    .getNamedItem("t").getNodeValue());
                            int weight = Integer.parseInt(attributes
                                    .getNamedItem("e").getNodeValue());

                            AttentionRelationTypes relationTypes = AttentionRelationTypes.PublishedComments;

                            switch (realtionTypeId) {
                            case 1:
                                relationTypes = AttentionRelationTypes.PublishedComments;
                                break;
                            case 2:
                                relationTypes = AttentionRelationTypes.ReplyToComment;
                                break;
                            case 3:
                                relationTypes = AttentionRelationTypes.FavoriteArticle;
                                break;
                            case 4:
                                relationTypes = AttentionRelationTypes.ArticleMention;
                                break;
                            case 5:
                                relationTypes = AttentionRelationTypes.Message;
                                break;
                            case 6:
                                relationTypes = AttentionRelationTypes.ReplyToMessage;
                                break;
                            case 7:
                                relationTypes = AttentionRelationTypes.CommentOnMood;
                                break;
                            case 8:
                                relationTypes = AttentionRelationTypes.ReplyToMoodComments;
                                break;
                            case 9:
                                relationTypes = AttentionRelationTypes.FavoriteMood;
                                break;
                            case 10:
                                relationTypes = AttentionRelationTypes.CommentOnPicture;
                                break;
                            case 11:
                                relationTypes = AttentionRelationTypes.ReplyToPictureComments;
                                break;
                            case 12:
                                relationTypes = AttentionRelationTypes.CirclePicture;
                                break;
                            case 13:
                                relationTypes = AttentionRelationTypes.Share;
                                break;
                            case 14:
                                relationTypes = AttentionRelationTypes.SiteMessage;
                                break;
                            case 15:
                                relationTypes = AttentionRelationTypes.ReplyToSiteMessage;
                                break;
                            }

                            Relationship relationShip = endUserNode
                                    .createRelationshipTo(beginUserNode,
                                            relationTypes);
                            relationShip.setProperty("weight", weight);
                        }
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                } finally {
                    tx.success();
                    tx.finish();
                }
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            graphDb.shutdown();
        }

        System.out.println("完成 共用时:"
                + (System.currentTimeMillis() - beginTime));
    }
}

 

你可能感兴趣的:(spring,neo4j)