实现用户推荐和资源二度推荐,没算法,纯体力活

黄平俊 发布于 2012/09/03 17:03
阅读 3K+
收藏 15
需求:
     1、一定要轻量级。最好只有一个Jar,依懒不要太多。
    
     2、必须容易上手。有文档,有例子,还得是开源的,安装配制一步到位。

 
     符合以上要求的,你想到了谁? Hadoop ?

     在oschina和Google搜了好像都没找到合适的开源项目,结果还是在无意中发现了有一种数据库叫图数据库,然后就知道了neo4j。

      neo4j 的文档、例子俱全,而且只要引入两个jar包就可以直接使用,同时还提供了Service模式供单独运行,并且还提供了REST API 。

初步使用:

1、下载neo4j 1.7.2 稳定版。网址:http://neo4j.org/

2、 解压后引入neo4j-kernel-1.7.2.jar,geronimo-jta_1.1_spec-1.1.1.jar到项目中。
            添加辅助包,以下几个:
                neo4j-cypher-1.7.2.jar,
                neo4j-graph-algo-1.7.2.jar,
                neo4j-graph-matching-1.7.2.jar ,
                scala-library-2.9.0-1.jar

                加上面这几个辅助包,是为了用于执行类似SQL查询。

3、启动、初始化图数据库并输出二度人脉的结果。       

package com.test;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.cypher.javacompat.ExecutionResult;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.index.Index;

import com.example.Matrix.RelTypes;

/**
 *  用户浏览推荐
 *  @ author  Jimmy Huang
 * 
 */
public class VisitorGraph {
	private final static String DB_PATH = "target/visitor";
 	private static GraphDatabaseService graphDb;
 	
	public static void main(String[] args){
		initVisitor2Neo();
		getRecommUsers(1258381);
 	}
	
	/**
	 * 启动并初始化图数据库
	 */
	private static void initVisitor2Neo(){
		if(graphDb == null){
		 	graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);
			registerShutdownHook( graphDb );
		}
		// int[] a =  new int[]{1,3};int[] b = new int[1,2] ;int[] c = new int[2,3]
		List<int[]> vs = Db2Db.listVisitors();
		long s = System.currentTimeMillis();
		Transaction tx = graphDb.beginTx();
		try{
			//如果没有root根结点呢?
             Node referenceNode = graphDb.getReferenceNode();
 			for(int[] v : vs){
   				Node user = getNode(v[0]);
   				Node visitor = getNode(v[1]);  	
 
   				if(user == null && visitor != null){
   					user = graphDb.createNode();
   					user.setProperty("uid",v[0]);
   					Relationship rl = visitor.createRelationshipTo(user,RelTypes.KNOWS);
    				rl.setProperty("visitor", 1);   				
   				}else if(visitor == null && user != null){
   					visitor = graphDb.createNode();
   					visitor.setProperty("uid",v[1]);
    				Relationship rl = user.createRelationshipTo(visitor,RelTypes.KNOWS);
    				rl.setProperty("visitor", 1);
   				}else if (visitor == null && user == null){
   					user = graphDb.createNode();
   					user.setProperty("uid",v[0]);
    				referenceNode.createRelationshipTo(user, RelTypes.NEO_NODE);
   					visitor = graphDb.createNode();
   					visitor.setProperty("uid",v[1]);
   					
   					Relationship rl = user.createRelationshipTo(visitor,RelTypes.KNOWS);
    				rl.setProperty("visitor", 1);
   				}else if(visitor != null && user != null){
   					Iterator<Relationship> rls = user.getRelationships().iterator();
   					boolean hasRel = false;
   					while(rls.hasNext()){
   						Relationship rl = rls.next();
   						Node[] nodes = rl.getNodes();
    					for(Node n : nodes){
   							if(n.getId() == visitor.getId()){
   								hasRel = true; 
   								break;
   							}
   						}
   					}
   					if(!hasRel){
   						Relationship uv = user.createRelationshipTo(visitor, RelTypes.KNOWS);
   						uv.setProperty("visitor",1);
   					}
   				}
 			}
			tx.success();
		}finally{
			tx.finish();
		}
 	 	graphDb.shutdown();
	 	long et = System.currentTimeMillis();
 	 	System.out.println("写入"+vs.size()+"条数据用时:"+ (et-s)  );
	}
	
	
	/**
	 * 输出二度人脉
	 * @param uid
	 */
	public static void getRecommUsers(int uid){
		Node node = getNode(uid);	
		String sql = "START user=node({nodeId}) MATCH user-[:KNOWS]->friend-[:KNOWS]->friend_of_friend, user-[r?:KNOWS]->friend_of_friend WHERE r IS NULL RETURN friend_of_friend.uid, COUNT(*) ORDER BY COUNT(*) DESC, friend_of_friend.uid";
		ExecutionEngine engine = new ExecutionEngine( graphDb );
		Map<String, Object> params = new HashMap<String, Object>(); 
  		params.put("nodeId",node.getId());
		ExecutionResult result = engine.execute(sql,params );
		
		System.out.println(result.toString());
	}
	
	
	/**
	 * 存在则返回Node 否则返回Null
	 * @ param parentNode
	 * @ param uid

	 */
	public static Node getNode(int uid){
		if(graphDb == null){
		 	graphDb = new GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);
 		}
 		ExecutionEngine engine = new ExecutionEngine( graphDb );
		Map<String, Object> params = new HashMap<String, Object>(); 
  		params.put("uid",uid);
		ExecutionResult result = engine.execute( "start user=node(*) WHERE user.uid!={uid}  return distinct user",params );
 		Iterator<Object> objs = result.columnAs("user");
   		if(!objs.hasNext()){
			 return null;
		}else{
 			return (Node)objs.next();
		}
  	}	
	/**
	 * 关闭NEO4J
	 * @ param graphDb
	 */
	private static void registerShutdownHook( final GraphDatabaseService graphDb ){ 
	    Runtime.getRuntime().addShutdownHook( new Thread()
	    {
	        @Override
	        public void run()
	        {
	            graphDb.shutdown();
	        }
	    } );
	}
}

