Удалить строку из таблицы на основе значения [Накопление]

У меня есть таблица, которая в настоящее время настроена так:

rowId : colFam: colQual -> value

in001 : user : name -> erp
in001 : user : age -> 23
in001 : group : name -> employee
in001 : group : name -> developer

Кажется, я не могу придумать способ удалить одну из записей группы или изменить ее, если на то пошло. Гипотетически я хочу удалить строку с сотрудником, потому что я теперь менеджер. Добавление очевидно, но я не могу понять, как получить доступ к employee, так как две группы имеют одинаковые colFam и colQual.

Я знаю mutation.putDelete(colFam,colQual), но это здесь не применимо, так как результатом этого будет удаление обоих. Или, если бы я просто сканировал каждую строку и возвращал пары значений ключа, например

for(Entry<Key,Value> e: scanner){
    e.getValue().toString() // atleast I can access it here
}

Но даже тогда, как узнать, что удалять? Это просто недостаток в моем дизайне таблиц?


person erp    schedule 03.08.2015    source источник


Ответы (3)


Хотя схема Accumulo Key-Value позволяет вам это сделать, как вы обнаружили, это проблематично. Первоначальная цель значения состоит в том, что оно может меняться с течением времени, при этом версии этого значения однозначно идентифицируются частью ключа с отметкой времени (при условии, что все остальные части ключа эквивалентны). Отключив VersioningIterator, вы можете сохранить историческую запись значений для ключа.

Наиболее распространенный подход к этой проблеме заключается в использовании некоторой сериализованной структуры данных для хранения всех «имен групп» в одном значении. Простым подходом является CSV «сотрудник, разработчик», и тогда ваше обновление будет «сотрудник, разработчик, менеджер». Вы можете использовать такие инструменты, как Hadoop Writable, Google Protocol Buffers или Apache Thrift (или многие другие), чтобы получить более компактное представление, более легкий программный доступ и обратную совместимость.

person elserj    schedule 05.08.2015

Можно удалить именно строку

in001 : group : name -> employee

с помощью: compact и настраиваемый фильтр, который точно исключает это значение от уплотнения. (Не проверено, но должно работать.) Используйте:

IteratorSetting config = new IteratorSetting(10, "excludeTermFilter", ExcludeTermFilter.class);
config.setTermToExclude("group","name","employee");
List<IteratorSetting> filterList = new ArrayList<IteratorSetting>();
filterList.add(config);
connector.tableOperations().compact(tableName, startRow, endRow, filterList, true, false);

с соответствующими значениями и этим настраиваемым фильтром (на основе GrepIterator):

public class ExcludeTermFilter extends Filter {    
  private byte termToExclude[];
  private byte columnFamily[];
  private byte columnQualifier[];
  @Override
  public boolean accept(Key k, Value v) {
    return !(match(v.get(),termToExclude) &&
             match(k.getColumnFamilyData(),columnFamily) &&
             match(k.getColumnQualifierData(),columnQualifier) 
            );
  }

  private boolean match(ByteSequence bs, byte[] term) {
    return indexOf(bs.getBackingArray(), bs.offset(), bs.length(), term) >= 0;
  }

  private boolean match(byte[] ba, byte[] term) {
    return indexOf(ba, 0, ba.length, term) >= 0;
  }

  // copied code below from java string and modified    
  private static int indexOf(byte[] source, int sourceOffset, int sourceCount, byte[] target) {
    byte first = target[0];
    int targetCount = target.length;
    int max = sourceOffset + (sourceCount - targetCount);

    for (int i = sourceOffset; i <= max; i++) {
      /* Look for first character. */
      if (source[i] != first) {
        while (++i <= max && source[i] != first)
          continue;
      }

      /* Found first character, now look at the rest of v2 */
      if (i <= max) {
        int j = i + 1;
        int end = j + targetCount - 1;
        for (int k = 1; j < end && source[j] == target[k]; j++, k++)
          continue;

        if (j == end) {
          /* Found whole string. */
          return i - sourceOffset;
        }
      }
    }
    return -1;
  }

  @Override
  public SortedKeyValueIterator<Key,Value> deepCopy(IteratorEnvironment env) {
    GrepIterator copy = (GrepIterator) super.deepCopy(env);
    copy.termToExclude = Arrays.copyOf(termToExclude, termToExcludelength);
    copy.columnFamily = Arrays.copyOf(columnFamily, termToExcludelength);
    copy.columnQualifier = Arrays.copyOf(columnQualifier, termToExcludelength);
    return copy;
  }

  @Override
  public void init(SortedKeyValueIterator<Key,Value> source, Map<String,String> options, IteratorEnvironment env) throws IOException {
    super.init(source, options, env);
    termToExclude = options.get("etf.term").getBytes(UTF_8);
    columnFamily = options.get("etf.family").getBytes(UTF_8);
    columnQualifier = options.get("etf.qualifier").getBytes(UTF_8);
  }

  /**
   * Encode the family, qualifier and termToExclude as an option for a ScanIterator
   */
  public static void setTermToExclude(IteratorSetting cfg, String family, String qualifier, String termToExclude) {
    cfg.addOption("etf.family", family);
    cfg.addOption("etf.qualifier", qualifier);
    cfg.addOption("etf.term", termToExclude);
  }
}
person Martin Grimmer    schedule 19.08.2015

Или вы можете использовать другую схему

rowId : colFam: colQual -> value

in001 : user : name -> erp 
in001 : user : age -> 23
in001 : group/0 : name -> employee
in001 : group/1 : name -> developer

Или, может быть

rowId : colFam: colQual -> value

in001 : user : name -> erp 
in001 : user : age -> 23
in001 : group : 0/name -> employee
in001 : group : 1/name -> developer

Это означает, что для отношений «имеет много» вы вводите ключ для каждого из них (либо в colFamily, либо в colQualifier), что позволяет вам управлять каждым из них независимо.

person angelf    schedule 29.12.2015