Storm實例:提交大地算法Topology

大地算法簡介

  • 相關(guān)概念

地軸:即為地球斜軸愧杯,又稱地球自轉(zhuǎn)軸。是指地球自轉(zhuǎn)所繞的軸,北端與地表的交點是北極岔绸,南端與地表的交點是南極
赤道:地球表面的點隨地球自轉(zhuǎn)產(chǎn)生的軌跡中周長最長的圓周線尿背,赤道半徑6,378.137km端仰。
緯度:緯度是指某點與地球球心的連線和地球赤道面所成的線面角,其數(shù)值在0至90度之間田藐。位于赤道以北的點的緯度叫北緯荔烧,記為N,位于赤道以南的點的緯度稱南緯坞淮,記為S茴晋。
經(jīng)度:一般指球面坐標系的縱坐標,具體來說就是地球上一個地點離一根被稱為本初子午線的南北方向走線以東或以西的度數(shù)回窘。
本初子午線:即0度經(jīng)線诺擅,亦稱格林威治子午線或格林尼治子午線,是位于英國格林尼治天文臺的一條經(jīng)線(亦稱子午線)啡直。本初子午線的東西兩邊分別定為東經(jīng)和西經(jīng)烁涌,于180度相遇。

  • 大地算法:
    在實際應(yīng)用中酒觅,我們計算2個位置的距離撮执,通常做法就是獲取2個位置中心處的經(jīng)緯度,然后根據(jù)經(jīng)緯度計算它們之間地表弧線距離舷丹。計算地表弧線距離的方法即稱為大地算法抒钱。

  • 算法推導(dǎo)

大地算法

如圖所示,我們計算A點和B點之間的弧線距離颜凯,因此我們的目標要獲取OA谋币、OB之間的夾角,記為C症概。
設(shè)第一點A的經(jīng) 緯度為(jA, wA)蕾额,第二點B的經(jīng)緯度為(jB, wB),按照0度經(jīng)線的基準彼城,東經(jīng)取經(jīng)度的正值(Longitude)诅蝶,西經(jīng)取經(jīng)度負值(-Longitude)退个,北緯取90-緯度值(90- Latitude),南緯取90+緯度值(90+Latitude)调炬,則經(jīng)過上述處理過后的兩點被計為(MLonA, MLatA)和(MLonB, MLatB)语盈。那么根據(jù)三角推導(dǎo),可以得到計算兩點距離的如下公式:

C = sin(MLatA)*sin(MLatB)*cos(MLonA-MLonB) + cos(MLatA)*cos(MLatB)
Distance = R*Arccos(C)*Pi/180

如果僅對經(jīng)度作正負的處理筐眷,而不對緯度作90-Latitude(假設(shè)都是北半球黎烈,南半球只有澳洲具有應(yīng)用意義)的處理,那么公式將是:

C = sin(wA)*sin(wB) + cos(wA)*cos(wB)*cos(jA-jB)
Distance = R*Arccos(C)*Pi/180

針對這種情況匀谣,可以簡單演示下推導(dǎo)過程:

推導(dǎo)過程
  • Java實現(xiàn)
  public static double Distance(Location loc1, Location loc2) {
    double a, b, R;
    R = 6378137; // 地球半徑照棋,單位:米
    double lat1 = loc1.latitude;
    double long1 = loc1.longitude;
    double lat2 = loc2.latitude;
    double long2 = loc2.longitude;
    
    a = (lat1 - lat2) * Math.PI / 180.0;
    b = (long1 - long2) * Math.PI / 180.0;
    
    double d;
    double sa2, sb2;
    sa2 = Math.sin(a / 2.0);
    sb2 = Math.sin(b / 2.0);
    d = 2 * R * Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1) * Math.cos(lat2) * sb2 * sb2));
    
    return d;
}

Spout/Bolt編程

我們的目標是本地不斷的隨機生成一個坐標點,然后計算這個點到一個固定位置的距離武翎。

  • Location類
    首先烈炭,為了書寫方便,我們先創(chuàng)建一個Location的Class宝恶。
public class Location {
    public double longitude;
    public double latitude;
    
