ToB企服应用市场:ToB评测及商务社交产业平台

标题: 过滤器 [打印本页]

作者: 铁佛    时间: 2022-8-9 14:40
标题: 过滤器
 

HBase 的基本 API,包括增、删、改、查等。 增、删都是相对简单的操作,与传统的 RDBMS 相比,这里的查询操作略显苍白,只能根据特性的行键进行查询(Get)或者根据行键的范围来查询(Scan)。 HBase 不仅提供了这些简单的查询,而且提供了更加高级的过滤器(Filter)来查询。
 
过滤器可以根据列族、列、版本等更多的条件来对数据进行过滤,
基于 HBase 本身提供的三维有序(行键,列,版本有序),这些过滤器可以高效地完成查询过滤的任务,带有过滤器条件的 RPC (远程服务)查询请求会把过滤器分发到各个 RegionServer(这是一个服务端过滤器),这样也可以降低网络传输的压力。
使用过滤器至少需要两类参数:
一类是抽象的操作符,另一类是比较器
作用

比较过滤器

所有比较过滤器均继承自 CompareFilter。创建一个比较过滤器需要两个参数,分别是比较运算符比较器实例
  1. public CompareFilter(final CompareOp compareOp,final ByteArrayComparable comparator) {
  2.    this.compareOp = compareOp;
  3.    this.comparator = comparator;
  4.   }
复制代码
比较运算符

常见的六大比较过滤器

BinaryComparator

按字节索引顺序比较指定字节数组,采用Bytes.compareTo(byte[])
BinaryPrefixComparator(前缀比较器)

通BinaryComparator,只是比较左端前缀的数据是否相同
NullComparator

判断给定的是否为空
BitComparator

按位比较
RegexStringComparator

提供一个正则的比较器,仅支持 EQUAL 和非EQUAL
SubstringComparator

判断提供的子串是否出现在中
代码演示

rowKey过滤器:RowFilter 行键过滤器

通过RowFilter与BinaryComparator过滤比rowKey 1500100010小的所有值出来
  1.    /**
  2.     *  行键过滤器
  3.     *  通过RowFilter与BinaryComparator过滤比rowKey 1500100010小的所有值出来
  4.     */
  5.    @Test
  6.    public void RowFilter1(){
  7.        try {
  8.            //获取表的实例
  9.            HTableInterface students = conn.getTable("students");
  10.            BinaryComparator binaryComparator = new BinaryComparator("1500100010".getBytes());
  11.            //创建一个行键过滤器的对象
  12.            RowFilter rowFilter = new RowFilter(CompareFilter.CompareOp.LESS, binaryComparator);
  13.            Scan scan = new Scan();
  14.            scan.setFilter(rowFilter);//把过滤器传给扫描到的对象
  15.            ResultScanner scanner = students.getScanner(scan);
  16.            print(scanner);
  17.        } catch (IOException e) {
  18.            e.printStackTrace();
  19.        }
  20.    }
  21.    /**
  22.     *      专门用来打印数据的方法
  23.     */
  24.    public void print(ResultScanner scanner) throws IOException {
  25.        Result rs = null;
  26.        while ((rs = scanner.next()) != null) {
  27.            String id = Bytes.toString(rs.getRow());
  28. //                List<Cell> cells = rs.listCells();
  29. //                System.out.print("id:" + id);
  30. //                System.out.print("\t");
  31. //                for (Cell cell : cells) {
  32. ////                String s = Bytes.toString(cell.getValue());
  33. //                    String col = Bytes.toString(CellUtil.cloneQualifier(cell));
  34. //                    String s = Bytes.toString(CellUtil.cloneValue(cell));
  35. //                    System.out.print(col + ":" + s);
  36. //                    System.out.print("\t");
  37. //                }
  38. //                System.out.println();
  39.            String name = Bytes.toString(rs.getValue("info".getBytes(), "name".getBytes()));
  40.            String age = Bytes.toString(rs.getValue("info".getBytes(), "age".getBytes()));
  41.            String gender = Bytes.toString(rs.getValue("info".getBytes(), "gender".getBytes()));
  42.            String clazz = Bytes.toString(rs.getValue("info".getBytes(), "clazz".getBytes()));
  43.            System.out.println("学号:" + id + ",姓名:" + name + ",年龄:" + age + ",性别:" + gender + ",班级:" + clazz);
  44.        }
  45.    }
