package au.gov.amsa.geo.adhoc; import java.io.File; import java.util.HashMap; import java.util.TreeMap; import java.util.concurrent.TimeUnit; import au.gov.amsa.ais.message.AisPosition; import au.gov.amsa.ais.rx.Streams; import au.gov.amsa.streams.Strings; import au.gov.amsa.util.Pair; import rx.Observable; public class SatelliteReportingIntervalsMain { /** * * Used this oracle query to get time diffs by mmsi for satellite reports * from cts.position. * * <pre> * select mmsi, timeMs from * ( * select mmsi, EXTRACT( DAY FROM diff ) * 24*60*60000 * + EXTRACT( HOUR FROM diff ) * 60*60000 * + EXTRACT( MINUTE FROM diff ) * 60000 * + EXTRACT( SECOND FROM diff ) * 1000 timeMs from * ( * select mmsi, position_time - to_timestamp('1970-01-01', 'yyyy-mm-dd') diff from cts.position * where position_time >= to_date('2015/06/28','yyyy/mm/dd') and position_time < to_date('2015/06/30','yyyy/mm/dd') * and (source_detail like 'AISSat%' or source_detail like 'NORAIS%' or source_detail like 'rEV%') * ) * ) order by mmsi, timeMs * </pre> * * @param args */ public static void main(String[] args) { Observable<Double> splits = Strings.from(new File("/home/dxm/times.txt")) // .compose(o -> Strings.split(o, "\n")) // .filter(line -> line.trim().length() > 0) // .map(line -> line.split("\t")) // // .doOnNext(items -> System.out.println(Arrays.asList(items))) // .map(items -> new Record(Long.parseLong(items[0]), Long.parseLong(items[1]) / ((double) TimeUnit.HOURS.toMillis(1)))) // .groupBy(record -> record.mmsi) // .flatMap(g -> g.buffer(2, 1) // .filter(list -> list.size() == 2) // time diff .map(list -> list.get(1).timeHrs - list.get(0).timeHrs)) // sort .toSortedList() // flatten .flatMap(list -> Observable.from(list)) // .cast(Double.class).cache(); splits.reduce(Pair.create(0, 0.0), (p1, x) -> Pair.<Integer, Double> create(p1.a() + 1, x + p1.b())) // .map(pair -> pair.b() / pair.a()) // .doOnNext(value -> System.out.println("average interval hours=" + value)) // .subscribe(); Observable<BucketCount> buckets = splits // .map(diff -> Math.floor(diff * 10) / 10.0) // collect into discrete interval buckets .collect(() -> new HashMap<Double, Integer>(), (map, x) -> { if (map.get(x) == null) map.put(x, 1); else map.put(x, map.get(x) + 1); }) // sort keys .map(map -> new TreeMap<Double, Integer>(map)) // flatten .flatMap(map -> Observable.from(map.entrySet())) // map to bucket .map(entry -> new BucketCount(entry.getKey(), entry.getValue())) // .scan(new BucketCount(0.0, 0), (b1, b2) -> new BucketCount(b2.bucket, b1.count + b2.count)) // cache .cache(); double max = buckets.last().map(b -> b.count).toBlocking().single(); buckets.doOnNext(b -> System.out.println(b.bucket + "\t" + b.count / max * 100)).count() .toBlocking().single(); System.exit(0); File file = new File("/home/dxm/2015-06-29.txt.gz"); Streams.nmeaFromGzip(file) // to AisMessage .compose(o -> Streams.extractMessages(o)) // filter on positions .filter(m -> m.message() instanceof AisPosition) // .filter(m -> isNorwaySatellite(m.message().getSource())) // group by mmsi .groupBy(m -> ((AisPosition) m.message()).getMmsi()) // calculate intervals .flatMap(g -> g.toSortedList()) // log .doOnNext(System.out::println) // count .count() // .toBlocking().single(); } private static class BucketCount { final double bucket; final int count; BucketCount(double bucket, int count) { super(); this.bucket = bucket; this.count = count; } } private static class Record { final long mmsi; final double timeHrs; Record(long mmsi, double timeHrs) { super(); this.mmsi = mmsi; this.timeHrs = timeHrs; } } private static boolean isSatellite(String source) { return source != null && (source.startsWith("rEV") || source.startsWith("AISSat") || source.startsWith("NORAIS")); } private static boolean isNorwaySatellite(String source) { return source != null && (source.startsWith("AISSat") || source.startsWith("NORAIS")); } private static boolean isExactEarthSatellite(String source) { return source != null && source.startsWith("rEV"); } }