4、如何验证已添加的数据和输出 正确 结果的呢?

          请下载:neoclipse

          设置相应的neo4j的数据库路径,如下图:
         

          neoclipse 不用配制Eclipse的,解压后直接运行即可。

5、图数据库NEO4J中存储的数据结构图:

6、输出二度人脉结果

      a、执行getRecommUsers(1258381);后获得的数据结果如下:

    b、执行 getRecommUsers(1540);后获得的数据结果如下:

7、应用场景。

    1、B2C商品推荐:购买过此商品的用户还购买过哪些商品等等类似的商品《-》用户 的推荐

    2、用户推荐:类似二度……N度的用户推荐。

    3、资源推荐:推荐某资源的人还推荐过哪些资源或贴子
         ……………………………………………………

8、题外话:

      为何不用现在流行的Hadoop实现呢?

      因为:不是每个公司都有海量数据的,不是每个公司都有几十、上百号的开发技术人员的,
                Hadoop 那是高帅富版的实现,而NEO4J是屌丝版的实现。

 

        话说在写贴时,没有自动保存成草稿的功能,写了三次,第一次不小心点错导航的链接,没了。第二次浏览器崩溃,没了~~
        还有在程序中有 @符号,居然也被转义成会员链接

加载中
0
朱__朱
朱__朱
深表同情,同样经常有有类似遭遇。现在习惯性写一会儿就来个Ctrl+A,Ctrl+C.....
0
吐槽的达达仔
吐槽的达达仔
进行遍历的话,不知道效果怎样。。。
0
wfifi
wfifi
有例子,不错
0
敲代码猥琐男
敲代码猥琐男
建议例子中的文件不完整的话,最好注明一下
0
伪猫
伪猫
回头试试 看起来很厉害的样子
0
苏生不惑
苏生不惑
不明觉厉。。。
0
1187856322
1187856322
能发一份完整版的代码给我吗?邮箱1187856322@qq.com
0
j
jlb_angle
我最近正在学习neo4j,我想问下,这个DB_PATH的值是什么。
0
gzthinker
gzthinker
DB_PATH的值, graphDb =new   GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);每次都创建了一个
0
西夏一品堂
西夏一品堂

GraphDatabaseFactory().newEmbeddedDatabase(DB_PATH);每次都创建了一个

请问,数据怎么持久化

返回顶部
顶部