zoukankan      html  css  js  c++  java
  • Hama——BSP、Graph教程

    1. BSP

    Hama提供纯BSP模型,支持消息传递与全局通信。BSP模型由一系列超步组成,每一个超步包括3个部分:

      1)本地计算

      2)进程通信

      3)障栅同步

    针对大量的科学计算问题,使用BSP模型可以编写高性能的并行计算算法。

    通过继承 org.apache.hama.bsp.BSP 类,创建自己的BSP类。

    继承类必须实现如下方法:

      public abstract void bsp(BSPPeer<K1, V1, K2, V2, M extends Writable> peer) throws IOException, SyncException, InterruptedException{}
    

    每一个BSP程序有一些系列的超步组成,但是BSP方法只被调用一次,这一点与MapReduce有所不同。在计算的前后,可以选择实现setup()和cleanup()方法,对每次计算的数据作进一步处理。建议在计算结束或计算失败时执行cleanup()。

    配置job:

      HamaConfiguration conf = new HamaConfiguration();
      BSPJob job = new BSPJob(conf, MyBSP.class);
      job.setJobName("My BSP program");
      job.setBspClass(MyBSP.class);
      job.setInputFormat(NullInputFormat.class);
      job.setOutputKeyClass(Text.class);
      ...
      job.waitForCompletion(true);
    

    用户接口  

    输入输出

    对BSPJob进行设置时,输入输出路径形式如下:

     job.setInputPath(new Path("/tmp/sequence.dat");
      job.setInputFormat(org.apache.hama.bsp.SequenceFileInputFormat.class);
      or,
      SequenceFileInputFormat.addInputPath(job, new Path("/tmp/sequence.dat"));
      or,
      SequenceFileInputFormat.addInputPaths(job, "/tmp/seq1.dat,/tmp/seq2.dat,/tmp/seq3.dat");
      
      job.setOutputKeyClass(Text.class);
      job.setOutputValueClass(IntWritable.class);
      job.setOutputFormat(TextOutputFormat.class);
      FileOutputFormat.setOutputPath(job, new Path("/tmp/result"));
      
    

    以上三种方式可以任选一种作为输入代码。

    然后,是对输入的数据的读取和输出数据。BSP创建一个方法,以BSPPeer作为参数。BSPPeer包含了通信、计数器和IO接口。读取一个文件,代码如下:

    @Override
      public final void bsp(
          BSPPeer<LongWritable, Text, Text, LongWritable, Text> peer)
          throws IOException, InterruptedException, SyncException {
          
          // this method reads the next key value record from file
          KeyValuePair<LongWritable, Text> pair = peer.readNext();
    
          // the following lines do the same:
          LongWritable key = new LongWritable();
          Text value = new Text();
          peer.readNext(key, value);
          
          // write
          peer.write(value, key);
      }
    

    可以对输入文件进行重复读取:

    for(int i = 0; i < 5; i++){
        LongWritable key = new LongWritable();
        Text value = new Text();
        while (peer.readNext(key, value)) {
           // read everything
        }
        // reopens the input
        peer.reopenInput() //***************
      }
    

    通信:  

     

     方法 描述 
     send(String peerName, BSPMessage msg)  向另外一个peer发送消息
     getCurrentMessage()  返回接收到的消息
     getNumCurrentMessages()  返回接收到的消息数
     sync()  障栅同步
     getPeerName()  返回peer的名称
     getAllPeerNames()  返回所有peer的名称
     getSuperstepCount()  返回超步数

      以上方法都比较灵活,下面是一个向所有peer传递消息的代码:

      @Override
      public void bsp(
          BSPPeer<NullWritable, NullWritable, Text, DoubleWritable, Text> peer)
          throws IOException, SyncException, InterruptedException {
        for (String peerName : peer.getAllPeerNames()) {
          peer.send(peerName, 
            new Text("Hello from " + peer.getPeerName(), System.currentTimeMillis()));
        }
    
        peer.sync();
      }
    

    同步:

    当所有的进程都进入同步状态,接下来将就进入下一个超步。需要注意的是,sync()方法并不是BSP Job的结束。如前所述,所有的通信方法都非常的灵活。例如,可以在一个for循环中执行sync(),这样就可以对迭代顺序进行控制。

     @Override
      public void bsp(
          BSPPeer<NullWritable, NullWritable, Text, DoubleWritable, Text> peer)
          throws IOException, SyncException, InterruptedException {
        for (int i = 0; i < 100; i++) {
          // send some messages
          peer.sync();
        }
      }
    

    最后,给出一个求取PI值的完整例子:

      private static Path TMP_OUTPUT = new Path("/tmp/pi-" + System.currentTimeMillis());
    
      public static class MyEstimator extends
          BSP<NullWritable, NullWritable, Text, DoubleWritable, DoubleWritable> {
        public static final Log LOG = LogFactory.getLog(MyEstimator.class);
        private String masterTask;
        private static final int iterations = 10000;
    
        @Override
        public void bsp(
            BSPPeer<NullWritable, NullWritable, Text, DoubleWritable, DoubleWritable> peer)
            throws IOException, SyncException, InterruptedException {
    
          int in = 0;
          for (int i = 0; i < iterations; i++) {
            double x = 2.0 * Math.random() - 1.0, y = 2.0 * Math.random() - 1.0;
            if ((Math.sqrt(x * x + y * y) < 1.0)) {
              in++;
            }
          }
    
          double data = 4.0 * in / iterations;
    
          peer.send(masterTask, new DoubleWritable(data));
          peer.sync();
        }
    
        @Override
        public void setup(
            BSPPeer<NullWritable, NullWritable, Text, DoubleWritable, DoubleWritable> peer)
            throws IOException {
          // Choose one as a master
          this.masterTask = peer.getPeerName(peer.getNumPeers() / 2);
        }
    
        @Override
        public void cleanup(
            BSPPeer<NullWritable, NullWritable, Text, DoubleWritable, DoubleWritable> peer)
            throws IOException {
          if (peer.getPeerName().equals(masterTask)) {
            double pi = 0.0;
            int numPeers = peer.getNumCurrentMessages();
            DoubleWritable received;
            while ((received = peer.getCurrentMessage()) != null) {
              pi += received.get();
            }
    
            pi = pi / numPeers;
            peer.write(new Text("Estimated value of PI is"), new DoubleWritable(pi));
          }
        }
      }
    
      static void printOutput(HamaConfiguration conf) throws IOException {
        FileSystem fs = FileSystem.get(conf);
        FileStatus[] files = fs.listStatus(TMP_OUTPUT);
        for (int i = 0; i < files.length; i++) {
          if (files[i].getLen() > 0) {
            FSDataInputStream in = fs.open(files[i].getPath());
            IOUtils.copyBytes(in, System.out, conf, false);
            in.close();
            break;
          }
        }
    
        fs.delete(TMP_OUTPUT, true);
      }
    
      public static void main(String[] args) throws InterruptedException,
          IOException, ClassNotFoundException {
        // BSP job configuration
        HamaConfiguration conf = new HamaConfiguration();
    
        BSPJob bsp = new BSPJob(conf, PiEstimator.class);
        // Set the job name
        bsp.setJobName("Pi Estimation Example");
        bsp.setBspClass(MyEstimator.class);
        bsp.setInputFormat(NullInputFormat.class);
        bsp.setOutputKeyClass(Text.class);
        bsp.setOutputValueClass(DoubleWritable.class);
        bsp.setOutputFormat(TextOutputFormat.class);
        FileOutputFormat.setOutputPath(bsp, TMP_OUTPUT);
    
        BSPJobClient jobClient = new BSPJobClient(conf);
        ClusterStatus cluster = jobClient.getClusterStatus(true);
    
        if (args.length > 0) {
          bsp.setNumBspTask(Integer.parseInt(args[0]));
        } else {
          // Set to maximum
          bsp.setNumBspTask(cluster.getMaxTasks());
        }
    
        long startTime = System.currentTimeMillis();
        if (bsp.waitForCompletion(true)) {
          printOutput(conf);
          System.out.println("Job Finished in "
              + (System.currentTimeMillis() - startTime) / 1000.0 + " seconds");
        }
      }
    

    2. Graph

    hama提供了Graph包,支持顶点为中心的图计算,使用较少的代码就可以实现google Pregel风格的应用。

    Vertex API

    实现一个Hama Graph应用包括对预定义的Vertex类进行子类化,模板参数涉及3种类型,顶点、边和消息(vertices, edges, and messages):

    public abstract class Vertex<V extends Writable, E extends Writable, M extends Writable>
          implements VertexInterface<V, E, M> {
    
        public void compute(Iterator<M> messages) throws IOException;
        ..
    
      }
    

    用户重写compute()方法,该方法将在每个超步的活跃顶点中执行。Compute()方法可以查询当前顶点及其边的信息,并向其他顶点发送消息。

    VertexReader API

    通过继承 org.apache.hama.graph.VertexInputReader 类,根据自己的文件格式创建自己的 VertexReader,示例如下:

      public static class PagerankTextReader extends
          VertexInputReader<LongWritable, Text, Text, NullWritable, DoubleWritable> {
    
        /**
         * 输入文件的格式
         * The text file essentially should look like: <br/>
         * VERTEX_ID\t(n-tab separated VERTEX_IDs)<br/>
         * E.G:<br/>
         * 1\t2\t3\t4<br/>
         * 2\t3\t1<br/>
         * etc.
         */
        @Override
      /***
       * 解析节点,如hadoop类似,以行为一个单位进行输入。以制表符作为分割符,
       * 将每一行分割为String类型的数组,最后转化为vertex类的一个实例
       */
        public boolean parseVertex(LongWritable key, Text value,
            Vertex<Text, NullWritable, DoubleWritable> vertex) throws Exception {
          String[] split = value.toString().split("\t");
          for (int i = 0; i < split.length; i++) {
            if (i == 0) {
              vertex.setVertexID(new Text(split[i]));
            } else {
              vertex
                  .addEdge(new Edge<Text, NullWritable>(new Text(split[i]), null));
            }
          }
          return true;
        }
    
      }
    

    PageRank的例子,很简单,不解释了:

    public static class PageRankVertex extends
          Vertex<Text, NullWritable, DoubleWritable> {
    
        @Override
        public void compute(Iterator<DoubleWritable> messages) throws IOException {
          if (this.getSuperstepCount() == 0) {
            this.setValue(new DoubleWritable(1.0 / (double) this.getNumVertices()));
          }
    
          if (this.getSuperstepCount() >= 1) {
            double sum = 0;
            while (messages.hasNext()) {
              DoubleWritable msg = messages.next();
              sum += msg.get();
            }
    
            double ALPHA = (1 - 0.85) / (double) this.getNumVertices();
            this.setValue(new DoubleWritable(ALPHA + (0.85 * sum)));
          }
    
          if (this.getSuperstepCount() < this.getMaxIteration()) {
            int numEdges = this.getOutEdges().size();
            sendMessageToNeighbors(new DoubleWritable(this.getValue().get()
                / numEdges));
          }
        }
      }
    

      

      

      

    参考资料:

    1、http://hama.apache.org/hama_bsp_tutorial.html

    2、http://hama.apache.org/hama_graph_tutorial.html

    转载请保留:http://www.cnblogs.com/Deron/archive/2013/06/09/3128135.html

      

      

  • 相关阅读:
    【Android 工具类】经常使用工具类(方法)大全
    driver: Linux设备模型之input子系统具体解释
    ural 1057 Amount of degrees 【数位dp】
    Java8 Lambda表达式教程
    Java线程池
    NodeJS实战——创建基础应用并应用模板引擎
    【网络】代理服务器
    【HTTP】Wireshark过滤规则
    【HTTP】WireShark中获取Content-Encoding: gzip时的响应内容
    【python】判断字符串日期是否有效
  • 原文地址:https://www.cnblogs.com/Deron/p/3128135.html
Copyright © 2011-2022 走看看