使用storm实现实时GPS数据客流特征分析系统:源码分析

问题导读
1.项目背景是什么?
2.nextTuple() 的作用是什么?
3.declareOutputFields(OutputFieldsDeclarer declarer)的作用是什么?
4.excute() 和declareOutputFields(OutputFieldsDeclarer declarer) 的作用是什么?





项目背景:
实时GPS数据客流特征分析系统,项目来源于深圳交委,数据来源是深圳大约5万两出租车和公交车的车载GPS仪,其目的是要研究出行者的出行特征、实时路况、客流特征等。

开发环境:请参考: storm的开发环境部署指导


函数详解:
一、GPSReceiverSpout

最重要的两个函数是 nextTuple() declareOutputFields(OutputFieldsDeclarer declarer)


nextTuple()告诉storm下一个tuple是什么内容,其处理过程是先用一个socket函数接受来自网络的实时GPS数据,用lineSplit()将GPS以逗号分隔 成字符串数组,发送给下一个处理单元 DistrictMatchingBolt。
例如一条原始GPS记录:粤BXXXXX,114.121765,22.569218,2013-02-08 17:29:58,1065382,28,101,0,蓝色
_collector.emit(new Values(GPSRecord[0],GPSRecord[3],GPSRecord[7],GPSRecord[5],GPSRecord[6] , GPSRecord[2],GPSRecord[1])) 这一条语句则提取了GPS记录中的第0、3、7、5、6、2、1列字符串发送给下一个处理单元。





declareOutputFields()告诉下一个处理单元DistrictMatchingBolt: spout的输出数据即DistrictMatchingBolt的输入数据格式的列数和内容,即:"vehicle_number","date_time","occupied","speed","bearing","lantitude","longitude" 共7列。


  1. public class GPSReceiverSpout implements IRichSpout {
  2.     private static final long serialVersionUID = 1L;
  3. private SpoutOutputCollector _collector;
  4.     private BufferedReader fileReader;
  5.     //private TopologyContext context;
  6.     //private String file="/home/ghchen/2013-01-05.1/2013-01-05--11_05_48.txt";
  7.     private TupleInfo tupleInfo=new TupleInfo();
  8.    
  9.     static Socket sock=null;
  10.    
  11.     @Override
  12.     public void close() {
  13.     }

  14.     @Override
  15.     public void open(Map conf, TopologyContext context, SpoutOutputCollector collector)
  16. {
  17. _collector = collector;

  18. System.out.println("This is open function in FieldSpout !");


  19. }


  20.     @SuppressWarnings("unused")
  21. @Override
  22. public void nextTuple() {
  23.      int count=0;
  24.      int ch=0;
  25.      int err=0;
  26.      try {
  27.      if(sock==null){
  28.      sock=new Socket("172.20.14.XXX",portXXXX);}
  29.      while(true){
  30. byte[] b3= new byte[3];
  31. if(sock!=null ){
  32. try{
  33. sock.getInputStream().read(b3,0,3);
  34. ch=b3[0];
  35. }catch ( Exception e){
  36. System.out.println("connection reset, reconnecting ...");
  37. sock.close();
  38. Thread.sleep(100);
  39. sock=new Socket("172.20.14.XXX",portXXXX);;
  40. }

  41. }else{
  42. sock=new Socket("172.20.14.XXX",portXXXX);;
  43. break ;
  44. }
  45.      int len=SocketJava.bytesToShort(b3, 1);
  46.      if(len<0) break;
  47.      byte[] bytelen= new byte[len];
  48.      sock.getInputStream().read(bytelen);
  49.      if(bytelen==null){
  50.      System.out.println("read the second part from byte from socket failed ! ");
  51.      break;
  52.      }
  53.      sock.getInputStream().markSupported();
  54.      sock.getInputStream().mark(3);

  55.      String gpsString=SocketJava.DissectOneMessage(ch,bytelen);
  56.        String[] GPSRecord=null;
  57.      if(gpsString!=null){
  58.      GPSRecord =gpsString.split(TupleInfo.getDelimiter());

  59.      _collector.emit(new Values(GPSRecord[0],GPSRecord[3],GPSRecord[7],GPSRecord[5],
  60.      GPSRecord[6] , GPSRecord[2],GPSRecord[1]));
  61.      //}

  62.      }else{
  63.      break;
  64.      }

  65.      }
  66.      } catch (IOException e) {
  67.       e.printStackTrace();
  68.      } catch (Exception e) {
  69.       e.printStackTrace();
  70.      }



  71.     }

  72.     @Override
  73.     public void ack(Object id) {
  74.      System.out.println("OK:"+id);
  75.     }
  76.    

  77.     @Override
  78.     public void fail(Object id) {
  79.      System.out.println("Fail:"+id);
  80.     }

  81.     @Override
  82.     public void declareOutputFields(OutputFieldsDeclarer declarer) {

  83.      TupleInfo tuple = new TupleInfo();
  84.      Fields fieldsArr;
  85.      try {
  86.      fieldsArr= tuple.getFieldList();
  87.      declarer.declare(fieldsArr);

  88. } catch (Exception e) {
  89. throw new RuntimeException("error:fail to new Tuple object in declareOutputFields, tuple is null",e);
  90. }

  91.     }

  92. @Override
  93. public void activate() {
  94. }

  95. @Override
  96. public void deactivate() {
  97. }

  98. @Override
  99. public Map<String, Object> getComponentConfiguration() {
  100. return null;
  101. }

  102. static int count=0;
  103. public static void writeToFile(String fileName, Object obj){
  104. try {

  105. FileWriter fwriter;
  106. fwriter= new FileWriter(fileName,true);
  107. BufferedWriter writer= new BufferedWriter(fwriter);

  108. writer.write(obj.toString());

  109. writer.close();

  110. } catch (IOException e1) {

  111. e1.printStackTrace();
  112. }
  113. }   
  114. }  
