Author: martinkl
Date: Sat Apr 13 04:30:13 2013
New Revision: 1467543

URL: http://svn.apache.org/r1467543
Log:
AVRO-1266. Java: Fix mapred.AvroMultipleOutputs to support multiple different 
schemas.  Contributed by Ashish Nagavaram.

Modified:
    avro/trunk/CHANGES.txt
    
avro/trunk/lang/java/mapred/src/main/java/org/apache/avro/mapred/AvroMultipleOutputs.java
    
avro/trunk/lang/java/mapred/src/test/java/org/apache/avro/mapred/TestAvroMultipleOutputs.java

Modified: avro/trunk/CHANGES.txt
URL: 
http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1467543&r1=1467542&r2=1467543&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Sat Apr 13 04:30:13 2013
@@ -24,6 +24,9 @@ Trunk (not yet released)
 
   BUG FIXES
 
+    AVRO-1266. Java: Fix mapred.AvroMultipleOutputs to support multiple
+    different schemas.  (Ashish Nagavaram via martinkl)
+
 Avro 1.7.4 (22 February 2012)
 
   NEW FEATURES

Modified: 
avro/trunk/lang/java/mapred/src/main/java/org/apache/avro/mapred/AvroMultipleOutputs.java
URL: 
http://svn.apache.org/viewvc/avro/trunk/lang/java/mapred/src/main/java/org/apache/avro/mapred/AvroMultipleOutputs.java?rev=1467543&r1=1467542&r2=1467543&view=diff
==============================================================================
--- 
avro/trunk/lang/java/mapred/src/main/java/org/apache/avro/mapred/AvroMultipleOutputs.java
 (original)
+++ 
avro/trunk/lang/java/mapred/src/main/java/org/apache/avro/mapred/AvroMultipleOutputs.java
 Sat Apr 13 04:30:13 2013
@@ -113,9 +113,11 @@ import org.apache.hadoop.io.NullWritable
  * AvroCollector<OUT>, Reporter reporter)
  * throws IOException {
  * ...
- * amos.getCollector("avro1", reporter).collect(datum);
+ * amos.collect("avro1", reporter,datum);
  * amos.getCollector("avro2", "A", reporter).collect(datum);
- * amos.getCollector("avro3", "B", reporter).collect(datum);
+ * amos.collect("avro1",reporter,schema,datum,"testavrofile");// this create a 
file testavrofile and writes data with schema "schema" into it
+ *                                                            and uses other 
values from namedoutput "avro1" like outputclass etc.
+ * amos.collect("avro1",reporter,schema,datum,"testavrofile1");
  * ...
  * }
  *