    public Location(double lon, double lat) {
        this.longitude = lon;
        this.latitude = lat;
    }
    
    public String locationInfo() {
        String info = "location:( " + longitude + "," + latitude + " ) ";
        return info;
    }
}
  • RandomLocationSpout類
    創(chuàng)建RandomLocationSpout類符隙,繼承BaseRichSpout,并重寫基類的基本方法垫毙。
public class RandomLocationSpout extends BaseRichSpout {

    SpoutOutputCollector spoutOutputCollector;

    @Override
    public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
        // TODO Auto-generated method stub
        spoutOutputCollector = collector;
    }

    @Override
    public void nextTuple() {
        // TODO Auto-generated method stub
        
        double lat = 39 + (Math.random()*2);
        double lon = 116 + Math.random();
        
        String loc = lon + "," + lat;
    
        spoutOutputCollector.emit(new Values(loc));
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        // TODO Auto-generated method stub
         declarer.declare(new Fields("spout"));
    }

}

nextTuple()方法中霹疫,我們隨機生成一個緯度在北緯39度-41度之間,經(jīng)度在東京116度-117度之間的一個坐標综芥,然后將該坐標發(fā)射出去丽蝎。

  • CalculateDistantBolt類
    創(chuàng)建CalculateDistantBolt類,并重寫IRichBolt接口的相關(guān)方法
public class CalculateDistantBolt implements IRichBolt {
    private OutputCollector outputCollector;
    
    public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
        // TODO Auto-generated method stub
        outputCollector = collector;
    }

    public void execute(Tuple input) {
        // TODO Auto-generated method stub
        String loc = input.getString(0);
        String[] s1 = loc.split(",");
        
        Location location = new Location(Double.parseDouble(s1[0]), Double.parseDouble(s1[1]));
        Location center = new Location(116.360664, 40.007614);
        
        double d = Distance(location, center);
        System.out.println("************\\n" +location.locationInfo() + "between" + center.locationInfo() + ":\\n" + "Distant: " + d +"\\n ***********");
    }

    public void cleanup() {
        // TODO Auto-generated method stub
        
    }

    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        // TODO Auto-generated method stub
        
    }

    public Map<String, Object> getComponentConfiguration() {
        // TODO Auto-generated method stub
        return null;
    }

    public static double Distance(Location loc1, Location loc2) {
        double a, b, R;
        R = 6378137; // 地球半徑
        double lat1 = loc1.latitude;
        double long1 = loc1.longitude;
        double lat2 = loc2.latitude;
        double long2 = loc2.longitude;

        a = (lat1 - lat2) * Math.PI / 180.0;
        b = (long1 - long2) * Math.PI / 180.0;
        
        double d;
        double sa2, sb2;
        sa2 = Math.sin(a / 2.0);
        sb2 = Math.sin(b / 2.0);
        d = 2 * R * Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1) * Math.cos(lat2) * sb2 * sb2));
        
        return d;
    }
}

execute(Tuple input)方法中膀藐,我們獲取Spout發(fā)射的坐標點屠阻,并計算該點到當前位置的地表距離(實例中center是我當前的位置)。** 打印輸出計算結(jié)果**额各。

  • DistantTopology類
    最后是創(chuàng)建啟動主類DistantTopology国觉,進行拓撲構(gòu)建。在main方法中設(shè)置好Spout和Bolt虾啦,然后Topology任務(wù)提交到Storm上麻诀。
public class DistantTopology {

    private static TopologyBuilder builder = new TopologyBuilder();
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
         Config config = new Config();

            builder.setSpout("RandomLocationSpout", new RandomLocationSpout(), 2);
            builder.setBolt("CalculateDistantBolt", new CalculateDistantBolt(), 2).shuffleGrouping(
                    "RandomLocationSpout");

            config.setDebug(true);

            //通過是否有參數(shù)來控制是否啟動集群,或者本地模式執(zhí)行
            if (args != null && args.length > 0) {
                try {
                    config.setNumWorkers(1);
                    StormSubmitter.submitTopology(args[0], config,
                            builder.createTopology());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                config.setMaxTaskParallelism(1);
                LocalCluster cluster = new LocalCluster();
                cluster.submitTopology("wordcount", config, builder.createTopology());
            }
    }

}

提交Topology任務(wù)

  • 使用mvn命令將工程打成jar包
  • 上傳jar包到集群的主機上
  • 主機上傲醉,終端執(zhí)行storm jar命令针饥,提交Topology任務(wù)
  • 提交成功后,在對應(yīng)節(jié)點上查看worker日志
1041937 [Thread-8-RandomLocationSpout] INFO  backtype.storm.daemon.task - Emitting: RandomLocationSpout default [116.61777982507657,39.25343303306309]
1041937 [Thread-14-CalculateDistantBolt] INFO  backtype.storm.daemon.executor - Processing received message source: RandomLocationSpout:2, stream: default, id: {}, [116.72828785729372,39.204690956457334]
************
location:( 116.72828785729372,39.204690956457334 ) betweenlocation:( 116.360664,40.007614 ) :
Distant: 88969.36622189148
 ***********
1041937 [Thread-8-RandomLocationSpout] INFO  backtype.storm.daemon.task - Emitting: RandomLocationSpout default [116.03394550808655,40.8784387953902]
1041937 [Thread-14-CalculateDistantBolt] INFO  backtype.storm.daemon.executor - Processing received message source: RandomLocationSpout:2, stream: default, id: {}, [116.87086610893954,40.505468257874966]
************
location:( 116.87086610893954,40.505468257874966 ) betweenlocation:( 116.360664,40.007614 ) :
Distant: 71556.36956545932
 ***********

日志中會不斷刷新計算距離需频,任務(wù)提交成功。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末筷凤,一起剝皮案震驚了整個濱河市昭殉,隨后出現(xiàn)的幾起案子苞七,更是在濱河造成了極大的恐慌,老刑警劉巖挪丢,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹂风,死亡現(xiàn)場離奇詭異,居然都是意外死亡乾蓬,警方通過查閱死者的電腦和手機惠啄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來任内,“玉大人撵渡,你說我怎么就攤上這事∷类拢” “怎么了趋距?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長越除。 經(jīng)常有香客問我节腐,道長迷守,這世上最難降的妖魔是什么絮爷? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮炊邦,結(jié)果婚禮上孩擂,老公的妹妹穿的比我還像新娘狼渊。我一直安慰自己,他們只是感情好肋殴,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布囤锉。 她就那樣靜靜地躺著,像睡著了一般护锤。 火紅的嫁衣襯著肌膚如雪官地。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天烙懦,我揣著相機與錄音驱入,去河邊找鬼。 笑死氯析,一個胖子當著我的面吹牛亏较,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播掩缓,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼雪情,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了你辣?” 一聲冷哼從身側(cè)響起巡通,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤尘执,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后宴凉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體誊锭,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年弥锄,在試婚紗的時候發(fā)現(xiàn)自己被綠了丧靡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡籽暇,死狀恐怖温治,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情图仓,我是刑警寧澤罐盔,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站救崔,受9級特大地震影響惶看,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜六孵,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一纬黎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧劫窒,春花似錦本今、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至孕索,卻和暖如春逛艰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搞旭。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工散怖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肄渗。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓镇眷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親翎嫡。 傳聞我的和親對象是個殘疾皇子欠动,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法惑申,內(nèi)部類的語法具伍,繼承相關(guān)的語法铆遭,異常的語法,線程的語...
    子非魚_t_閱讀 31,597評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理沿猜,服務(wù)發(fā)現(xiàn),斷路器碗脊,智...
    卡卡羅2017閱讀 134,628評論 18 139
  • 這些經(jīng)緯線是怎樣定出來的呢衙伶?地球是在不停地繞地軸旋轉(zhuǎn)(地軸是一根通過地球南北兩極和地球中心的假想線)祈坠,在地球中腰畫...
    Akitas閱讀 1,149評論 0 2
  • 是歲月的光 是陳舊的墨 是樹樁上一圈又一圈 或是蒼海桑田 亦或 ……
    滄海一粟貝閱讀 181評論 1 4
  • 1.添加圖片: 2.文字 3.按鈕 4.屏幕分布
    冰西瓜大郎閱讀 386評論 0 0