多线程读多文本写入MongoDB

10 篇文章 0 订阅

一、相关说明

前面有一篇博客写的是多线程读文本写入OracleNoSQL,但是写入的效率很慢(数据库和客户端不在一个机器上):三个文件夹(三个线程分别读里面的文本,共有4.3G*3大小的原始数据,花费时间大约为5-6小时)自己就想对比下写入MongoDB的效率和写入OracleNoSQL的效率。所以这就博客出现的原因。
同样由于代码过长,也没什么营养,主要是贴出来怕自己忘记。

二、代码

1.工程一览图
2.constructDoc.java
package oracle.common;

import java.util.Date;

<span style="color:#ff0000;">import org.bson.Document;</span>

import com.mongodb.client.MongoCollection;

public class constructDoc {
	public static Document construct(String[] fields)
	{
		int fieldsLen=fields.length;
		Document result=null;
		Document attribute=null;
		Date date=commonFunc.StringToDate(fields[1]);
		int cioid=commonFunc.StringToInt(fields[5]);
		int cgpsf=commonFunc.StringToInt(fields[7]);
		int cspeed=commonFunc.StringToInt(fields[8]);
		int cdir=commonFunc.StringToInt(fields[9]);
		
		float dy_54=commonFunc.StringToFloat(fields[fieldsLen-8]);
		float dx_54=commonFunc.StringToFloat(fields[fieldsLen-7]);
		
		float totalkm=commonFunc.StringToFloat(fields[fieldsLen-5]);
		int datekm=commonFunc.StringToInt(fields[fieldsLen-4]);
		int shtxt=commonFunc.StringToInt(fields[fieldsLen-1]);
		
		attribute=new Document("CTELNUM", fields[2])
										.append("DX", fields[3])
										.append("DY", fields[4])
										.append("CIOID", cioid)
										.append("CSTATUS",fields[6])
										.append("CGPSF",cgpsf)
										.append("CSPEED",cspeed)
										.append("CDIR",cdir)
										.append("ADDRESS",fields[10])
										.append("DALARMPEOPLE",fields[fieldsLen-6])
										.append("TOTALKM",totalkm)
										.append("DATEKM",datekm)
										.append("SHTXT",shtxt);
										
		result=new Document("objectid",fields[0])
								.append("start_time", date)
								.append("end_time", date)
								.append("center", <span style="color:#ff0000;">new Document</span>("lat",dy_54).append("lon", dx_54))
								.append("attribute",attribute);
							
		if(date==constants.StringToDateFunc_Exception
				||cioid==constants.StringToIntFunc_Exception
				||cgpsf==constants.StringToIntFunc_Exception
				||cspeed==constants.StringToIntFunc_Exception
				||dx_54==constants.StringToFloatFunc_Exception
				||dy_54==constants.StringToFloatFunc_Exception
				||totalkm==constants.StringToFloatFunc_Exception
				||datekm==constants.StringToIntFunc_Exception
				||shtxt==constants.StringToIntFunc_Exception)
		{
			return null;
		}
		return result;
	}

}


3.ReadData.java
package oracle.writeMongo;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import oracle.common.connectMongo;
import oracle.common.constructDoc;

import org.bson.Document;

import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;

public class ReadData implements Runnable{
	private String folderPath;

	private MongoDatabase db;
	private String encoding="GBK";
	
	public ReadData(String folderPath,MongoDatabase db) {
		// TODO Auto-generated constructor stub
		this.folderPath=folderPath;
		this.db=db;
	}
	
	private static String[] getFilePaths(String folderPath)
	{
		File files=new File(folderPath);
		String[] result=files.list();
		for(int i=0;i<result.length;i++)
		{
			result[i]=folderPath+"/"+result[i];
		}
		return result;
	}
	
