Textコンストラクターから、実際には意味をなさない動作が発生しています。基本的に、文字列からTextオブジェクトを作成する場合、getBytes()が両方のオブジェクトに対して同じ値を返す場合でも、バイトから作成した別のTextオブジェクトと同じではありません。
だから私たちはこのような奇妙なものを手に入れます:
//This succeeds
assertEquals(new Text("ACTACGACCA_0"), new Text("ACTACGACCA_0"));
//This succeeds
assertEquals((new Text("ACTACGACCA_0")).getBytes(), (new Text("ACTACGACCA_0")).getBytes());
//This fails. Why?
assertEquals(new Text((new Text("ACTACGACCA_0")).getBytes()), new Text("ACTACGACCA_0"));
これは、ハッシュマップにアクセスしようとしたときに現れます。ここでは、org.apache.hadoop.hbase.KeyValue.getRow()によって返された値に基づいてルックアップを実行しようとしています。
//This succeeds
assertEquals((new Text("ACTACGACCA_0")).getBytes(), keyValue.getRow());
//This returns a value
hashMap.get(new Text("ACTACGACCA_0"));
//This returns null. Why?
hashMap.get(new Text(keyValue.getRow()));
では、ここで何が起こっているのでしょうか。また、どのように対処すればよいのでしょうか。これはエンコーディングと関係がありますか?
更新:問題は解決しました
これで私を正しい方向に向けてくれたクリスに感謝します。したがって、少し背景があります。keyValueオブジェクトは、htable.put()の呼び出しから(Mockito ArgumentCaptorを使用して)キャプチャされます。基本的に、私はこのコードのチャンクを持っていました:
byte[] keyBytes = matchRow.getKey().getBytes();
RowLock rowLock = hTable.lockRow(keyBytes);
Get get = new Get(keyBytes, rowLock);
SetWritable<Text> toWrite = new SetWritable<Text>(Text.class);
toWrite.getValues().addAll(matchRow.getMatches(hTable, get));
Put put = new Put(keyBytes, rowLock);
put.add(Bytes.toBytes(MatchesByHaplotype.MATCHING_COLUMN_FAMILY), Bytes.toBytes(MatchesByHaplotype.UID_QUALIFIER),
SERIALIZATION_HELPER.serialize(toWrite));
hTable.put(put);
ここで、matchRow.getKey()はテキストオブジェクトを返します。ここに問題がありますか?無効なバイトも含めて、すべてのバイトを追加していました。 だから私はこれを行う素晴らしいヘルパー関数を作成しました:
public byte[] getValidBytes(Text text) {
return Arrays.copyOf(text.getBytes(), text.getLength());
}
そして、そのブロックの最初の行をこれに変更しました:
byte[] keyBytes = SERIALIZATION_HELPER.getValidBytes(matchRow.getKey());
問題が解決しました!振り返ってみると:すごい、なんて厄介なバグでしょう!結局のところ、Text.getBytes()の動作は非常にn00bに対応していないということだと思います。予期しないもの(無効なバイト)を返すだけでなく、Textオブジェクトには有効なバイトのみを返す関数がありません!これは一般的なユースケースだと思うでしょう。たぶん彼らはこれを将来追加するのでしょうか?