簡體   English   中英

如何確定Apache Spark中的偏移量?

[英]How do I determine an offset in Apache Spark?

我正在搜索一些數據文件(約20GB)。 我想在該數據中找到一些特定的術語,並為匹配項標記偏移量。 有沒有辦法讓Spark識別我正在處理的數據塊的偏移量?

import org.apache.spark.api.java.*;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.function.Function;

import java.util.regex.*;

public class Grep {
        public static void main( String args[] ) {
            SparkConf        conf       = new SparkConf().setMaster( "spark://ourip:7077" );
            JavaSparkContext jsc        = new JavaSparkContext( conf );
            JavaRDD<String>  data       = jsc.textFile( "hdfs://ourip/test/testdata.txt" ); // load the data from HDFS
            JavaRDD<String>  filterData = data.filter( new Function<String, Boolean>() {
                    // I'd like to do something here to get the offset in the original file of the string "babe ruth"
                    public Boolean call( String s ) { return s.toLowerCase().contains( "babe ruth" ); } // case insens matching

            });

            long matches = filterData.count();  // count the hits

            // execute the RDD filter
            System.out.println( "Lines with search terms: " + matches );
 );
        } //  end main
} // end class Grep

我想在“過濾器”操作中執行一些操作,以計算原始文件中“嬰兒露絲”的偏移量。 我可以在當前行中獲取“ baby ruth”的偏移量,但是告訴我文件中該行的偏移量的過程或函數是什么?

在Spark中,可以使用通用的Hadoop輸入格式 要從文件讀取字節偏移,可以使用Hadoop中的TextInputFormat類( org.apache.hadoop.mapreduce.lib.input )。 它已經與Spark捆綁在一起。

它將讀取文件作為 (字節偏移)和 (文本行):

純文本文件的InputFormat。 文件分為幾行。 換行或回車均用於表示行結束。 鍵是文件中的位置,值是文本行。

在Spark中,可以通過調用newAPIHadoopFile()來使用它

SparkConf conf = new SparkConf().setMaster("");
JavaSparkContext jsc = new JavaSparkContext(conf);

// read the content of the file using Hadoop format
JavaPairRDD<LongWritable, Text> data = jsc.newAPIHadoopFile(
        "file_path", // input path
        TextInputFormat.class, // used input format class
        LongWritable.class, // class of the value
        Text.class, // class of the value
        new Configuration());    

JavaRDD<String> mapped = data.map(new Function<Tuple2<LongWritable, Text>, String>() {
    @Override
    public String call(Tuple2<LongWritable, Text> tuple) throws Exception {
        // you will get each line from as a tuple (offset, text)    
        long pos = tuple._1().get(); // extract offset
        String line = tuple._2().toString(); // extract text

        return pos + " " + line;
    }
});

你可以使用wholeTextFiles(String path, int minPartitions)方法從JavaSparkContext返回一個JavaPairRDD<String,String>其中鍵是文件名和值是包含一個文件(因此的整個內容的字符串,在該RDD每個記錄代表一個文件)。 從這里,只需運行一個map() ,它將對每個值調用indexOf(String searchString) 這應該返回每個文件中的第一個索引,並包含出現問題的字符串。

(編輯:)

因此,可以以分布式方式為一個文件找到偏移量(根據注釋,在下面的用例中)。 下面是在Scala中工作的示例。

val searchString = *search string*
val rdd1 = sc.textFile(*input file*, *num partitions*)

// Zip RDD lines with their indices
val zrdd1 = rdd1.zipWithIndex()

// Find the first RDD line that contains the string in question
val firstFind = zrdd1.filter { case (line, index) => line.contains(searchString) }.first()

// Grab all lines before the line containing the search string and sum up all of their lengths (and then add the inline offset)
val filterLines = zrdd1.filter { case (line, index) => index < firstFind._2 }
val offset = filterLines.map { case (line, index) => line.length }.reduce(_ + _) + firstFind._1.indexOf(searchString)

請注意,您還需要在此之上手動添加任何新行字符,因為它們沒有被考慮(輸入格式使用新行作為記錄之間的分界)。 新行數只是包含搜索字符串的行之前的行數,因此添加起來很簡單。

不幸的是,我並不完全熟悉Java API,並且測試起來也不容易,因此我不確定下面的代碼是否有效,但是可以使用(此外,我使用了Java 1.7,但1.8使用lambda壓縮了很多代碼表達式。):

String searchString = *search string*;
JavaRDD<String> data = jsc.textFile("hdfs://ourip/test/testdata.txt");

JavaRDD<Tuple2<String, Long>> zrdd1 = data.zipWithIndex();

Tuple2<String, Long> firstFind = zrdd1.filter(new Function<Tuple2<String, Long>, Boolean>() {
      public Boolean call(Tuple2<String, Long> input) { return input.productElement(0).contains(searchString); }
  }).first();

JavaRDD<Tuple2<String, Long>> filterLines = zrdd1.filter(new Function<Tuple2<String, Long>, Boolean>() {
      public Boolean call(Tuple2<String, Long> input) { return input.productElement(1) < firstFind.productElement(1); }
  });

Long offset = filterLines.map(new Function<Tuple2<String, Long>, Int>() {
      public Int call(Tuple2<String, Long> input) { return input.productElement(0).length(); }
  }).reduce(new Function2<Integer, Integer, Integer>() {
      public Integer call(Integer a, Integer b) { return a + b; }
  }) + firstFind.productElement(0).indexOf(searchString);

僅當您的輸入是一個文件時才可以執行此操作(否則, zipWithIndex()不能保證文件中的偏移量),但是此方法適用於任意數量的分區的RDD,因此可以將文件任意分區為任意數量大塊。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM