2015-10-19 21 views
5

Ustawienia:

Mam tabelę HBase, z 100M + wiersze i 1 Milion + kolumn. Każdy wiersz ma dane tylko od 2 do 5 kolumn. Jest tylko jedna rodzina kolumn.Czy możemy uzyskać wszystkie nazwy kolumn z tabeli HBase?

Problem:

chcę znaleźć wszystkie odrębne qualifiers (kolumny) w tym column family. Czy istnieje szybki sposób na zrobienie tego?

Mogę myśleć o przeskanowaniu całego stołu, a następnie otrzymaniu familyMap dla każdego wiersza, uzyskania qualifier i dodania go do Set<>. Ale to byłoby strasznie powolne, ponieważ istnieje 100 milionów wierszy.

Czy możemy zrobić coś lepszego?

Odpowiedz

1

HBase mogą być wizualizowane w postaci rozproszonej NavigableMap<byte[], NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>>>

Jest nr „metadane” (coś powiedzieć przechowywane centralnie w węźle nadrzędnym) o listę wszystkich eliminacjach, które jest dostępne na wszystkich serwerach regionu.

Jeśli masz jednorazowy przypadek użycia, jedynym sposobem jest przeskanowanie całej tabeli i dodanie nazw kwalifikatorów do Set<>, tak jak wspomniałeś.

Jeśli jest to wielokrotny przypadek użycia (plus jeśli masz prawo dodawać komponenty do stosu technologii), możesz rozważyć dodanie Redis. Zestaw kwalifikatorów można utrzymywać w sposób rozproszony za pomocą Redis Set.

0

Do tego scenariusza można użyć koprocesorów HBase. Możesz napisać niestandardową implementację EndPoint, która działa podobnie jak procedury przechowywane w RDBMS. Wykonuje kod po stronie serwera i otrzymuje odrębne kolumny dla każdego regionu. Na kliencie możesz uzyskać oddzielne kolumny we wszystkich regionach.

Korzyści z wydajności: Wszystkie kolumny nie są przesyłane do klienta, co skutkuje zmniejszonymi połączeniami sieciowymi.

2

Możesz użyć do tego celu mapy. W tym przypadku nie trzeba instalować niestandardowych bibliotek dla hbase, jak w przypadku koprocesora. Poniżej kod do tworzenia zadania mapreduce.

setup Praca

Job job = Job.getInstance(config); 
    job.setJobName("Distinct columns"); 

    Scan scan = new Scan(); 
    scan.setBatch(500); 
    scan.addFamily(YOU_COLUMN_FAMILY_NAME); 
    scan.setFilter(new KeyOnlyFilter()); //scan only key part of KeyValue (raw, column family, column) 
    scan.setCacheBlocks(false); // don't set to true for MR jobs 


    TableMapReduceUtil.initTableMapperJob(
      YOU_TABLE_NAME, 
      scan,   
      OnlyColumnNameMapper.class, // mapper 
      Text.class,    // mapper output key 
      Text.class,    // mapper output value 
      job); 

    job.setNumReduceTasks(1); 
    job.setReducerClass(OnlyColumnNameReducer.class); 
    job.setReducerClass(OnlyColumnNameReducer.class); 

Mapper

public class OnlyColumnNameMapper extends TableMapper<Text, Text> { 
    @Override 
    protected void map(ImmutableBytesWritable key, Result value, final Context context) throws IOException, InterruptedException { 
     CellScanner cellScanner = value.cellScanner(); 
     while (cellScanner.advance()) { 

      Cell cell = cellScanner.current(); 
      byte[] q = Bytes.copy(cell.getQualifierArray(), 
           cell.getQualifierOffset(), 
           cell.getQualifierLength()); 

      context.write(new Text(q),new Text()); 

     } 
} 

}

Reduktor

public class OnlyColumnNameReducer extends Reducer<Text, Text, Text, Text> { 

    @Override 
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {  
      context.write(new Text(key), new Text());  
    } 
}