HBase的分頁-PageFilter
使用PageFilter分頁效率比較低,應為每次都需要掃描前面的資料,直到掃描到所需要查的資料,但是查詢下一頁的時候可以直接利用上一頁的rowkey來直接查出
Filter是定義每次scan得出多少條記錄,
下面看用PageFilter實現分頁的(最好使用rowksy,不建議使用過濾器,過濾器效率太低,設計表的時候設計一個好的rowkey可以帶來好多的便利的條件)
程式碼記錄:
package hbasepage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.FilterList;
import org.apache.hadoop.hbase.filter.PageFilter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
public class Pager {
public static Configuration configuration;
static {
configuration = HBaseConfiguration.create();
configuration.set("hbase.zookeeper.property.clientPort", "2181");
configuration.set("hbase.zookeeper.quorum",
"192.168.10.24,192.168.10.29,192.168.10.64");
configuration.set("hbase.master", "192.168.10.120:60000");
}
private String tableName;
private static HTable hTable;
private static String startRow = null;
private static List list = null;
public Pager(String tableName) {
try {
this.hTable = new HTable(configuration, tableName.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static List getLast(int pageNum, int pageSize){
getPage(pageNum-1,pageSize);
return null;
}
/**
* 取得下一頁 這個類是接著getPage來用
* @param pageSize 分頁的大小
* @return 返回分頁資料
*/
public static List getNext(int pageSize) throws Exception{
Filter filter = new PageFilter(pageSize +1);
Scan scan = new Scan();
scan.setFilter(filter);
scan.setStartRow(startRow.getBytes());
ResultScanner result = hTable.getScanner(scan);
Iterator iterator = result.iterator();
list = new ArrayList<>();
int count = 0;
for(Result r:result){
count++;
if (count==pageSize + 1) {
startRow = new String(r.getRow());
scan.setStartRow(startRow.getBytes());
System.out.println("startRow" + startRow);
break;
}else{
list.add(r);
}
startRow = new String(r.getRow());
System.out.println(startRow);
//把 r的所有的列都取出來 key-value age-20
System.out.println(count);
}
return list;
}
// pageNum = 3 pageSize = 10
public static void getPage(int pageNum, int pageSize) {
System.out.println("hahha");
// int pageNow = 0;
// TODO 這個filter到底是幹嘛的?
Filter page = new PageFilter(pageSize + 1);
int totalSize = pageNum * pageSize;
Scan scan = new Scan();
scan.setFilter(page);
//pageNum = 3 需要掃描3頁
for (int i = 0; i < pageNum; i++) {
try {
ResultScanner rs = hTable.getScanner(scan);
int count = 0;
for (Result r : rs) {
count++;
if (count==pageSize + 1) {
startRow = new String(r.getRow());
scan.setStartRow(startRow.getBytes());
System.out.println("startRow" + startRow);
break;
}
startRow = new String(r.getRow());
System.out.println(startRow);
//把 r的所有的列都取出來 key-value age-20
for (KeyValue keyValue : r.list()) {
System.out.println("列:"
+ new String(keyValue.getQualifier()) + "====值:"
+ new String(keyValue.getValue()));
}
System.out.println(count);
}
if (count < pageSize) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
下面寫一點常用的fiter過濾器
HBase為篩選資料提供了一組過濾器,通過這個過濾器可以在HBase中的資料的多個維度(行,列,資料版本)上進行對資料的篩選操作,也就是說過濾器最終能夠篩選的資料能夠細化到具體的一個儲存單元格上(由行鍵,列明,時間戳定位)。通常來說,通過行鍵,值來篩選資料的應用場景較多。
- RowFilter:篩選出匹配的所有的行,對於這個過濾器的應用場景,是非常直觀的:使用BinaryComparator可以篩選出具有某個行鍵的行,或者通過改變比較運算子(下面的例子中是CompareFilter.CompareOp.EQUAL)來篩選出符合某一條件的多條資料,以下就是篩選出行鍵為row1的一行資料:
Filter rf = new RowFilter(CompareFilter.CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes(“row1”))); // OK 篩選出匹配的所有的行
- PrefixFilter:篩選出具有特定字首的行鍵的資料。這個過濾器所實現的功能其實也可以由RowFilter結合RegexComparator來實現,不過這裡提供了一種簡便的使用方法,以下過濾器就是篩選出行鍵以row為字首的所有的行:
Filter pf = new PrefixFilter(Bytes.toBytes(“row”)); // OK 篩選匹配行鍵的字首成功的行
- KeyOnlyFilter:這個過濾器唯一的功能就是隻返回每行的行鍵,值全部為空,這對於只關注於行鍵的應用場景來說非常合適,這樣忽略掉其值就可以減少傳遞到客戶端的資料量,能起到一定的優化作用:
Filter kof = new KeyOnlyFilter(); // OK 返回所有的行,但值全是空
- RandomRowFilter:從名字上就可以看出其大概的用法,本過濾器的作用就是按照一定的機率(<=0會過濾掉所有的行,>=1會包含所有的行)來返回隨機的結果集,對於同樣的資料集,多次使用同一個RandomRowFilter會返回不通的結果集,對於需要隨機抽取一部分資料的應用場景,可以使用此過濾器:
Filter rrf = new RandomRowFilter((float) 0.8); // OK 隨機選出一部分的行
- InclusiveStopFilter:掃描的時候,我們可以設定一個開始行鍵和一個終止行鍵,預設情況下,這個行鍵的返回是前閉後開區間,即包含起始行,單不包含中指行,如果我們想要同時包含起始行和終止行,那麼我們可以使用此過濾器:
Filter isf = new InclusiveStopFilter(Bytes.toBytes(“row1”)); // OK 包含了掃描的上限在結果之內
- FirstKeyOnlyFilter:如果你只想返回的結果集中只包含第一列的資料,那麼這個過濾器能夠滿足你的要求。它在找到每行的第一列之後會停止掃描,從而使掃描的效能也得到了一定的提升:
Filter fkof = new FirstKeyOnlyFilter(); // OK 篩選出第一個每個第一個單元格
- ColumnPrefixFilter:顧名思義,它是按照列名的字首來篩選單元格的,如果我們想要對返回的列的字首加以限制的話,可以使用這個過濾器:
Filter cpf = new ColumnPrefixFilter(Bytes.toBytes(“qual1”)); // OK 篩選出字首匹配的列
- ValueFilter:按照具體的值來篩選單元格的過濾器,這會把一行中值不能滿足的單元格過濾掉,如下面的構造器,對於每一行的一個列,如果其對應的值不包含ROW2_QUAL1,那麼這個列就不會返回給客戶端:
Filter vf = new ValueFilter(CompareFilter.CompareOp.EQUAL, new SubstringComparator(“ROW2_QUAL1”)); // OK 篩選某個(值的條件滿足的)特定的單元格
- ColumnCountGetFilter:這個過濾器來返回每行最多返回多少列,並在遇到一行的列數超過我們所設定的限制值的時候,結束掃描操作:
Filter ccf = new ColumnCountGetFilter(2); // OK 如果突然發現一行中的列數超過設定的最大值時,整個掃描操作會停止
- SingleColumnValueFilter:用一列的值決定這一行的資料是否被過濾。在它的具體物件上,可以呼叫setFilterIfMissing(true)或者setFilterIfMissing(false),預設的值是false,其作用是,對於咱們要使用作為條件的列,如果這一列本身就不存在,那麼如果為true,這樣的行將會被過濾掉,如果為false,這樣的行會包含在結果集中。
SingleColumnValueFilter scvf = new SingleColumnValueFilter(
Bytes.toBytes(“colfam1”),
Bytes.toBytes(“qual2”),
CompareFilter.CompareOp.NOT_EQUAL,
new SubstringComparator(“BOGUS”));
scvf.setFilterIfMissing(false);
scvf.setLatestVersionOnly(true); // OK
- SingleColumnValueExcludeFilter:這個與10種的過濾器唯一的區別就是,作為篩選條件的列的不會包含在返回的結果中。
- SkipFilter:這是一種附加過濾器,其與ValueFilter結合使用,如果發現一行中的某一列不符合條件,那麼整行就會被過濾掉:
Filter skf = new SkipFilter(vf); // OK 發現某一行中的一列需要過濾時,整個行就會被過濾掉
- WhileMatchFilter:這個過濾器的應用場景也很簡單,如果你想要在遇到某種條件資料之前的資料時,就可以使用這個過濾器;當遇到不符合設定條件的資料的時候,整個掃描也就結束了:
Filter wmf = new WhileMatchFilter(rf); // OK 類似於Python itertools中的takewhile
- FilterList:用於綜合使用多個過濾器。其有兩種關係:FilterList.Operator.MUST_PASS_ONE和FilterList.Operator.MUST_PASS_ALL,預設的是FilterList.Operator.MUST_PASS_ALL,顧名思義,它們分別是AND和OR的關係,並且FilterList可以巢狀使用FilterList,使我們能夠表達更多的需求:
List filters = new ArrayList();
filters.add(rf);
filters.add(vf);
FilterList fl = new FilterList(FilterList.Operator.MUST_PASS_ALL, filters); // OK 綜合使用多個過濾器, AND 和 OR 兩種關係
以上,是對於HBase內建的過濾器的部分總結