[置顶] SpatialHadoop中空间索引系列之(十)R-Tree 索引源码解析

       前面章节已经大概描述了在SpatialHadoop中R-Tree空间索引实现的步骤,本章节就从源码角度来看下该算法是怎么实现的。

================================================================

第一步:Sampler类

       在这个类中主要实现了对输入数据集的一个随机抽样,控制抽样的有两个参数,一个抽样的大小,第二个是抽样的个数。大小由内存计算决定,小于100MB,个数由输入要素集的总个数决定,为0.1%的比率。

 public void map(Rectangle cell, Text line,
        OutputCollector<IntWritable, Text> output, Reporter reporter)
            throws IOException { 
      if (random.nextFloat() < sampleRatio) { 
        switch (conversion) {
        case None:
          output.collect(key, line);
          break;
        case ShapeToPoint:
          inShape.fromText(line);
          Rectangle mbr = inShape.getMBR();
          if (mbr != null) {
            Point center = mbr.getCenterPoint(); 
            line.clear();
            center.toText(line);
            output.collect(key, line); 
          }
          break;
        case ShapeToRect:
          inShape.fromText(line);
          mbr = inShape.getMBR();
          if (mbr != null) {
            line.clear();
            mbr.toText(line);
            output.collect(key, line);
          }
          break;
        }
      } 
      以上代码是抽样过程中的Map函数。其中random是随机生成的一个介于0.0-1之间的float,与sampleratio进行对比,这里默认是0.0099******,这样每一个map到的要素被执行的概率约为0.1%。由于是面要素,所以这里取其中心点。

第二步:Partition类

       在这个类中开始计算分割的方法。这里用到了STR算法。这里用STR算法用了两次,第一次是对采样点X进行排序。排完之后计算分割的行和列以及分割线。如何计算呢?上代码。

 partitioner.createFromPoints(inMBR, sample.toArray(new Point[sample.size()]), partitionCapacity);
------------------------------------------------------------------

       这里我们知道了整个数据集的面积,知道了要分多少行,要分多少列,还有一堆抽样点。那么如何将所有抽样点进行划分呢?

       我们先看X方向(经度),这里X代表着列。

       第一列,当column=0的时候,我们只用计算第一列的右边的X分隔线,因为左边就是输入要素集的边界啦。

     int col_quantile = (column + 1) * points.length / columns;      
     this.xSplits[column] = col_quantile == points.length ? mbr.x2 : points[col_quantile-1].x;
       第一行是计算第一列的点编号,这里就是平均,比如我有100个点,分了10列,那么第一个点就取X排序的第十个点作为分隔线就可以了;第二行开始计算第一列的右分隔线。这里只是做了一个判断,判断你要计算的点是否在范围内,如果在,那就取当前的点,如果不在就取要素集的最右边界线就可以了。

       这样就取完了第一列。下面开始取这一列的所有行。同上开始循环啦。

       也要对Y进行一次排序。排完之后,开始取Y的分隔线。

      // Compute y-splits for this column
      for (int row = 0; row < rows; row++) {
        int row_quantile = (prev_quantile * (rows - (row+1)) +
            col_quantile * (row+1)) / rows;
        // Determine y split for this row. Last row has a special handling
        this.ySplits[column * rows + row] = row_quantile == col_quantile ? mbr.y2 : points[row_quantile].y;
      }
       最终我们得到了如何划分整个区域的规则,即要划分多少行,多少列,以及从哪里开始划分。

第三步:物理切分数据

       取到当前要素之后,判断它与块边界的关系,来划分所有的要素。

 while (reader.nextKeyValue()) {
        Iterable<Shape> shapes = reader.getCurrentValue();
        if (replicate) {
          for (final Shape s : shapes) {
            partitioner.overlapPartitions(s, new ResultCollector<Integer>() {
              @Override
              public void collect(Integer id) {
                partitionID.set(id);
                try {
                  recordWriter.write(partitionID, s);
                } catch (IOException e) {
                  throw new RuntimeException(e);
                }
              }
            });
          }
        } else {
          for (final Shape s : shapes) {
            int pid = partitioner.overlapPartition(s);
            if (pid != -1) {
              partitionID.set(pid);
              recordWriter.write(partitionID, s);
            }
          }
        }

第四步:生成索引文件。

[置顶] SpatialHadoop中空间索引系列之(十)R-Tree 索引源码解析_第1张图片

GeoHadoop

你可能感兴趣的:(源码,索引,Gis,SpatialHadoop,R-tree,GeoHadoop)