// Get all events with exit at last location public static Map<Integer, VesselEvent> getAllEventsStartBeforeEndAfterBeforeLocation( Table VTEvent_Table, String IMO_str, VesselLocation location) throws IOException { Scan getAllEventsWithExistAtLastLocation = new Scan(); getAllEventsWithExistAtLastLocation .setStartRow( Bytes.toBytes( IMO_str + LpadNum(Long.MAX_VALUE - location.recordtime, 19) + "0000000000")) .setStopRow(Bytes.toBytes(IMO_str + LpadNum(Long.MAX_VALUE, 19) + "9999999999")) .addColumn(details, exittime); getAllEventsWithExistAtLastLocation.setCaching(100); Filter ExistTimeValuefilter = new ValueFilter( CompareFilter.CompareOp.GREATER_OR_EQUAL, new BinaryComparator( Bytes.toBytes(new DateTime(location.recordtime).toString(rawformatter)))); getAllEventsWithExistAtLastLocation.setFilter(ExistTimeValuefilter); ResultScanner Result_event = VTEvent_Table.getScanner(getAllEventsWithExistAtLastLocation); Map<Integer, VesselEvent> events = new HashMap<Integer, VesselEvent>(); for (Result res : Result_event) { Get get = new Get(res.getRow()); get.addColumn(details, entrytime); get.addColumn(details, entrycoordinates); Result result = VTEvent_Table.get(get); String rowkey = Bytes.toString(result.getRow()); String polygonid = rowkey.substring(26); VesselEvent VE = new VesselEvent(); VE.exittime = location.recordtime; VE.exitcoordinates = location.coordinates; VE.destination = location.destination; VE.polygonid = Integer.parseInt(polygonid); for (Cell cell : result.rawCells()) { String Qualifier = Bytes.toString(CellUtil.cloneQualifier(cell)); String Value = Bytes.toString(CellUtil.cloneValue(cell)); if (Qualifier.equals("entertime")) { VE.entrytime = DateTime.parse(Value, rawformatter).getMillis(); } else if (Qualifier.equals("entercoordinates")) { VE.entrycoordinates = Value; } } events.put(VE.polygonid, VE); } Result_event.close(); return events; }
@Override protected void reduce( Key_IMOAndRecordTime key, Iterable<TextArrayWritable> LocationList, Context context) throws IOException, InterruptedException { try { context.getCounter(Counters.VESSEL_PROCESSED).increment(1); String IMO_str = LpadNum(key.getIMO().get(), 7); long first_pos_time = key.getRecordTime().get(); ///////////////////////////////////////////////////////////////////////////////// // Populate newPoints with new locations List<VesselLocation> newPoints = new ArrayList<VesselLocation>(); for (TextArrayWritable rowcontent : LocationList) { // population location context.getCounter(Counters.LOCATION_ROWS).increment(1); VesselLocation newlocation = new VesselLocation(); try { Writable[] content = rowcontent.get(); String Latitude = content[16].toString().trim(); String Longitude = content[15].toString().trim(); String Coordinates = Latitude + "," + Longitude; String Speed = content[18].toString().trim(); String Destination = content[9].toString().trim(); String Timestamp = content[21].toString().trim().substring(0, 19); long record_time = DateTime.parse(Timestamp, rawformatter).getMillis(); newlocation.coordinates = Coordinates; newlocation.recordtime = record_time; newlocation.speed = Speed; newlocation.destination = Destination; context.getCounter(Counters.LOCATION_VALID).increment(1); } catch (Exception e) { e.printStackTrace(); context.getCounter(Counters.LOCATION_ERROR).increment(1); continue; } newPoints.add(newlocation); } ///////////////////////////////////////////////////////////////////////////////// // Get last new post time long last_pos_time = newPoints.get(newPoints.size() - 1).recordtime; //////////////////////////////////////////////////////////////////////////////// // Get Existing trackinfo VesselTrackInfo VTI = getTrackInfo(TrackInfo_Table, IMO_str); List<VesselLocation> AllBetweenPoints = new ArrayList<VesselLocation>(); String BeforeRowKey = null; String AfterRowKey = null; // ////////////////////////////////////////////////////////////////////////////// // Retrieve all the existing locations between the first new location and the last new // location. if ((VTI.FirstRecordTime != null) && (VTI.LastRecordTime != null)) { if (last_pos_time < VTI.FirstRecordTime) { AfterRowKey = IMO_str + LpadNum(Long.MAX_VALUE - VTI.FirstRecordTime, 19); } else if (first_pos_time > VTI.LastRecordTime) { BeforeRowKey = IMO_str + LpadNum(Long.MAX_VALUE - VTI.LastRecordTime, 19); } else { AllBetweenPoints = ImportReducer.getLocationsBetween( VTLocation_Table, IMO_str, first_pos_time, last_pos_time); if (AllBetweenPoints.size() == 0) { // Search for the first DB point before the first new point VesselLocation BeforeLocation = getLocationBefore(VTLocation_Table, IMO_str, first_pos_time); BeforeRowKey = IMO_str + LpadNum(Long.MAX_VALUE - BeforeLocation.recordtime, 19); AfterRowKey = BeforeLocation.nextlocation; } else { java.util.Collections.sort(AllBetweenPoints); BeforeRowKey = AllBetweenPoints.get(0).previouslocation; AfterRowKey = AllBetweenPoints.get(AllBetweenPoints.size() - 1).nextlocation; } List<Delete> deletes = ImportReducer.GetDeleteEventsBetween( VTEvent_Table, IMO_str, first_pos_time, last_pos_time); ImportReducer.DeleteEvents(VTEvent, deletes); VTEvent.flush(); } } // Find out the location before the first new location in VesselLocation BeforeLocation = getLocation(VTLocation_Table, BeforeRowKey); // Find out the location after the last new location in VesselLocation AfterLocation = getLocation(VTLocation_Table, AfterRowKey); Map<Integer, VesselEvent> PreviousZoneEvents = new HashMap<Integer, VesselEvent>(); ; Map<Integer, VesselEvent> AfterZoneEvents = new HashMap<Integer, VesselEvent>(); if (BeforeLocation != null) { // Get all events with exit at last location PreviousZoneEvents = getAllEventsStartBeforeEndAfterBeforeLocation(VTEvent_Table, IMO_str, BeforeLocation); } //////////////////////////////////////////////////// // Analyze and calculate previous and next location for (VesselLocation newlocation : newPoints) { int index = AllBetweenPoints.indexOf(newlocation); if (index != -1) { VesselLocation dblocation = AllBetweenPoints.get(index); dblocation.coordinates = newlocation.coordinates; dblocation.destination = newlocation.destination; dblocation.speed = newlocation.speed; } else { AllBetweenPoints.add(newlocation); } } java.util.Collections.sort(AllBetweenPoints); String previousRowKey = null; for (VesselLocation location : AllBetweenPoints) { location.previouslocation = previousRowKey; previousRowKey = IMO_str + LpadNum(Long.MAX_VALUE - location.recordtime, 19); } String NextRowKey = null; for (int i = (AllBetweenPoints.size() - 1); i >= 0; i--) { VesselLocation location = AllBetweenPoints.get(i); location.nextlocation = NextRowKey; NextRowKey = IMO_str + LpadNum(Long.MAX_VALUE - location.recordtime, 19); } AllBetweenPoints.get(0).previouslocation = BeforeRowKey; AllBetweenPoints.get(AllBetweenPoints.size() - 1).nextlocation = AfterRowKey; //////////////////////////////////////////////////// // Upsert all locations for (VesselLocation location : AllBetweenPoints) { // population location try { byte[] rowkey = Bytes.toBytes(IMO_str + LpadNum(Long.MAX_VALUE - location.recordtime, 19)); Put put = new Put(rowkey); put.addColumn(details, speed, Bytes.toBytes(location.speed)); put.addColumn(details, destination, Bytes.toBytes(location.destination)); put.addColumn(details, coordinates, Bytes.toBytes(location.coordinates)); put.addColumn( details, timestamp, Bytes.toBytes(new DateTime(location.recordtime).toString(rawformatter))); if (location.previouslocation != null) { put.addColumn(details, previouslocation, Bytes.toBytes(location.previouslocation)); } if (location.nextlocation != null) { put.addColumn(details, nextlocation, Bytes.toBytes(location.nextlocation)); } VTLocation.mutate(put); } catch (Exception e) { e.printStackTrace(); context.getCounter(Counters.LOCATION_ERROR).increment(1); continue; } } // update before next location and after previous location if (BeforeRowKey != null) { Put BeforeLocationPut = new Put(Bytes.toBytes(BeforeRowKey)); BeforeLocationPut.addColumn( details, nextlocation, Bytes.toBytes( IMO_str + LpadNum(Long.MAX_VALUE - AllBetweenPoints.get(0).recordtime, 19))); VTLocation.mutate(BeforeLocationPut); } if (AfterRowKey != null) { Put AfterLocationPut = new Put(Bytes.toBytes(AfterRowKey)); AfterLocationPut.addColumn( details, previouslocation, Bytes.toBytes( IMO_str + LpadNum( Long.MAX_VALUE - AllBetweenPoints.get(AllBetweenPoints.size() - 1).recordtime, 19))); VTLocation.mutate(AfterLocationPut); } VTLocation.flush(); ///////////////////////////////////////////////////////////////////// // Store latest location // rowkey: global zone id (4)+ longlat22 // ((long11(sign(1)+integer(3)+digit(7)))(lat11(sign(1)+integer(3)+(7))))+imo(7)+recordtime(19) ///////////////////////////////////////////////////////////////////// Put vessel_track_info = new Put(Bytes.toBytes(IMO_str)); if (AfterLocation == null) { // Get the last location VesselLocation lastLocation = AllBetweenPoints.get(AllBetweenPoints.size() - 1); // update the last location String[] longlat = lastLocation.coordinates.split(","); GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null); Coordinate coord = new Coordinate(Double.parseDouble(longlat[1]), Double.parseDouble(longlat[0])); Point point = geometryFactory.createPoint(coord); Integer BelongedGlobalZoneIndex = null; for (int i = 0; i < VesselZone.GlobalZones.length; i++) { if (VesselZone.GlobalZones[i].covers(point)) { BelongedGlobalZoneIndex = i; break; } } if (VTI.LastLocation != null) { LastLocation_BM.mutate(new Delete(VTI.LastLocation)); } byte[] lastlocationrowkey = Bytes.toBytes( LpadNum(BelongedGlobalZoneIndex, 4) + ConvertCoordinatesToStr(longlat[1]) + ConvertCoordinatesToStr(longlat[0])); Put lastlocation_put = new Put(lastlocationrowkey); lastlocation_put.addColumn(details, imo, Bytes.toBytes(IMO_str)); lastlocation_put.addColumn( details, timestamp, Bytes.toBytes(new DateTime(lastLocation.recordtime).toString(rawformatter))); LastLocation_BM.mutate(lastlocation_put); LastLocation_BM.flush(); vessel_track_info.addColumn(details, lastlocation, lastlocationrowkey); vessel_track_info.addColumn( details, lastrecordtime, Bytes.toBytes(new DateTime(lastLocation.recordtime).toString(rawformatter))); } else { // Get events that start before last new location and end after last new location AfterZoneEvents = getAllEventsStartBeforeEndAfter(VTEvent_Table, IMO_str, AfterLocation.recordtime); } // update firstrecordtime and lastrecordtime if (BeforeLocation == null) { vessel_track_info.addColumn( details, firstrecordtime, Bytes.toBytes( new DateTime(AllBetweenPoints.get(0).recordtime).toString(rawformatter))); } if (!vessel_track_info.isEmpty()) { TrackInfo_BM.mutate(vessel_track_info); TrackInfo_BM.flush(); } //////////////////////////////////////////////////////////////////// ArrayList<VesselEvent> DerivedEventList = new ArrayList<VesselEvent>(); /////////////////////////////////////////////////////////// // Get Vessel String VesselType = getVesselType(Vessel_Table, IMO_str); if (VesselType == null) { context.getCounter(Counters.VESSEL_WITHOUTTYPE).increment(1); return; } // calculating event for (VesselLocation VL : AllBetweenPoints) { ArrayList<Integer> CurrentZones = LocateCurrentZone(VL.coordinates, VesselType, Zonemap); Iterator<Map.Entry<Integer, VesselEvent>> it = PreviousZoneEvents.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Integer, VesselEvent> thisEntry = it.next(); int Zone_Axsmarine_id = thisEntry.getKey(); if (!CurrentZones.contains(Zone_Axsmarine_id)) { VesselEvent PreviousEvent = thisEntry.getValue(); if (!DerivedEventList.contains(PreviousEvent)) { DerivedEventList.add(PreviousEvent); } // remove close event from PreviousZoneEvents; it.remove(); } } for (Integer thisZone_Axsmarine_id : CurrentZones) { if (PreviousZoneEvents.containsKey(thisZone_Axsmarine_id)) { ////////////////////////////////////////////////// // For current zones which both previous and current locations belong to, update exit // point of previous open events with current locations. ////////////////////////////////////////////////// VesselEvent PreviousEvent = PreviousZoneEvents.get(thisZone_Axsmarine_id); PreviousEvent.exitcoordinates = VL.coordinates; PreviousEvent.exittime = VL.recordtime; PreviousEvent.destination = VL.destination; if (!DerivedEventList.contains(PreviousEvent)) { DerivedEventList.add(PreviousEvent); } } else { ////////////////////////////////////////////////// // For current zones which only current locations belong to, fire new open events ////////////////////////////////////////////////// VesselEvent NewEvent = new VesselEvent(); NewEvent.entrycoordinates = VL.coordinates; NewEvent.entrytime = VL.recordtime; NewEvent.exitcoordinates = VL.coordinates; NewEvent.exittime = VL.recordtime; NewEvent.destination = VL.destination; NewEvent.polygonid = thisZone_Axsmarine_id; PreviousZoneEvents.put(thisZone_Axsmarine_id, NewEvent); DerivedEventList.add(NewEvent); } } } /////////////////////////////////////////////////////////////////////////////////////// // Merge with PreviousZoneEvents with AfterZoneEvents Iterator<Map.Entry<Integer, VesselEvent>> it = AfterZoneEvents.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Integer, VesselEvent> thisEntry = it.next(); int Zone_Axsmarine_id = thisEntry.getKey(); VesselEvent After_VE = thisEntry.getValue(); VesselEvent Previous_VE = PreviousZoneEvents.get(Zone_Axsmarine_id); if (Previous_VE != null) { Previous_VE.exitcoordinates = After_VE.exitcoordinates; Previous_VE.exittime = After_VE.exittime; Previous_VE.destination = After_VE.destination; if (!DerivedEventList.contains(Previous_VE)) { DerivedEventList.add(Previous_VE); } } else { VesselEvent NewEvent = new VesselEvent(); NewEvent.entrycoordinates = AfterLocation.coordinates; NewEvent.entrytime = AfterLocation.recordtime; NewEvent.exitcoordinates = After_VE.exitcoordinates; NewEvent.exittime = After_VE.exittime; NewEvent.destination = After_VE.destination; NewEvent.polygonid = Zone_Axsmarine_id; DerivedEventList.add(NewEvent); } // Delete This Event from HBase DeleteEvent(VTEvent, IMO_str, After_VE); } VTEvent.flush(); // pupulate Derived Events into Hbase for (VesselEvent newEvent : DerivedEventList) { // rowkey: IMO(7)+timestamp(19 desc)+polygonid(8) // qualifier:entrytime,entrycoordinates,exittime,exitcoordinates,destination context.getCounter(Counters.EVENT_UPSERTS).increment(1); byte[] rowkey = Bytes.toBytes( IMO_str + LpadNum(Long.MAX_VALUE - newEvent.entrytime, 19) + LpadNum(newEvent.polygonid, 10)); Put put = new Put(rowkey); put.addColumn( details, entrytime, Bytes.toBytes(new DateTime(newEvent.entrytime).toString(rawformatter))); put.addColumn(details, entrycoordinates, Bytes.toBytes(newEvent.entrycoordinates)); put.addColumn( details, exittime, Bytes.toBytes(new DateTime(newEvent.exittime).toString(rawformatter))); put.addColumn(details, exitcoordinates, Bytes.toBytes(newEvent.exitcoordinates)); put.addColumn(details, destination, Bytes.toBytes(newEvent.destination)); VTEvent.mutate(put); context.getCounter(Counters.EVENT_VALID).increment(1); } // VTLocation.flush(); Moved to the first step VTEvent.flush(); } catch (RuntimeException e) { // TODO Auto-generated catch block System.out.println("Exception occured while loading data for:" + key.getIMO()); throw e; } }