HBase 的基本 API,包括增、刪、改、查等。查詢可以根據(jù) Rowkey 進(jìn)行 Get 或根據(jù) Rowkey 的范圍進(jìn)行 Scan 掃描。同時(shí)提供了更加高級(jí)的過(guò)濾器(Filter)在 Server 端過(guò)濾查詢結(jié)果,只將滿足條件的數(shù)據(jù)返回給客戶端。
過(guò)濾器的類型很多,可以分為兩大類:比較過(guò)濾器和專用過(guò)濾器。
比較運(yùn)算符和比較器
比較過(guò)濾器需要兩個(gè)參數(shù):比較運(yùn)算符和比較器
比較運(yùn)算符
在比較過(guò)濾器中需要用到比較運(yùn)算符,HBase 內(nèi)置以下7種比較運(yùn)算符
public enum CompareOp {
LESS, // 檢查是否小于比較器里的值
LESS_OR_EQUAL, // 檢查是否小于或等于比較器里的值
EQUAL, // 檢查是否等于比較器里的值
NOT_EQUAL, // 檢查是否不等于比較器里的值
GREATER_OR_EQUAL, // 檢查是否大于或等于比較器里的值
GREATER, // 檢查是否大于比較器里的值
NO_OP, // 默認(rèn)返回false,因此過(guò)濾掉所有的數(shù)據(jù)
}
比較器
通過(guò)比較器可以實(shí)現(xiàn)多樣化目標(biāo)匹配效果,比較器有以下子類可以使用:
BinaryComparator // 匹配完整字節(jié)數(shù)組
BinaryPrefixComparator // 匹配字節(jié)數(shù)組前綴
BitComparator // 按位執(zhí)行與、或、異或比較
NullComparator // 判斷當(dāng)前值是不是 NULL
RegexStringComparator // 正則表達(dá)式匹配字符串
SubstringComparator // 子串匹配,相當(dāng)于 contains()
比較過(guò)濾器
行鍵過(guò)濾器 RowFilter
Scan scan = new Scan();
Filter filter = new RowFilter(CompareOp.LESS_OR_EQUAL,
new BinaryComparator(Bytes.toBytes("uid-100")));
scan.setFilter(filter);
篩選出匹配的所有的行,基于行鍵(Rowkey)過(guò)濾數(shù)據(jù),可以執(zhí)行精確匹配,子字符串匹配或正則表達(dá)式匹配,過(guò)濾掉不匹配的數(shù)據(jù)。
一般來(lái)說(shuō),對(duì) Rowkey 進(jìn)行范圍過(guò)濾,可以執(zhí)行 Scan 的 startKey 和 endKey,RowFilter 可以更精確的過(guò)濾。
列族過(guò)濾器 FamilyFilter
Scan scan = new Scan();
Filter filter = new FamilyFilter(CompareFilter.CompareOp.LESS,
new BinaryComparator(Bytes.toBytes("cf-d")));
scan.setFilter(filter);
與 RowFilter 類似,區(qū)別是比較列族,而不是比較行鍵。當(dāng) HBase 表有多個(gè)列族時(shí),可以用來(lái)篩選不同列族中的列。
列名過(guò)濾器 QualifierFilter
Scan scan = new Scan();
Filter filter = new QualifierFilter(CompareFilter.CompareOp.EQUAL,
new BinaryComparator(Bytes.toBytes("col-1")));
scan.setFilter(filter1);
根據(jù)列名進(jìn)行篩選。
值過(guò)濾器 ValueFilter
Scan scan = new Scan();
Filter filter = new ValueFilter(CompareFilter.CompareOp.NOT_EQUAL,
new SubstringComparator("abc"));
scan.setFilter(filter);
篩選特定值的單元格,可以與 RegexStringComparator 搭配使用,完成復(fù)雜的篩選。
不同的比較器,只能與部分比較運(yùn)算符搭配,例如 SubstringComparator 只能使用 EQUAL 或 NOT_EQUAL
參考列過(guò)濾器 DependentColumnFilter
Scan scan = new Scan();
Filter filter = new DependentColumnFilter(Bytes.toBytes("cf-d"),
Bytes.toBytes("col-1"),
"false",
CompareOp.EQUAL,
new BinaryComparator(Bytes.toBytes("val-1"))))
scan.setFilter(filter);
一種更復(fù)雜的過(guò)濾器,不止簡(jiǎn)單的通過(guò)用戶指定的信息篩選數(shù)據(jù)。允許指定一個(gè)參考列或引用列,使用參考列控制其他列的過(guò)濾。該過(guò)濾器會(huì)使用參考列的時(shí)間戳,并在過(guò)濾時(shí)包括所有與引用時(shí)間戳相同的列。
參考列過(guò)濾器相當(dāng)于一個(gè) ValueFilter 和一個(gè)時(shí)間戳過(guò)濾器的組合。
專用過(guò)濾器
單列值過(guò)濾器 SingleColumnValueFilter
使用某一列的值,決定一行數(shù)據(jù)是否被過(guò)濾。
Scan scan = new Scan();
SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("cf-d"),
Bytes.toBytes("col-5"),
CompareFilter.CompareOp.NOT_EQUAL,
new SubstringComparator("val-1"));
filter.setFilterIfMissing(true); // 如果不設(shè)置為 true,那些不包含指定列的行也會(huì)返回
scan.setFilter(filter);
對(duì)于不包含指定列的行數(shù)據(jù),通過(guò) setFilterIfMissing() 決定是否返回。
單列值排除器 SingleColumnValueExcludeFilter
繼承自 SingleColumnValueFilter,實(shí)現(xiàn)的與單列值過(guò)濾器相反的語(yǔ)義。
行前綴過(guò)濾器 PrefixFilter
Scan scan = new Scan();
Filter filter = new PrefixFilter(Bytes.toBytes("row1"));
scan.setFilter(filter);
基于行鍵(Rowkey)的前綴過(guò)濾行數(shù)據(jù)。Scan 操作以字典序查找,當(dāng)行鍵大于前綴時(shí),Scan 結(jié)束。
列前綴過(guò)濾器 ColumnPrefixFilter
Scan scan = new Scan();
Filter filter = new ColumnPrefixFilter(Bytes.toBytes("col-"));
scan.setFilter(filter);
通過(guò)對(duì)列名稱的前綴匹配過(guò)濾,返回的結(jié)果只包含滿足過(guò)濾器的列。
分頁(yè)過(guò)濾器 PageFilter
byte[] lastRow = null;
Filter filter = new PageFilter(10);
while(true) {
int rowCount = 0;
Scan scan = new Scan();
scan.setFilter(filter);
scan.setStartRow(lastRow);
ResultScanner resultScanner = table.getScanner(scan);
Iterator<Result> resultIterator = resultScanner.iterator();
while (resultIterator.hasNext()) {
Result result = resultIterator.next();
// ...
lastRow = result.getRow(); // 記錄最后一行的rowkey
rowCount++; // 記錄本頁(yè)行數(shù)
}
if(rowCount <= 10) {
break;
}
}
使用該過(guò)濾器,對(duì)結(jié)果進(jìn)行按行分野,需要指定 pageSize 參數(shù),控制每頁(yè)返回的行數(shù),并設(shè)置 startRow 多次調(diào)用 getScanner(),感覺(jué)功能只適用于一些特殊場(chǎng)景,性能也并不高。
行鍵過(guò)濾器 KeyOnlyFilter
KeyOnlyFilter filter = new KeyOnlyFilter();
KeyOnlyFilter filter = new KeyOnlyFilter(true);
這個(gè) Filter 只會(huì)返回每行的行鍵+列簇+列,而不返回值(value),對(duì)不需要值的應(yīng)用場(chǎng)景來(lái)說(shuō),非常實(shí)用,減少了值的傳遞。構(gòu)造方法可以設(shè)置 lenAsValue 參數(shù)(默認(rèn) false),表示返回時(shí),value 設(shè)為原列值的長(zhǎng)度。
首次行鍵過(guò)濾器 FirstKeyOnlyFilter
FirstKeyOnlyFilter filter = new FirstKeyOnlyFilter();
這個(gè) Filter 僅僅返回每一行中的第一個(gè) cell 的值,可以用于高效的執(zhí)行行數(shù)統(tǒng)計(jì)操作,在掃描到第一個(gè) cell 時(shí),立即跳到下一行數(shù)據(jù),性能相比全表掃描得到提升。
包含結(jié)束的過(guò)濾器 InclusiveStopFilter
Filter filter = new InclusiveStopFilter(Bytes.toBytes("uid-10"));
一般的掃描結(jié)果中,設(shè)置一個(gè)開(kāi)始行鍵和一個(gè)終止行鍵,是前閉后開(kāi)區(qū)間,不包含結(jié)束行,使用這個(gè)過(guò)濾器時(shí)將結(jié)束行加入到結(jié)果中。
時(shí)間戳過(guò)濾器 TimestampsFilter
Filter filter = new TimestampsFilter(Arrays.asList(5L, 10L, 15L));
Scan scan1 = new Scan();
scan1.setMaxVersions(3)
scan1.setFilter(filter);
Scan scan2 = new Scan();
scan2.setMaxVersions(3)
scan2.setFilter(filter);
scan2.setTimeRange(8, 12);
當(dāng)需要在掃描結(jié)果中對(duì)版本進(jìn)行細(xì)粒度控制時(shí),可以使用這個(gè) Filter 傳入一個(gè)時(shí)間戳集合,對(duì)時(shí)間進(jìn)行限制,只會(huì)返回與指定時(shí)間戳相同的版本數(shù)據(jù),并且與設(shè)置時(shí)間戳范圍共同使用。
列計(jì)數(shù)過(guò)濾器 ColumnCountGetFilter
Filter filter = new ColumnCountGetFilter(10);
使用這個(gè)過(guò)濾器,限制每行最多返回多少列。注意當(dāng)一行的列數(shù)達(dá)到設(shè)定的最大值,過(guò)濾器會(huì)停止 Scan 操作,所以不適合全表掃描,適合在 Get 方法中使用。
列分頁(yè)過(guò)濾器 ColumnPaginationFilter
Filter filter = new ColumnPaginationFilter(10,5);
與 PageFilter 類似,可以對(duì)一行的所有列進(jìn)行分也,需要傳入偏移量 offset 和返回?cái)?shù)量 limit。
隨機(jī)行過(guò)濾器 RandomRowFilter
Filter filter = new RandomRowFilter(0.5F);
這個(gè) Filter 可以使結(jié)果中包含隨機(jī)行,參數(shù) chance 取值在 0.0 到 1.0 之間,表示隨機(jī)取行數(shù)的比例,每一行會(huì)調(diào)用 Random.nextFloat() 與 chance 比較來(lái)確定是否被過(guò)濾。
附加過(guò)濾器
普通過(guò)濾器可以提供對(duì)返回結(jié)果的篩選限制,一些額外的控制可以附加在過(guò)濾器上
跳轉(zhuǎn)過(guò)濾器 SkipFilter
Scan scan = new Scan();
Filter filter1 = new ValueFilter(CompareFilter.CompareOp.NOT_EQUAL,
new BinaryComparator(Bytes.toBytes("val-0")));
Filter filter2 = new SkipFilter(filter1);
包裝了用戶的一個(gè)過(guò)濾器,當(dāng)過(guò)濾器發(fā)現(xiàn)某一行的一列需要過(guò)濾時(shí),整行數(shù)據(jù)都被過(guò)濾掉。上面的例子是,使用 SkipFilter 和 ValueFilter 組合,獲取不等于指定列值的行,同時(shí)過(guò)濾掉其他不符合條件的行(即只要有一行中一列的值等于“val-0”,就會(huì)被過(guò)濾)。
全匹配過(guò)濾 WhileMatchFilter
Scan scan = new Scan();
Filter filter1 = new ValueFilter(CompareFilter.CompareOp.NOT_EQUAL,
new BinaryComparator(Bytes.toBytes("val-0")));
Filter filter2 = new WhileMatchFilter(filter1);
與SkipFilter 相似,不過(guò)當(dāng)一條數(shù)據(jù)被過(guò)濾掉時(shí),會(huì)停止 Scan 操作。可以用來(lái)檢查全表數(shù)據(jù)中,是否有某些數(shù)據(jù)不符合條件。
多種過(guò)濾條件的使用方法
通過(guò) FilterList 實(shí)例可以提供多個(gè)過(guò)濾器共同使用的功能。并且可以指定對(duì)多個(gè)過(guò)濾器的過(guò)濾結(jié)果如何組合。
FilterList 構(gòu)造函數(shù)和方法
FilterList(List<Filter> rowFilters)
FilterList(Operator operator)
FilterList(Operator operator, List<Filter> rowFilters)
void addFilter(Filter filter)
FilterList.Operator 決定了過(guò)濾器集合 List<Filter> rowFilters 的組合結(jié)果,可選值:
MUST_PASS_ALL // 當(dāng)所有過(guò)濾器都允許包含這個(gè)值時(shí),才會(huì)加入到結(jié)果中
MUST_PASS_ONE // 只需要有一個(gè)過(guò)濾器允許包含這個(gè)值時(shí),就會(huì)加入到結(jié)果中
代碼示例:
Filter filter1 = new ...;
Filter filter2 = new ...;
Filter filter3 = new ...;
FilterList filterList = new FilterList(Arrays.asList(filter1, filter2, filter3));
Scan scan = new Scan();
scan.setFilter(filterList);
References:
《HBase 權(quán)威指南》