入力文字列に基づいて指定したビット範囲の数値を返すので、それを利用してアクセス先を振り分けることが出来る。
使い方としては、以下の用に接頭語を付けてキーを作成する。
private static Key createShardKey(String inPrefix, String inKeyName) {
int bitSize = 8;
long hashNum = Digest.getHashNum(inKeyName, bitSize);
String key = inPrefix + String.format("_%05x", hashNum);
return Datastore.createKey(Hoge.class, key);
}
データの読み込みはキーの名前を文字列に格納し、クエリで取得する。
(ここでは検索用にキーとは別に文字列型のフィールドを用意していますが、キーに対して前方一致はが出来ればな良いのにな~、と思いました。
少しでも不要なインデックスを減らしたいので。)
Datastore.query(META)
.filter(META.keyName.startsWith("Prefix"))
.asList();
処理の内容としては、文字列をハッシュ変換し、その先頭から数値を取り出しています。
取り出す数値の範囲は出来るだけ偏りが無いように、ビットで指定します。
なので2, 4, 6, ...と2の倍数までの値となります。
package auction.service.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Digest {
/**
* 指定したビット範囲内のハッシュを取得
*
*/
public static long getHashNum(String str, int bit) {
byte[] hash = digest(str);
long num = 0;
/* ハッシュ値の先頭8byteをLongへ変換 */
for (int cnt_i = 0; cnt_i < 8; cnt_i++) {
num = (num << 8) | (hash[cnt_i] & 0xff);
}
/* 指定ビットでマスク */
long mask = getMask(bit);
num = num & mask;
return num;
}
/**
* ハッシュ文字列を取得
*
*/
public static String getHash(String str) {
byte[] hash = digest(str);
return hexToString(hash);
}
/**
* 文字列をハッシュ化した結果を表示
*
*/
public static void printDigest(String str) {
byte[] hash = digest(str);
System.out.println("文字列:" + str);
System.out.println(hash.length);
System.out.println(hexToString(hash));
}
/**
* メッセージダイジェスト (固定長のハッシュ値) を取得
*
*/
private static byte[] digest( String inText ) {
MessageDigest dig = null;
try {
dig = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
dig.update(inText.getBytes());
return dig.digest();
}
/**
* ビットマスクを取得
*
*/
private static long getMask(int bit) {
long mask = 0L;
for (int cnt_i = 0; cnt_i < bit; cnt_i++) {
mask = (mask << 1) + 1L;
}
return mask;
}
/**
* バイト列を文字列へ変換
*
*/
private static String hexToString(byte[] bin) {
StringBuilder sb = new StringBuilder();
int size = bin.length;
for (int i = 0; i < size; i++) {
String hex = String.format("%02x", bin[i]);
sb.append(hex);
}
return sb.toString();
}
}
0 件のコメント:
コメントを投稿