首页 > 解决方案 > 累积范围 - 不包含结束键

问题描述

我正在学习 Accumulo,似乎无法让 Range 中指定的结束键包含在内。我的代码如下。我曾尝试将其明确设置endKeyInclusivetruein Range,但这并没有帮助。

BatchWriter writer = conn.createBatchWriter("table", config);

List<String> deterTimes = new ArrayList<>();

String rowId = "3015551212<ll>";
String columnFamily = "deter";
for (int i = 0; i < 10; i++) {
    String deterTime = "20181112:21:46:33" + i;
    deterTimes.add(deterTime);
    writer.addMutation(makeRecord(rowId, columnFamily, deterTime, "DETER" + i));                   
}

writer.flush();
writer.close();

Scanner scan = conn.createScanner("table", auths);

Key startKey = new Key(rowId.getBytes(), columnFamily.getBytes(), deterTimes.get(1).getBytes());
Key endKey = new Key(rowId.getBytes(), columnFamily.getBytes(), deterTimes.get(4).getBytes());
Range range = new Range(startKey, endKey);
if (range.isEndKeyInclusive())  System.out.println("true");
scan.setRange(range);

for (Entry<Key,Value> entry : scan) {
    Text row = entry.getKey().getRow();
    Text cq = entry.getKey().getColumnQualifier();
    Value value = entry.getValue();
    System.out.println("Fetched row " + row + " with value: " + value + ", cq=" + cq);
}

输出:

true
Fetched row 3015551212<ll> with value: DETER1, cq='20181112:21:46:331'
Fetched row 3015551212<ll> with value: DETER2, cq='20181112:21:46:332'
Fetched row 3015551212<ll> with value: DETER3, cq='20181112:21:46:333'

标签: javaaccumulo

解决方案


您正在使用( row, column family, column qualifier )as 字节数组构建结束键,并将键的其余维度( column visibility, timestamp )设置为默认值(具体而言,分别为空字节数组和Long.MAX_VALUE)。

扫描仪将停在那个确切的键上,包括在内。但是,您的实际数据输入几乎肯定不是那个确切的密钥(您没有提供您的实现makeRecord来验证)。即使您的数据实际上具有空列可见性,时间戳也几乎肯定不是Long.MAX_VALUE,而是您在makeRecord实现中设置的内容,或者它是基于 tserver 的时间或某些表逻辑计数器设置的。由于键的时间戳维度是按降序排列的,因此您的扫描器将在数据Long.MAX_LONG到达您的条目之前停止查找数据。

这有点像在字典中搜索analogy,但当你到达时停止analog:你会错过以 开头的剩余单词analog

在基于精确键构建范围时,这是一个常见的陷阱。通常,基于行(包括行将包括整行)而不是键(有一个Range 构造函数)来构造范围通常更好。或者,指定结束键以使其独占。您可以通过在列的最后一个有意义元素的末尾附加一个空字节来做到这一点。例如,您可以执行以下操作:

Key endKey = new Key(rowId.getBytes(),
                     columnFamily.getBytes(),
                     (deterTimes.get(4) + "\0").getBytes());
Range range = new Range(startKey, true, endKey, false);

您应该注意的另一个陷阱是String.getBytes()在不指定编码的情况下获取字节数组。最好使用一致的东西,比如"abc".getBytes(StandardCharsets.UTF_8)(我通常做一个静态导入,所以我只能指定UTF_8)。


推荐阅读