2016-03-25 24 views
1

Mapper tarafından Reducer'da yayılan en yaygın anahtarı bulmalıyım. Benim düşürücü bu şekilde çalışıyor: Bu en küçük mesafeler ile K örneklerini bulur ve çıkış dosyasına yazarReducer'da en yaygın anahtarı bulma, Hata: java.lang.ArrayIndexOutOfBoundsException: 1

public static class MyReducer extends Reducer<NullWritable, Text, NullWritable, Text> { 
    private Text result = new Text(); 
    private TreeMap<Double, Text> k_closest_points= new TreeMap<Double, Text>(); 
    public void reduce(NullWritable key, Iterable<Text> values, Context context) 
      throws IOException, InterruptedException { 

     Configuration conf = context.getConfiguration(); 
     int K = Integer.parseInt(conf.get("K")); 
     for (Text value : values) { 
      String v[] = value.toString().split("@"); //format of value from mapper: "[email protected]" 
      double distance = Double.parseDouble(v[1]); 
      k_closest_points.put(distance, new Text(value)); //finds the K smallest distances 
      if (k_closest_points.size() > K) 
       k_closest_points.remove(k_closest_points.lastKey()); 
     } 
     for (Text t : k_closest_points.values()) //it perfectly emits the K smallest distances and keys 
      context.write(NullWritable.get(), t); 
    } 
} 

. Ama TreeMap'ımdaki en yaygın anahtarı bulmalıyım. Bu yüzden aşağıda gibi çalışıyorum:

Error: java.lang.ArrayIndexOutOfBoundsException: 1 
     at KNN$MyReducer.reduce(KNN.java:108) 
     at KNN$MyReducer.reduce(KNN.java:98) 
     at org.apache.hadoop.mapreduce.Reducer.run(Reducer.java:171) 

Bunu düzeltmek için bana yardım edebilir:

public static class MyReducer extends Reducer<NullWritable, Text, NullWritable, Text> { 
    private Text result = new Text(); 
    private TreeMap<Double, Text> k_closest_points = new TreeMap<Double, Text>(); 

    public void reduce(NullWritable key, Iterable<Text> values, Context context) 
      throws IOException, InterruptedException { 

     Configuration conf = context.getConfiguration(); 
     int K = Integer.parseInt(conf.get("K")); 
     for (Text value : values) { 
      String v[] = value.toString().split("@"); 
      double distance = Double.parseDouble(v[1]); 
      k_closest_points.put(distance, new Text(value)); 
      if (k_closest_points.size() > K) 
       k_closest_points.remove(k_closest_points.lastKey()); 
     } 
     TreeMap<String, Integer> class_counts = new TreeMap<String, Integer>(); 
     for (Text value : k_closest_points.values()) { 
      String[] tmp = value.toString().split("@"); 
      if (class_counts.containsKey(tmp[0])) 
       class_counts.put(tmp[0], class_counts.get(tmp[0] + 1)); 
      else 
       class_counts.put(tmp[0], 1); 
     } 
     context.write(NullWritable.get(), new Text(class_counts.lastKey())); 
    } 
} 

Sonra bu hata alıyorum? Sen "@" üzerine Ayrılıyorlar

double distance = Double.parseDouble(v[1]); 

ve dizede olmayabilir:

+0

'double distance = Double.parseDouble (v [1]); 'Burası gerçekleşiyor. Değerde bir "@" olduğundan emin misin? – Tgsmith61591

+0

Evet, eminim. İlk versiyonun çıkışı şöyle: [email protected] Ve ayrıca birincisi problemsiz çalışıyor. –

+0

Olasılıkları azaltmak için 'v' ve' tmp' boyutlarını kontrol edin. – Berger

cevap

1

bir kaç şey ... İlk senin sorunun burada. Değilse, OutOfBoundsException'u atar. tmp bir String[] ve henüz burada aslında sadece put kendisine '1' bitiştirmek ediyoruz,

if(v.length < 2) 
    continue; 

İkinci (ve ben deliyim sürece bu bile derlemek olmamalı): Ben böyle bir madde eklersiniz operasyon (öyle bir parantez sayı):

class_counts.put(tmp[0], class_counts.get(tmp[0] + 1)); 

olmalıdır: Bu aramaya da pahalı

class_counts.put(tmp[0], class_counts.get(tmp[0]) + 1); 

Potansiyel olarak büyük bir Map numaralı anahtarın iki katı. İşte bütçeyi nasıl (bu tamamen denenmemiş olan) bize verdiklerinin dayalı redüktör yeniden yazmak:

public static class MyReducer extends Reducer<NullWritable, Text, NullWritable, Text> { 
    private Text result = new Text(); 
    private TreeMap<Double, Text> k_closest_points = new TreeMap<Double, Text>(); 