复制代码
列簇过滤器:FamilyFilter

通过FamilyFilter与SubstringComparator查询列簇名包含in的所有列簇下面的数据
  1.    /**
  2.     *      列簇过滤器案例1:通过FamilyFilter与SubstringComparator查询列簇名包含in的所有列簇下面的数据
  3.     */
  4.    @Test
  5.    public void FamilyFilter1(){
  6.        try {
  7.            //获取表的实例
  8.            HTableInterface students = conn.getTable("students");
  9.            //创建一个比较器对象
  10.            //只要列簇名中包含了in,就把该列簇下的所有列查询出来
  11.            SubstringComparator substringComparator = new SubstringComparator("in");
  12.            //创建列簇过滤器
  13.            FamilyFilter familyFilter = new FamilyFilter(CompareFilter.CompareOp.EQUAL, substringComparator);
  14.            Scan scan = new Scan();
  15.            scan.setFilter(familyFilter);//把过滤器传给扫描到的对象
  16.            //获取数据
  17.            ResultScanner scanner = students.getScanner(scan);
  18.            print(scanner);
  19.        } catch (IOException e) {
  20.            e.printStackTrace();
  21.        }
  22.    }
复制代码
通过FamilyFilter与 BinaryPrefixComparator 过滤出列簇以i开头的列簇下的所有数据
  1.    /**
  2.     * 列簇过滤器案例2:通过FamilyFilter与 BinaryPrefixComparator 过滤出列簇以i开头的列簇下的所有数据
  3.     *
  4.     */
  5.    @Test
  6.    public void FamilyFilter2(){
  7.        try {
  8.            //获取表的实例
  9.            HTableInterface students = conn.getTable("students");
  10.            //创建前缀比较器
  11.            BinaryPrefixComparator binaryPrefixComparator = new BinaryPrefixComparator("i".getBytes());
  12.            //创建列簇过滤器
  13.            FamilyFilter familyFilter = new FamilyFilter(CompareFilter.CompareOp.EQUAL, binaryPrefixComparator);
  14.            Scan scan = new Scan();
  15.            scan.setFilter(familyFilter);
  16.            ResultScanner scanner = students.getScanner(scan);
  17.            print(scanner);
  18.        } catch (IOException e) {
  19.            e.printStackTrace();
  20.        }
  21.    }
复制代码
列过滤器:QualifierFilter

通过QualifierFilter与SubstringComparator查询列名包含ge的列的值
  1.    /**
  2.     * 列过滤器案例1:通过QualifierFilter与SubstringComparator查询列名包含ge的列的值
  3.     *
  4.     */
  5.    @Test
  6.    public void QualifierFilter1(){
  7.        try {
  8.            //获取表的实例
  9.            HTableInterface students = conn.getTable("students");
  10.            //创建包含比较器
  11.            //age
  12.            //gender
  13.            SubstringComparator substringComparator = new SubstringComparator("ge");
  14.            //创建一个列过滤器
  15.            QualifierFilter qualifierFilter = new QualifierFilter(CompareFilter.CompareOp.EQUAL, substringComparator);
  16.            Scan scan = new Scan();
  17.            scan.setFilter(qualifierFilter);
  18.            ResultScanner scanner = students.getScanner(scan);
  19.            print(scanner);
  20.        } catch (IOException e) {
  21.            e.printStackTrace();
  22.        }
  23.    }