复制代码



二、DistrictMatchingBolt


最重要的两个函数是 excute() 和declareOutputFields(OutputFieldsDeclarer declarer)。

excute() 将GPSReceiverSpout接受到的数据提取经度和纬度,调用Sects类 Sect.fetchSect(GPSrecord)方法,查询本地的地理信息数据库,返回该条GPS记录所在的区域标号 districtID,并将这个字段添加到GPS后面,发射给下一个bolt : countBolt。

declareOutputFields() 告诉下一个countBolt , 这个DistrcitMatchingBolt的输出数据格式是:"viechleID", "dateTime", "occupied", "speed","bearing", "latitude", "longitude", "districtID"。

需要说明的是Sects类调用了开源的地理信息系统工具geotools,感兴趣的朋友可以去http://www.geotools.org/ 下载安装包,并将相关的jar包全部添加到Eclipse 的building path里面,就可以调用geotools查询本地的地理信息数据库了。


  1. package main.java.realODMatrix.bolt;

  2. import java.io.IOException;
  3. import java.util.List;
  4. import java.util.Map;


  5. import backtype.storm.task.OutputCollector;
  6. import backtype.storm.task.TopologyContext;
  7. import backtype.storm.topology.IRichBolt;
  8. import backtype.storm.topology.OutputFieldsDeclarer;
  9. import backtype.storm.tuple.Fields;
  10. import backtype.storm.tuple.Values;

  11. import backtype.storm.tuple.Tuple;
  12. import main.java.realODMatrix.spout.FieldListenerSpout;
  13. import main.java.realODMatrix.struct.*;

  14. public class DistrictMatchingBolt implements IRichBolt {

  15. private static final long serialVersionUID = -433427751113113358L;

  16. private OutputCollector _collector;

  17. Integer districtID ;
  18. GPSRcrd record;
  19. Map<GPSRcrd, Integer> gpsMatch; //map
  20. Integer taskID;
  21. String taskname;
  22. List<Object> inputLine;
  23. Fields matchBoltDeclare=null;

  24. static String path = "/home/ghchen/sects/sects.shp";
  25. static Sects sects=null ;
  26. int count=0;

  27. @Override
  28. public void prepare(Map stormConf, TopologyContext context,
  29. OutputCollector collector) {
  30. // TODO Auto-generated method stub
  31. this._collector=collector;
  32. this.taskID=context.getThisTaskId();
  33. this.taskname=context.getThisComponentId();

  34. }


  35. @Override
  36. public void execute(Tuple input) {

  37. try {
  38. if(sects==null){
  39. sects= new Sects(path);
  40. }

  41. List<</span>Object> inputLine = input.getValues();//getFields();
  42. Fields inputLineFields = input.getFields();

  43. record=new GPSRcrd(Double.parseDouble((String) inputLine.get(6)),
  44. Double.parseDouble((String) inputLine.get(5)), Integer.parseInt((String) inputLine.get(3)),
  45. Integer.parseInt((String) inputLine.get(4)));

  46. if( Double.parseDouble((String) inputLine.get(6)) > 114.5692938 ||
  47. Double.parseDouble((String) inputLine.get(6)) <</span> 113.740000 ||
  48. Double.parseDouble((String) inputLine.get(5)) > 22.839945 ||
  49. Double.parseDouble((String) inputLine.get(5)) <</span> 22.44
  50. ) return;


  51. districtID = sects.fetchSect(record);

  52. if(districtID!=-1)
  53. {
  54. System.out.println(count++ +": GPS Point falls into Sect No. :" + districtID);


  55. inputLine.add(Integer.toString(districtID));
  56. //input.getFields().toList().add("districtID");
  57. List<String> fieldList= input.getFields().toList();
  58. fieldList.add("districtID");
  59. matchBoltDeclare=new Fields(fieldList);
  60. //FieldListenerSpout.writeToFile("/home/ghchen/output","matchBoltDeclare="+matchBoltDeclare);


  61. String[] obToStrings=new String[inputLine.size()];
  62. obToStrings=inputLine.toArray(obToStrings);

  63. _collector.emit(new Values(obToStrings));
  64. //_collector.emit(new Values(inputLine));
  65. }

  66. } catch (Exception e) {

  67. e.printStackTrace();
  68. }

  69. _collector.ack(input);

  70. }


  71. @Override
  72. public void cleanup() {
  73. // TODO Auto-generated method stub

  74. System.out.println("-- District Mathchier ["+taskname+"-"+districtID+"] --");
  75. for(Map.Entry<</span>GPSRcrd, Integer> entry : gpsMatch.entrySet()){
  76. System.out.println(entry.getKey()+": "+entry.getValue());
  77. }

  78. }


  79. @Override
  80. public void declareOutputFields(OutputFieldsDeclarer declarer) {
  81. declarer.declare(new Fields ("viechleID", "dateTime", "occupied", "speed",
  82. "bearing", "latitude", "longitude", "districtID"));
  83. }


  84. @Override
  85. public Map<</span>String, Object> getComponentConfiguration() {
  86. // TODO Auto-generated method stub
  87. return null;
  88. }

  89. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值