6

我有一个带有单个列族的 HBase (v0.94.7) 表,并且随着时间的推移将列添加到其中。这些列被命名为它们创建的时间戳,所以除非我查询该行,否则我不知道它的所有列。

现在给定一行,我想自动删除该列族的所有现有列并添加一组新的列和值。

所以我想到了使用 HBase 的RowMutations,比如:

RowMutations mutations = new RowMutations(row);

//delete the column family
Delete delete = new Delete(row);
delete.deleteFamily(cf);

//add new columns
Put put = new Put(row);
put.add(cf, col1, v1);
put.add(cf, col2, v2);

//delete column family and add new columns to same family
mutations.add(delete);
mutations.add(put);

table.mutateRow(mutations);

但是这段代码最终做的只是删除列族,而不是添加新列。这种行为是预期的吗?

如果是这样,那么我怎样才能实现用一组新的列原子地替换列族的所有列的目标?

这是相同的测试用例:

import junit.framework.Assert;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.TableExistsException;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import java.util.NavigableMap;

public class TestHBaseRowMutations {
    static String tableName = "nnn";
    static byte[] cf1 = Bytes.toBytes("cf1");
    static byte[] row = Bytes.toBytes("r1");
    static HTablePool hTablePool;

    @BeforeClass
    public static void beforeClass() throws Exception {
        Configuration config = HBaseConfiguration.create();
        hTablePool = new HTablePool(config, Integer.MAX_VALUE);
        HBaseAdmin admin = new HBaseAdmin(config);
        HTableDescriptor tableDescriptor = new HTableDescriptor(tableName);
        tableDescriptor.addFamily(new HColumnDescriptor(cf1));
        try {
            admin.createTable(tableDescriptor);
        } catch (TableExistsException ignored){}
    }

    @Before
    public void before() throws Exception {
        HTableInterface table = hTablePool.getTable(tableName);
        try {
            Delete delete = new Delete(row);
            table.delete(delete);
            System.out.println("deleted old row");

            Put put = new Put(row);
            put.add(cf1, Bytes.toBytes("c1"), Bytes.toBytes("v1"));
            put.add(cf1, Bytes.toBytes("c11"), Bytes.toBytes("v11"));
            table.put(put);
            System.out.println("Created row with seed data");
        } finally {
            table.close();
        }
    }


    @Test
    public void testColumnFamilyDeleteRM() throws Exception {
        HTableInterface table = hTablePool.getTable(tableName);
        try {
            RowMutations rm =new RowMutations(row);

            //delete column family cf1
            Delete delete = new Delete(row);
            delete.deleteFamily(cf1);
            rm.add(delete);
            System.out.println("Added delete of cf1 column family to row mutation");

            //add new columns to same column family cf1
            Put put = new Put(row);
            put.add(cf1, Bytes.toBytes("c1"), Bytes.toBytes("new_v1"));
            put.add(cf1, Bytes.toBytes("c11"), Bytes.toBytes("new_v11"));
            rm.add(put);
            System.out.println("Added puts of cf1 column family to row mutation");

            //atomic mutate the row
            table.mutateRow(rm);
            System.out.println("Mutated row");

            //now read the column family cf1 back
            Result result = table.get(new Get(row));
            NavigableMap<byte[], byte[]> familyMap = result.getFamilyMap(cf1);

            //column family cf1 should have 2 columns because of the Put above
            //------Following assert fails as cf1 does not exist anymore, why does cf1 not exist anymore?-------
            Assert.assertNotNull(familyMap);
            Assert.assertEquals(2, familyMap.size());
        } finally {
            table.close();
        }
    }
}
4

3 回答 3

5

在 HBase 用户论坛上发布了相同的问题,结果发现这是 HBase 中的一个错误。

预期的行为是,如果 RowMutation 对某个列族/列/行进行了删除,然后对同一列族/列/行进行了 Put,则也应该遵守 Put(但目前情况并非如此)。

HBase 用户组对此的讨论: http: //apache-hbase.679495.n3.nabble.com/Using-RowMutations-to-replace-all-columns-of-a-row-td4045247.html

相同的 HBase JIRA: https ://issues.apache.org/jira/browse/HBASE-8626 ,它也提供补丁。

于 2013-05-27T17:09:34.740 回答
2

最接近的方法是将 Put 上的时间戳设置为高于 Delete 上的时间戳:

long now = System.currentTimeMillis();

Delete delete = new Delete(row);
delete.deleteFamily(cf1, now);

Put put = new Put(row);
put.add(cf1, col1, now + 1);

RowMutations mutations = new RowMutations(row);
mutations.add(delete);
mutations.add(put);

table.mutateRow(mutations);

可悲的是,这确实意味着get时间戳“现在”在该列族中将没有任何内容。资源

于 2016-02-11T19:08:47.283 回答
0

有一个场景要分享,当我们尝试执行 RowMutations 列表时,每个可能包含 ROW1:CF1:Q1:V1 的有效 Put 和 ROW1:CF2:Q1:V1 的删除作为 hbase 批量操作,并得到以下错误

java.lang.RuntimeException:java.lang.UnsupportedOperationException:多次调用中没有 RowMutations;在 org.apache.hadoop.hbase.client.AsyncProcess$AsyncRequestFutureImpl$SingleServerRequestRunnable.run(AsyncProcess.java:748) 在 java 的 org.apache.hadoop.hbase.client.RpcRetryingCaller.callWithoutRetries(RpcRetryingCaller.java:218) 使用 mutateRow .util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) 在 java.util.concurrent.FutureTask.run(FutureTask.java:266) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149 ) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 在 java.lang.Thread.run(Thread.java:748)

为了解决这个问题,我们选择单独执行每个 rowMutation。欢迎您提出任何建议。

于 2019-05-16T11:11:39.500 回答