复制代码
过滤出列的名字中 包含 "am" 所有的列 及列的值
  1.    /**
  2.     *
  3.     * 列过滤器案例2:通过QualifierFilter与SubstringComparator查询列名包含ge的列的值
  4.     */
  5.    @Test
  6.    public void QualifierFilter2(){
  7.        try {
  8.            //获取表的实例
  9.            HTableInterface students = conn.getTable("students");
  10.            SubstringComparator substringComparator = new SubstringComparator("am");
  11.            //创建列过滤器
  12.            QualifierFilter qualifierFilter = new QualifierFilter(CompareFilter.CompareOp.EQUAL, substringComparator);
  13.            Scan scan = new Scan();
  14.            scan.setFilter(qualifierFilter);
  15.            ResultScanner scanner = students.getScanner(scan);
  16.            print(scanner);
  17.        } catch (IOException e) {
  18.            e.printStackTrace();
  19.        }
  20.    }
复制代码
列值过滤器:ValueFilter

通过ValueFilter与BinaryPrefixComparator过滤出所有的cell中值以 "张" 开头的学生
  1.    /**
  2.     * 列值过滤器案例1:通过ValueFilter与BinaryPrefixComparator过滤出所有的cell中值以 "张" 开头的学生
  3.     */
  4.    @Test
  5.    public void ValueFilter1() {
  6.        try {
  7.            //获取表的实例
  8.            HTableInterface students = conn.getTable("students");
  9.            //创建前缀比较器
  10.            BinaryPrefixComparator binaryPrefixComparator = new BinaryPrefixComparator("张".getBytes());
  11.            //创建列值过滤器的对象
  12.            ValueFilter valueFilter = new ValueFilter(CompareFilter.CompareOp.EQUAL, binaryPrefixComparator);
  13.            Scan scan = new Scan();
  14.            scan.setFilter(valueFilter);
  15.            ResultScanner scanner = students.getScanner(scan);
  16.            //因为ResultScanner类继承了迭代器
  17.            //使用增强for循环遍历
  18. //            for (Result rs : scanner) {
  19. //                String id = Bytes.toString(rs.getRow());
  20. //                System.out.println("当前行的rowkey为:" + id);
  21. //                //继续增强for循环得到每一行中的每一个单元格(列)
  22. //                //获取一行中的所有单元格
  23. //                for (Cell cell : rs.listCells()) {
  24. //                    //获取该单元格属于的列簇
  25. //                    String family = Bytes.toString(CellUtil.cloneFamily(cell));
  26. //                    //获取该单元格的列名
  27. //                    String colName = Bytes.toString(CellUtil.cloneQualifier(cell));
  28. //                    //获取该单元格的列值
  29. //                    String value = Bytes.toString(CellUtil.cloneValue(cell));
  30. //                    System.out.println(family + ":" + colName + "的值为:" + value);
  31. //                }
  32. //            }
  33.            print(scanner);
  34.        } catch (IOException e) {
  35.            e.printStackTrace();
  36.        }
  37.    }
复制代码
过滤出文科的学生,只会返回以文科开头的数据列,其他列的数据不符合条件,不会返回
  1.    /**
  2.     *      列值过滤器案例2:> 过滤出文科的学生,只会返回以文科开头的数据列,其他列的数据不符合条件,不会返回
  3.     */
  4.    @Test
  5.    public void ValueFilter12(){
  6.        try {
  7.            //获取表的实例
  8.            HTableInterface students = conn.getTable("students");
  9.            //创建正则比较器
  10.            RegexStringComparator regexStringComparator = new RegexStringComparator("^文科.*");
  11.            //创建列值过滤器
  12.            ValueFilter valueFilter = new ValueFilter(CompareFilter.CompareOp.EQUAL, regexStringComparator);
  13.            Scan scan = new Scan();
  14.            scan.setFilter(valueFilter);
  15.            ResultScanner scanner = students.getScanner(scan);
  16.            print(scanner);
  17.        } catch (IOException e) {
  18.            e.printStackTrace();
  19.        }
  20.    }