	public void run()
	{
		String[] filePaths=getFilePaths(folderPath);
		BufferedReader bufferedReader=null;
		try
		{
			MongoCollection<Document> objectStatesCollec=db.getCollection("st_objectstates");
			for(int i=0;i<filePaths.length;i++)
			{
				System.out.println("开始读取"+folderPath+"第"+(i+1)+"个文本。。。");
				File file =new File(filePaths[i]);
				if(file.exists()&&file.isFile())
				{
					InputStreamReader reader=new InputStreamReader(new FileInputStream(file),encoding);
					<span style="color:#ff0000;">bufferedReader=new BufferedReader(reader,1024*1024*80);</span>
					
					String lineTxt="";
					Document doc=null;
					while((lineTxt=bufferedReader.readLine())!=null)
					{
						String[] fields=lineTxt.split(",");
						//List<Document>documents=new ArrayList<Document>();
						doc=constructDoc.construct(fields);
						if(doc!=null)
						{
							objectStatesCollec.insertOne(doc);
						}
						
					}
					reader.close();
				}
				System.out.println("读取"+folderPath+"第"+(i+1)+"个文本结束!");
			}
			System.out.println("存储任务结束!");
			
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
			return;
		}
	}

}

注意红色部分的代码,如果BufferedReader的第二个参数设置过大,会出现超出虚拟机内存的错误。同时,要理解这行代码的意思。
这行代码的意思就是:设置一次读入缓冲区的文本大小,这里为80m.在while里面循环的时候,就每次从缓冲区里读一行,然后进行解析。当缓冲区里读完了,代码会自动再次读80m的文本到缓冲区【需要切记的是这行代码不能写到while循环里,这是我们容易理解错的地方】。

4.connectMongo.java
package oracle.common;

import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;

public class connectMongo {
	
	public static MongoClient getClient(String ip,int port)
	{
		try
		{
			 return new MongoClient(ip,port);
		}
		catch(Exception e)
		{
			System.out.println("获取MongoClient失败,"+e.getMessage());
			return null;
		}
		
	}

	public static MongoDatabase getDB(MongoClient mongoClient,String dbName) {
		try
		{
			return mongoClient.getDatabase(dbName);
		}
		catch(Exception e)
		{
			System.out.println("获取数据库失败,"+e.getMessage());
			return null;
		}
		
	}
	
	public static boolean closeClient(MongoClient mongoClient)
	{
		try
		{
			mongoClient.close();
			
			return true;
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
			return false;
		}
		
	}

}

5.mainFunc.java
package oracle.main;

import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;

import oracle.common.connectMongo;
import oracle.writeMongo.ReadData;

public class mainFunc {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		String ip="localhost";//<strong><span style="color:#ff0000;">如果数据库不在客户端,请改为对应IP</span></strong>
		int port=27017;
		String dbName="testdb";
		MongoClient client=connectMongo.getClient(ip, port);
		if(client!=null)
		{
			MongoDatabase db=connectMongo.getDB(client, dbName);
			if(db!=null)
			{
				ReadData readThread1=new ReadData("/data/1-1",db);
				new Thread(readThread1).start();
			
				ReadData readThread2=new ReadData("/data/1-2",db);
				new Thread(readThread2).start();
			}
		}

		
		
	}

}

从上面代码可以看出,每个线程读的是不同文件夹下的文本。

剩下的java文件和之前的那篇“多线程读文本写入OracleNoSQL”差不多,因为是要比较写入的性能,所以要尽量保持数据的存入结构和代码的结构一致。
整个工程,可以 点击这里下载。【工程里面没有mongoDB的java driver,需要自己下载并添加进去】
同时,需要强调的是,由于本人不会如何监听除了主线程之外的所有线程何时结束,所以工程的代码中并没有在整个程序结束的时候关闭client.对于我们的程序没有影响,但是要记住自己确实没有关闭。

多线程只能公用一个MongoClient.官方文档上有说明, 查看这里,或者查看截图:


三、性能对比

同样地数据,同样地服务器,同样地线程数,写入OracleNoSQL需要5个多小时,接近6小时,写入MongoDB3小时四十分钟。这说明了写入MongoDB的效率比写入OracleNoSQL的效率高。这只是三个线程,如果是五个线程、六个线程,写入MongoDB的效率肯定能达到写入OracleNoSQL的两倍。

注:三个线程并不是最快的,读者可以将要读取的文本组织到多个文件夹(大于3)下,然后多线程读。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值