1. 程式人生 > >網站使用者行為資料統計與分析之二:資料寫入mongodb

網站使用者行為資料統計與分析之二:資料寫入mongodb

    接著上一篇博文,我再補充一下:

    在js中收集到使用者行為資料之後呢,我們要在後臺對資料進行處理,怎麼處理?在實際專案中我分兩條路走:

    一、直接寫入mongodb,隨著電商網站規模越來越大,訪問量越來越高,這種非關係型資料庫可以有效地化解高併發的問題

    二、做日誌處理(後臺資料-----redis-----logstash-----elasticsearch------kibana)

    在這篇文章中,我們先來探討寫DB。

    兩種方式,一、利用java mongodb api;二、利用log4j

    方式一mongodb提供了很友好的java api

    我們先來看看:

   package com.founder.ec.util;

   import java.net.SocketException;
   import java.net.UnknownHostException;

   import com.founder.ec.entity.BehaviorUser;
   import com.mongodb.BasicDBObject;
   import com.mongodb.DB;
   import com.mongodb.DBCollection;
   import com.mongodb.DBObject;
   import com.mongodb.Mongo;

   /**
    * 實現MongoDB的CRUD操作
    * 
    * @author 五味子
    * @version 2014/04/04
    */
    public class MongOpera {

	private static DB db;
	private static DBCollection users;
	private static Mongo mg;

	@SuppressWarnings("deprecation")
	public static DBCollection init() {
		try {
			try {
				mg = DBManager.inits("192.168.2.87", 27017, 300);
			} catch (SocketException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// 獲取temp DB;如果預設沒有建立,mongodb會自動建立
		db = mg.getDB("test");
		// 獲取users DBCollection;如果預設沒有建立,mongodb會自動建立
		users = db.getCollection("testdb");
		return users;
	}
	/**//**
	 * 銷燬mongo物件
	 * @param
	 * @return
	 *//*
	public static void destory() {
		if (mg != null)
			mg.close();
		mg = null;
		db = null;
		users = null;
		System.gc();//記憶體垃圾回收
	}
	*//**
	 * 列印查詢結果
	 * @param o
	 * @return
	 *//*
	public static void print(Object o) {
		System.out.println(o);
	}
	*//**
	 * 查詢所有資料
	 * @param
	 * @return
	 *//*
	private static void queryAll() {
		print("查詢users的所有資料:");
		// db遊標
		DBCursor cur = users.find();
		while (cur.hasNext()) {
			print(cur.next());
		}
	}*/
	/**
	 * 新增資料
	 * @param Synchronized 
	 * @param
	 * @return
	 */
	public static void add(BehaviorUser behaviorUser) {
		// 先查詢所有資料
		//queryAll();
		//print("count: " + users.count());

		DBObject user = new BasicDBObject();
		user.put("sessionId", behaviorUser.getSessionId());
		user.put("uuid", 24);
		user.put("memberId", behaviorUser.getMemberId());
		user.put("refPage", behaviorUser.getRefPage());
		user.put("firstPage", behaviorUser.getFirstPage());
		user.put("initTime", behaviorUser.getInitTime());
		user.put("orderId", behaviorUser.getOrderId());
		user.put("currentTime", behaviorUser.getCurrentTime());
		user.put("currentURL", behaviorUser.getCurrentPage());
		
		users = init();
		
		users.save(user);//儲存,getN()獲取影響行數
		
		/*List list1 = new ArrayList();
		
		List<DBObject> list2 = null;
		
		list1.add(user);
		
		if (list1.size()>=30) {
			
			list2 = new ArrayList();
			
			Synchronized{
				
				list2.addAll(list1);
				list1.clear();
				
			}
			
			new Thread().start();
		
			new Thread(
				
				try{
					
					users.insert(list2);
				}catch(ApplicationException e){
					
				}
			).start();
			
		  }*/
	
		
		
		//print(users.save(user).getN());

		/*// 擴充套件欄位,隨意新增欄位,不影響現有資料
		user.put("sex", "男");
		print(users.save(user).getN());

		// 新增多條資料,傳遞Array物件
		print(users.insert(user, new BasicDBObject("name", "tom")).getN());

		// 新增List集合
		List<DBObject> list = new ArrayList<DBObject>();
		list.add(user);
		DBObject user2 = new BasicDBObject("name", "lucy");
		user.put("age", 22);
		list.add(user2);
		// 新增List集合
		print(users.insert(list).getN());

		// 查詢下資料,看看是否新增成功
		print("count: " + users.count());
		queryAll();*/
	}
	
      /*	*//**
	 * 移除資料
	 * @param
	 * @return
	 *//*
	public static void remove() {
		queryAll();
		print("刪除id = 4de73f7acd812d61b4626a77:"
				+ users.remove(
						new BasicDBObject("_id", new ObjectId(
								"4de73f7acd812d61b4626a77"))).getN());
		print("remove age >= 24: "
				+ users.remove(
						new BasicDBObject("age", new BasicDBObject("$gte", 24)))
						.getN());
	}
	*//**
	 * 修改資料
	 * @param
	 * @return
	 *//*
	public static void modify() {
		print("修改:"
				+ users.update(
						new BasicDBObject("_id", new ObjectId(
								"4dde25d06be7c53ffbd70906")),
						new BasicDBObject("age", 99)).getN());
		print("修改:"
				+ users.update(
						new BasicDBObject("_id", new ObjectId(
								"4dde2b06feb038463ff09042")),
						new BasicDBObject("age", 121), true,// 如果資料庫不存在,是否新增
						false// 多條修改
				).getN());
		print("修改:"
				+ users.update(new BasicDBObject("name", "haha"),
						new BasicDBObject("name", "dingding"), true,// 如果資料庫不存在,是否新增
						true// false只修改第一天,true如果有多條就不修改
				).getN());

		// 當資料庫不存在就不修改、不新增資料,當多條資料就不修改
		// print("修改多條:" + coll.updateMulti(new BasicDBObject("_id", new
		// ObjectId("4dde23616be7c19df07db42c")), new BasicDBObject("name",
		// "199")));
	}
	*//**
	 * 條件查詢
	 * @param
	 * @return
	 *//*
	public static void query() {
		// 查詢所有
		// queryAll();

		// 查詢id = 4de73f7acd812d61b4626a77
		print("find id = 4de73f7acd812d61b4626a77: "
				+ users.find(
						new BasicDBObject("_id", new ObjectId(
								"4de73f7acd812d61b4626a77"))).toArray());

		// 查詢age = 24
		print("find age = 24: "
				+ users.find(new BasicDBObject("age", 24)).toArray());

		// 查詢age >= 24
		print("find age >= 24: "
				+ users.find(
						new BasicDBObject("age", new BasicDBObject("$gte", 24)))
						.toArray());
		print("find age <= 24: "
				+ users.find(
						new BasicDBObject("age", new BasicDBObject("$lte", 24)))
						.toArray());

		print("查詢age!=25:"
				+ users.find(
						new BasicDBObject("age", new BasicDBObject("$ne", 25)))
						.toArray());
		print("查詢age in 25/26/27:"
				+ users.find(
						new BasicDBObject("age", new BasicDBObject(
								QueryOperators.IN, new int[] { 25, 26, 27 })))
						.toArray());
		print("查詢age not in 25/26/27:"
				+ users.find(
						new BasicDBObject("age", new BasicDBObject(
								QueryOperators.NIN, new int[] { 25, 26, 27 })))
						.toArray());
		print("查詢age exists 排序:"
				+ users.find(
						new BasicDBObject("age", new BasicDBObject(
								QueryOperators.EXISTS, true))).toArray());

		print("只查詢age屬性:"
				+ users.find(null, new BasicDBObject("age", true)).toArray());
		// 只查詢一條資料,多條去第一條
		print("findOne: " + users.findOne());
		print("findOne: " + users.findOne(new BasicDBObject("age", 26)));
		print("findOne: "
				+ users.findOne(new BasicDBObject("age", 26),
						new BasicDBObject("name", true)));

		// 查詢修改、刪除
		print("findAndRemove 查詢age=25的資料,並且刪除: "
				+ users.findAndRemove(new BasicDBObject("age", 25)));

		// 查詢age=26的資料,並且修改name的值為Abc
		print("findAndModify: "
				+ users.findAndModify(new BasicDBObject("age", 26),
						new BasicDBObject("name", "Abc")));
		print("findAndModify: "
				+ users.findAndModify(new BasicDBObject("age", 28), // 查詢age=28的資料
						new BasicDBObject("name", true), // 查詢name屬性
						new BasicDBObject("age", true), // 按照age排序
						false, // 是否刪除,true表示刪除
						new BasicDBObject("name", "Abc"), // 修改的值,將name修改成Abc
						true, true));
		queryAll();
	}

	*//**
	 * mongoDB不支援聯合查詢、子查詢,這需要我們自己在程式中完成。將查詢的結果集在Java查詢中進行需要的過濾即可。
	 * @param
	 * @return
	 *//*
	public static void testOthers() {
		DBObject user = new BasicDBObject();
		user.put("name", "hoojo");
		user.put("age", 24);

		// JSON 物件轉換
		print("serialize: " + JSON.serialize(user));
		// 反序列化
		print("parse: " + JSON.parse("{ \"name\" : \"hoojo\" , \"age\" : 24}"));

		print("判斷temp Collection是否存在: " + db.collectionExists("temp"));

		// 如果不存在就建立
		if (!db.collectionExists("temp")) {
			DBObject options = new BasicDBObject();
			options.put("size", 20);
			options.put("capped", 20);
			options.put("max", 20);
			print(db.createCollection("account", options));
		}

		// 設定db為只讀
		db.setReadOnly(true);

		// 只讀不能寫入資料
		db.getCollection("test").save(user);
	}*/
}
    以上程式碼,CRUD好像都有了!但是有個問題需要指出,mongodb有預設的連線池,只不過預設連線數為10,我們如果有特別需要,可以自建連線池
   package com.founder.ec.util;
   import com.mongodb.Mongo;
   import com.mongodb.MongoOptions;
   /**
   * mongodb連線池
   * @author 五味子
   * @version 2014/04/04
   */
   public class DBManager{
	
	    private static Mongo mongo;  //mongodb資料庫操作物件
	    
	    /**
	     * 
	     * @param ip ip地址
	     * @param port 埠號
	     * @param poolSize 連線數
	     * @return Mongo操作物件
	     * @throws java.net.UnknownHostException 找不到主機異常
	     */
	    public static Mongo inits(final String ip, int port, int poolSize) throws java.net.UnknownHostException,java.net.SocketException {  
	    	try{
		        System.setProperty("MONGO.POOLSIZE", String.valueOf(poolSize));  
		        if (mongo == null) {  
		            mongo = new Mongo(ip, port);  
		            MongoOptions options = mongo.getMongoOptions(); 
		            //每個主機的連線數
		            options.connectionsPerHost = poolSize;  
		            //這個控制是否在一個連線時,系統會自動重試
		            options.autoConnectRetry = true;
		            //最大等待連線的執行緒阻塞時間 
		            options.maxWaitTime = 5000; 
		           //socket超時。0是預設和無限
		            options.socketTimeout = 2000; 
		            //連線超時的毫秒。0是預設和無限
		            options.connectTimeout = 15000;
		           //執行緒佇列數,它以上面connectionsPerHost值相乘的結果就是執行緒佇列最大值。如果連線執行緒排滿了佇列就會丟擲“Out of semaphores to get db”錯誤。
		            options.threadsAllowedToBlockForConnectionMultiplier = 4; 
		        }  
	    	}catch(Exception e){
	    		
	    		e.getMessage();
	    	}
	    	 return mongo;
	    }  
	}  


    

      方式二:log4j

      這種方式比較簡單,只不過只能作為新增資料用

      在log4j.propertites檔案中:

    log4j.rootLogger=debug, stdout, R, MongoDB

    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%-d{MM-dd HH:mm:ss.SSS} %-5p - [%c{1}.%t] %m%n

    log4j.appender.R=org.apache.log4j.RollingFileAppender
    log4j.appender.R.File=D:/data/Sample.log
    log4j.appender.R.MaxFileSize=1000KB
    log4j.appender.R.MaxBackupIndex=1
    log4j.appender.R.layout=org.apache.log4j.PatternLayout
    log4j.appender.R.layout.ConversionPattern=%-d{MM-dd HH:mm:ss.SSS} %-5p - [%c{1}.%t] %m%n

    #log4j.appender.MongoDB=org.log4mongo.MongoDbAppender
    #log4j.appender.MongoDB.databaseName=test
    #log4j.appender.MongoDB.collectionName=testdb
    #log4j.appender.MongoDB.hostname=192.168.2.86
    #log4j.appender.MongoDB.port=27017
     

     注意打上#的幾段程式碼,應該不要解釋吧!

     什麼?你看不懂屬性檔案,那你還是先補補屬性檔案再來看吧!
     想進一步瞭解Mongodb,請閱讀超詳細的中文指南:
     http://download.csdn.net/detail/u013339851/7120473