复制代码
专用过滤器

单列值过滤器:SingleColumnValueFilter

SingleColumnValueFilter会返回满足条件的cell所在行的所有cell的值(即会返回一行数据)
通过SingleColumnValueFilter与查询文科班所有学生信息
  1.    /**
  2.     * 单列值过滤器
  3.     * SingleColumnValueFilter会返回满足条件的cell所在行的所有cell的值(即会返回一行数据)
  4.     *
  5.     * 通过SingleColumnValueFilter与查询文科班所有学生信息
  6.     */
  7.    @Test
  8.    public void SingleColumnValueFilter(){
  9.        try {
  10.            //获取表的实例
  11.            HTableInterface students = conn.getTable("students");
  12.            //创建一个正则比较器
  13.            RegexStringComparator regexStringComparator = new RegexStringComparator("^文科.*");
  14.            //创建单列值过滤器对象
  15.            SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(
  16.                    "info".getBytes(),
  17.                    "clazz".getBytes(),
  18.                    CompareFilter.CompareOp.EQUAL,
  19.                    regexStringComparator
  20.            );
  21.            Scan scan = new Scan();
  22.            scan.setFilter(singleColumnValueFilter);
  23.            ResultScanner scanner = students.getScanner(scan);
  24.            print(scanner);
  25.        } catch (IOException e) {
  26.            e.printStackTrace();
  27.        }
  28.    }
  29.    /**
  30.     * 专门用来打印数据的方法
  31.     */
  32.    public void print(ResultScanner scanner) throws IOException {
  33.        Result rs = null;
  34.        while ((rs = scanner.next()) != null) {
  35.            String id = Bytes.toString(rs.getRow());
  36.            List<Cell> cells = rs.listCells();
  37.            System.out.print("id:" + id);
  38.            System.out.print("\t");
  39.            for (Cell cell : cells) {
  40. //                String s = Bytes.toString(cell.getValue());
  41.                String col = Bytes.toString(CellUtil.cloneQualifier(cell));
  42.                String s = Bytes.toString(CellUtil.cloneValue(cell));
  43.                System.out.print(col + ":" + s);
  44.                System.out.print("\t");
  45.            }
  46.            System.out.println();
  47. //            String name = Bytes.toString(rs.getValue("info".getBytes(), "name".getBytes()));
  48. //            String age = Bytes.toString(rs.getValue("info".getBytes(), "age".getBytes()));
  49. //            String gender = Bytes.toString(rs.getValue("info".getBytes(), "gender".getBytes()));
  50. //            String clazz = Bytes.toString(rs.getValue("info".getBytes(), "clazz".getBytes()));
  51. //            System.out.println("学号:" + id + ",姓名:" + name + ",年龄:" + age + ",性别:" + gender + ",班级:" + clazz);
  52.        }
  53.    }
复制代码
列值排除过滤器:SingleColumnValueExcludeFilter

与SingleColumnValueFilter相反,会排除掉指定的列,其他的列全部返回
通过SingleColumnValueExcludeFilter与BinaryComparator查询文科一班所有学生信息,最终不返回clazz列
  1.    /**
  2.     * 列值排除过滤器
  3.     * 与SingleColumnValueFilter相反,会排除掉指定的列,其他的列全部返回
  4.     *
  5.     * 通过SingleColumnValueExcludeFilter与BinaryComparator查询文科一班所有学生信息,最终不返回clazz列
  6.     */
  7.    @Test
  8.    public void SingleColumnValueExcludeFilter(){
  9.        try {
  10.            //获取表的实例
  11.            HTableInterface students = conn.getTable("students");
  12.            //创建一个二进制比较器
  13.            BinaryComparator binaryComparator = new BinaryComparator("文科一班".getBytes());
  14.            //创建一个列值排除过滤器
  15.            SingleColumnValueExcludeFilter singleColumnValueExcludeFilter = new SingleColumnValueExcludeFilter(
  16.                    "info".getBytes(),
  17.                    "clazz".getBytes(),
  18.                    CompareFilter.CompareOp.EQUAL,
  19.                    binaryComparator
  20.            );
  21.            Scan scan = new Scan();
  22.            scan.setFilter(singleColumnValueExcludeFilter);
  23.            ResultScanner scanner = students.getScanner(scan);
  24.            print(scanner);
  25.        } catch (IOException e) {
  26.            e.printStackTrace();
  27.        }
  28.    }