@@ -140,7 +142,6 @@ public class AvroMultipleOutputs {
   private static final String COUNTERS_ENABLED = "mo.counters";
  
  
-  private static Map<String,Schema> schemaList = new HashMap<String,Schema>();
   /**
    * Counters group used by the counters of MultipleOutputs.
    */
@@ -310,7 +311,8 @@ public class AvroMultipleOutputs {
     checkNamedOutputName(namedOutput);
     checkNamedOutput(conf, namedOutput, true);
     boolean isMapOnly = conf.getNumReduceTasks() == 0;
-    schemaList.put(namedOutput+"_SCHEMA", schema);
+    if(schema!=null)
+      conf.set(MO_PREFIX+namedOutput+".schema", schema.toString());
     conf.set(NAMED_OUTPUTS, conf.get(NAMED_OUTPUTS, "") + " " + namedOutput);
     conf.setClass(MO_PREFIX + namedOutput + FORMAT, outputFormatClass,
       OutputFormat.class);
@@ -393,7 +395,7 @@ public class AvroMultipleOutputs {
   // MultithreaderMapRunner.
   private synchronized RecordWriter getRecordWriter(String namedOutput,
                                                     String baseFileName,
-                                                    final Reporter reporter)
+                                                    final Reporter 
reporter,Schema schema)
     throws IOException {
     RecordWriter writer = recordWriters.get(baseFileName);
     if (writer == null) {
@@ -401,6 +403,8 @@ public class AvroMultipleOutputs {
         throw new IllegalArgumentException(
           "Counters are enabled, Reporter cannot be NULL");
       }
+      if(schema!=null)
+        conf.set(MO_PREFIX+namedOutput+".schema",schema.toString());
       JobConf jobConf = new JobConf(conf);
       jobConf.set(InternalFileOutputFormat.CONFIG_NAMED_OUTPUT, namedOutput);
       FileSystem fs = FileSystem.get(conf);
@@ -440,7 +444,52 @@ public class AvroMultipleOutputs {
       writer.close(reporter);
     }
   }
-
+  
+  /**
+   * Output Collector for the default schema.
+   * <p/>
+   *
+   * @param namedOutput the named output name
+   * @param reporter    the reporter
+   * @param datum       output data
+   * @return void
+   * @throws IOException thrown if output collector could not be created
+   */
+  public void collect(String namedOutput, Reporter reporter,Object datum) 
throws IOException{
+    getCollector(namedOutput,reporter).collect(datum);
+  }
+  
+  /**
+   * OutputCollector with custom schema.
+   * <p/>
+   *
+   * @param namedOutput the named output name (this will the output file name)
+   * @param reporter    the reporter
+   * @param datum       output data
+   * @param schema      schema to use for this output
+   * @return void
+   * @throws IOException thrown if output collector could not be created
+  */
+  public void collect(String namedOutput, Reporter reporter, Schema 
schema,Object datum) throws IOException{
+    getCollector(namedOutput,reporter,schema).collect(datum);
+  }
+  
+  /**
+   * OutputCollector with custom schema and file name.
+   * <p/>
+   *
+   * @param namedOutput the named output name
+   * @param reporter    the reporter
+   * @param baseOutputPath outputfile name to use.
+   * @param datum       output data
+   * @param schema      schema to use for this output
+   * @return void
+   * @throws IOException thrown if output collector could not be created
+  */
+  public void collect(String namedOutput,Reporter reporter,Schema 
schema,Object datum,String baseOutputPath) throws IOException{
+    
getCollector(namedOutput,null,reporter,baseOutputPath,schema).collect(datum);
+  }
+  
   /**
    * Gets the output collector for a named output.
    * <p/>
@@ -449,13 +498,43 @@ public class AvroMultipleOutputs {
    * @param reporter    the reporter
    * @return the output collector for the given named output
    * @throws IOException thrown if output collector could not be created
+   * @deprecated Use {@link collect} method for collecting output
    */
-  @SuppressWarnings({"unchecked"})
+  @SuppressWarnings({"unchecked", "rawtypes"})
   public AvroCollector getCollector(String namedOutput, Reporter reporter)
     throws IOException {
-    return getCollector(namedOutput, null, reporter);
+    return getCollector(namedOutput, null, reporter,namedOutput,null);
+  }
+
+  @SuppressWarnings("rawtypes")
+  private AvroCollector getCollector(String namedOutput, Reporter reporter, 
Schema schema)
+      throws IOException{
+    return getCollector(namedOutput,null,reporter,namedOutput,schema);
+  }
+  
+  /**
+   * Gets the output collector for a named output.
+   * <p/>
+   *
+   * @param namedOutput the named output name
+   * @param reporter    the reporter
+   * @param multiName   the multiname 
+   * @return the output collector for the given named output
+   * @throws IOException thrown if output collector could not be created
+   */
+  @SuppressWarnings("rawtypes")
+  public AvroCollector getCollector(String namedOutput,String multiName, 
Reporter reporter)
+      throws IOException{
+    return getCollector(namedOutput,multiName,reporter,namedOutput,null);
   }
 
+  @SuppressWarnings("rawtypes")
+  private AvroCollector getCollector(String namedOutput,Schema schema, 
Reporter reporter, String baseFileName)
+      throws IOException{
+    //namedOutputs.add(baseFileName);
+    return getCollector(namedOutput,null,reporter,baseFileName,schema);
+  }  
+  
   /**
    * Gets the output collector for a multi named output.
    * <p/>
@@ -467,8 +546,8 @@ public class AvroMultipleOutputs {
    * @throws IOException thrown if output collector could not be created
    */
   @SuppressWarnings({"unchecked"})
-  public AvroCollector getCollector(String namedOutput, String multiName,
-                                      Reporter reporter)
+  private AvroCollector getCollector(String namedOutput, String multiName,
+                                      Reporter reporter,String 
baseOutputFileName, Schema schema)
     throws IOException {
 
     checkNamedOutputName(namedOutput);
@@ -486,10 +565,10 @@ public class AvroMultipleOutputs {
       checkTokenName(multiName);
     }
 
-    String baseFileName = (multi) ? namedOutput + "_" + multiName : 
namedOutput;
+    String baseFileName = (multi) ? namedOutput + "_" + multiName : 
baseOutputFileName;
 
     final RecordWriter writer =
-      getRecordWriter(namedOutput, baseFileName, reporter);
+      getRecordWriter(namedOutput, baseFileName, reporter,schema);
 
     return new AvroCollector() {
    
@@ -525,11 +604,14 @@ public class AvroMultipleOutputs {
   private static class InternalFileOutputFormat extends 
FileOutputFormat<Object, Object> {
    public static final String CONFIG_NAMED_OUTPUT = "mo.config.namedOutput";
 
-   @SuppressWarnings({"unchecked"})
+   @SuppressWarnings({"unchecked", "deprecation"})
    public RecordWriter<Object, Object> getRecordWriter(FileSystem fs,JobConf 
job, String baseFileName, Progressable arg3) throws IOException {
    String nameOutput = job.get(CONFIG_NAMED_OUTPUT, null);
    String fileName = getUniqueName(job, baseFileName);
-   Schema schema = schemaList.get(nameOutput+"_SCHEMA");
+   Schema schema = null;
+   String schemastr = job.get(MO_PREFIX+nameOutput+".schema",null);
+   if (schemastr!=null)
+      schema = Schema.parse(schemastr);
    JobConf outputConf = new JobConf(job);
    outputConf.setOutputFormat(getNamedOutputFormatClass(job, nameOutput));
    boolean isMapOnly = job.getNumReduceTasks() == 0;

Modified: 
avro/trunk/lang/java/mapred/src/test/java/org/apache/avro/mapred/TestAvroMultipleOutputs.java
URL: 
http://svn.apache.org/viewvc/avro/trunk/lang/java/mapred/src/test/java/org/apache/avro/mapred/TestAvroMultipleOutputs.java?rev=1467543&r1=1467542&r2=1467543&view=diff
==============================================================================
--- 
avro/trunk/lang/java/mapred/src/test/java/org/apache/avro/mapred/TestAvroMultipleOutputs.java
 (original)
+++ 
avro/trunk/lang/java/mapred/src/test/java/org/apache/avro/mapred/TestAvroMultipleOutputs.java
 Sat Apr 13 04:30:13 2013
@@ -90,7 +90,9 @@ public class TestAvroMultipleOutputs {
         sum += count;
       Pair<Utf8,Long> outputvalue= new Pair<Utf8,Long>(word,sum);
       amos.getCollector("myavro",reporter).collect(outputvalue);
-      amos.getCollector("myavro1",reporter).collect(outputvalue.toString());
+      amos.collect("myavro1",reporter,outputvalue.toString());
+      amos.collect("myavro",reporter,new Pair<Utf8,Long>(new Utf8(""), 
0L).getSchema(),outputvalue,"testavrofile");
+      
amos.collect("myavro",reporter,Schema.create(Schema.Type.STRING),outputvalue.toString(),"testavrofile1");
       collector.collect(new Pair<Utf8,Long>(word, sum));
     }
     public void close() throws IOException
@@ -102,6 +104,8 @@ public class TestAvroMultipleOutputs {
   @Test public void runTestsInOrder() throws Exception {
     testJob();
     testProjection();
+    testProjection_newmethods();
+    testProjection_newmethods_1();
     testProjection1();
     testJob_noreducer();
     testProjection_noreducer();
@@ -186,7 +190,57 @@ public class TestAvroMultipleOutputs {
     }
     
     Assert.assertEquals(sumOfCounts, actualSumOfCounts);
+
+  }
+  
+  @SuppressWarnings("deprecation")
+  public void testProjection_newmethods() throws Exception {
+    JobConf job = new JobConf();
+    
+    Integer defaultRank = new Integer(-1);
+    
+    String jsonSchema = 
+      "{\"type\":\"record\"," +
+      "\"name\":\"org.apache.avro.mapred.Pair\","+
+      "\"fields\": [ " + 
+        "{\"name\":\"rank\", \"type\":\"int\", \"default\": -1}," +
+        "{\"name\":\"value\", \"type\":\"long\"}" + 
+      "]}";
+    
+    Schema readerSchema = Schema.parse(jsonSchema);
+    
+    AvroJob.setInputSchema(job, readerSchema);
+    
+    String dir = System.getProperty("test.dir", ".") + "/mapred";
+    Path inputPath = new Path(dir + "/out" + "/testavrofile-r-00000.avro");
+    FileStatus fileStatus = FileSystem.get(job).getFileStatus(inputPath);
+    FileSplit fileSplit = new FileSplit(inputPath, 0, fileStatus.getLen(), 
job);
+
+    
+    AvroRecordReader<Pair<Integer, Long>> recordReader = new 
AvroRecordReader<Pair<Integer, Long>>(job, fileSplit);
+    
+    AvroWrapper<Pair<Integer, Long>> inputPair = new AvroWrapper<Pair<Integer, 
Long>>(null);
+    NullWritable ignore = NullWritable.get();
+    
+    long sumOfCounts = 0;
+    long numOfCounts = 0;
+    while(recordReader.next(inputPair, ignore)) {
+      Assert.assertEquals((Integer)inputPair.datum().get(0), defaultRank);
+      sumOfCounts += (Long) inputPair.datum().get(1);
+      numOfCounts++;
+    }
+    
+    Assert.assertEquals(numOfCounts, WordCountUtil.COUNTS.size());
+    
+    long actualSumOfCounts = 0;
+    for(Long count : WordCountUtil.COUNTS.values()) {
+      actualSumOfCounts += count;
+    }
+    
+    Assert.assertEquals(sumOfCounts, actualSumOfCounts);
+
   }
+  
 
   @SuppressWarnings("deprecation")
   // Test for a differnt schema output
@@ -215,6 +269,34 @@ public class TestAvroMultipleOutputs {
     }
     Assert.assertEquals(sumOfCounts, actualSumOfCounts);
   }
+  
+  @SuppressWarnings("deprecation")
+  // Test for a differnt schema output
+  public void testProjection_newmethods_1() throws Exception {
+    JobConf job = new JobConf();
+    Schema readerSchema = Schema.create(Schema.Type.STRING);
+    AvroJob.setInputSchema(job, readerSchema);
+
+    String dir = System.getProperty("test.dir", ".") + "/mapred";
+    Path inputPath = new Path(dir + "/out" + "/testavrofile1-r-00000.avro");
+    FileStatus fileStatus = FileSystem.get(job).getFileStatus(inputPath);
+    FileSplit fileSplit = new FileSplit(inputPath, 0, fileStatus.getLen(), 
job);
+    AvroWrapper<Utf8> inputPair = new AvroWrapper<Utf8>(null);
+    NullWritable ignore = NullWritable.get();
+    AvroRecordReader<Utf8> recordReader = new AvroRecordReader<Utf8>(job, 
fileSplit);
+    long sumOfCounts = 0;
+    long numOfCounts = 0;
+    while(recordReader.next(inputPair, ignore)) {
+        sumOfCounts += 
Long.parseLong(inputPair.datum().toString().split(":")[2].replace("}","").trim());
+        numOfCounts++;
+    }
+    Assert.assertEquals(numOfCounts, WordCountUtil.COUNTS.size());
+    long actualSumOfCounts = 0;
+    for(Long count : WordCountUtil.COUNTS.values()) {
+     actualSumOfCounts += count;
+    }
+    Assert.assertEquals(sumOfCounts, actualSumOfCounts);
+  }
 
   @SuppressWarnings("deprecation")
   public void testJob_noreducer() throws Exception {


Reply via email to