    public void reduce(NullWritable key, Iterable<Text> values, Context context) 
      throws IOException, InterruptedException { 

     Configuration conf = context.getConfiguration(); 
     int K = Integer.parseInt(conf.get("K")); 

     for (Text value : values) { 
      String v[] = value.toString().split("@"); 
      if(v.length < 2) 
       continue; // consider adding an enum counter 

      double distance = Double.parseDouble(v[1]); 
      k_closest_points.put(distance, new Text(v[0])); // you've already split once, why do it again later? 

      if (k_closest_points.size() > K) 
       k_closest_points.remove(k_closest_points.lastKey()); 
     } 


     // exit early if nothing found 
     if(k_closest_points.isEmpty()) 
      return; 


     TreeMap<String, Integer> class_counts = new TreeMap<String, Integer>(); 
     for (Text value : k_closest_points.values()) { 
      String tmp = value.toString(); 
      Integer current_count = class_counts.get(tmp); 

      if (null != current_count) // avoid second lookup 
       class_counts.put(tmp, current_count + 1); 
      else 
       class_counts.put(tmp, 1); 
     } 

     context.write(NullWritable.get(), new Text(class_counts.lastKey())); 
    } 
} 

Sonraki ve daha semantik, siz bir TreeMap kullanarak KNN işlemi gerçekleştirirken olmadığınız, seçim veri tabanı. Bu, anahtarların karşılaştırmalı sırayla dahili olarak depolanması anlamında mantıklı olsa da, bağları koparmak için neredeyse hiç şüphesiz gereken bir işlem için bir Map kullanmak mantıklı değildir. İşte nedeni:

int k = 2; 
TreeMap<Double, Text> map = new TreeMap<>(); 
map.put(1.0, new Text("close")); 
map.put(1.0, new Text("equally close")); 
map.put(1500.0, new Text("super far")); 
// ... your popping logic... 

Korunan en yakın iki nokta hangileridir? "equally close" ve "super far". Bunun nedeni, aynı anahtarın iki örneğinin bulunamamasıdır. Böylece, algoritmanız bağları koparmaktan acizdir. Eğer Reducer bu işlemi gerçekleştirirken ayarlanmış konum ve biliyor eğer

İlk, gelen veriler, bir OutOfMemoryError neden farklı kullanmayı düşünün olmaz: Bunu düzeltmek için yapabileceği bir şeyler vardır bir TreeSet gibi yapı sıralanmış ve özel bir Comparable nesneyi oluşturmak o tür olacak: senin TreeMap yerine o

static class KNNEntry implements Comparable<KNNEntry> { 
    final Text text; 
    final Double dist; 

    KNNEntry(Text text, Double dist) { 
     this.text = text; 
     this.dist = dist; 
    } 

    @Override 
    public int compareTo(KNNEntry other) { 
     int comp = this.dist.compareTo(other.dist); 
     if(0 == comp) 
      return this.text.compareTo(other.text); 
     return comp; 
    } 
} 

ve içten sıralama kendisi Comparator l dayalı bir TreeSet<KNNEntry> kullanmak yukarıda yaptığımız ogic.Daha sonra tüm tuşlardan geçtikten sonra, ilk sırayla k'u tekrarlayarak sırayla saklayın. Bununla birlikte, bunun bir dezavantajı vardır: eğer verileriniz gerçekten büyükse, tüm değerleri redüktörden belleğe yükleyerek heapspace'i taşabilirsiniz.

İkinci seçenek: KNNEntry yukarıda WritableComparable uygulamak ve senin Mapper dan, sonra girişlerin sıralamayı işlemek için secondary sorting kullandığını yayarlar inşa edin. Bu çok daha kıllı olur, çünkü çok sayıda haritacı kullanmanız gerekir ve daha sonra ilk k'u yakalamak için sadece bir redüktör kullanmanız gerekir. Verileriniz yeterince küçükse, bağlantı kopmasına izin vermek için ilk seçeneği deneyin.

Ancak, orijinal sorunuza geri döndüğünüzde, erişmeye çalıştığınız dizin olmadığı için OutOfBoundsException alıyorsunuz, yani String girişinde "@" bulunmuyor.

+0

Öncelikle önerileriniz için çok teşekkür ederim. Sunulan ilk yaklaşımı uygulamaya çalışacağım. Fakat haritadan yayılan değer, içinde @ işareti içeriyor. Çünkü ilk versiyonun çıktısı tam olarak beklediğim şey (sınıf @ mesafesi). En yaygın anahtarı bulmak için yeni satırlar ekledikten sonra, bu dizin sınırlarından şikayet etmeye başlar. –

+0

Düzenlememi kontrol et. Redüktörünü tekrar yazdım. Tmp ile ilgili bir sorun olabileceğini düşünüyorum. Bunu deneyin ve işe yarayıp yaramadığını görün… – Tgsmith61591

+0

Tamam şimdi anladım. Bunu kontrol edeceğim. –