复制代码
rowkey前缀过滤器:PrefixFilter

通过PrefixFilter查询以150010008开头的所有前缀的rowkey
  1.    /**
  2.     * rowkey前缀过滤器
  3.     *
  4.     * 通过PrefixFilter查询以150010008开头的所有前缀的rowkey
  5.     */
  6.    @Test
  7.    public void PrefixFilter(){
  8.        try {
  9.            //获取表的实例
  10.            HTableInterface students = conn.getTable("students");
  11.            //创建rowkey前缀过滤器
  12.            PrefixFilter prefixFilter = new PrefixFilter("150010008".getBytes());
  13.            Scan scan = new Scan();
  14.            scan.setFilter(prefixFilter);
  15.            ResultScanner scanner = students.getScanner(scan);
  16.            print2(scanner);
  17.        } catch (IOException e) {
  18.            e.printStackTrace();
  19.        }
  20.    }
复制代码
分页过滤器PageFilter

通过PageFilter查询三页的数据,每页10条
使用PageFilter分页效率比较低,每次都需要扫描前面的数据,直到扫描到所需要查的数据
可设计一个合理的rowkey来实现分页需求
  1. # 注意事项:
  2. 客户端进行分页查询,需要传递 startRow(起始 RowKey),知道起始 startRow 后,就可以返回对应的 pageSize 行数据。这里唯一的问题就是,对于第一次查询,显然 startRow 就是表格的第一行数据,但是之后第二次、第三次查询我们并不知道 startRow,只能知道上一次查询的最后一条数据的 RowKey(简单称之为 lastRow)。
  3. 我们不能将 lastRow 作为新一次查询的 startRow 传入,因为 scan 的查询区间是[startRow,endRow) ,即前闭后开区间,这样 startRow 在新的查询也会被返回,这条数据就重复了。
  4. 同时在不使用第三方数据库存储 RowKey 的情况下,我们是无法通过知道 lastRow 的下一个 RowKey 的,因为 RowKey 的设计可能是连续的也有可能是不连续的。
  5. 由于 Hbase 的 RowKey 是按照字典序进行排序的。这种情况下,就可以在 lastRow 后面加上 0 ,作为 startRow 传入,因为按照字典序的规则,某个值加上 0 后的新值,在字典序上一定是这个值的下一个值,对于 HBase 来说下一个 RowKey 在字典序上一定也是等于或者大于这个新值的。
  6. 所以最后传入 lastRow+0,如果等于这个值的 RowKey 存在就从这个值开始 scan,否则从字典序的下一个 RowKey 开始 scan。
  7. 25 个字母以及数字字符,字典排序如下:
  8. '0' < '1' < '2' < ... < '9' < 'a' < 'b' < ... < 'z'
复制代码
需要注意的是在多台 Regin Services 上执行分页过滤的时候,由于并行执行的过滤器不能共享它们的状态和边界,所以有可能每个过滤器都会在完成扫描前获取了 PageCount 行的结果,这种情况下会返回比分页条数更多的数据,分页过滤器就有失效的可能。
[code]    /**     * 分页过滤器     * 通过PageFilter查询三页的数据,每页10条     */​    @Test    public void PageFilter() {        try {            //获取表的实例            HTableInterface students = conn.getTable("students");            //定义要查询的页数            int pageNum = 3;            //定义每页的条数            int pageSize = 10;            Scan scan = new Scan();​            //定义一开始的行            String current_page_start_row = "";​            for (int i = 1; i




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4