过滤器

查询大量数据时客户端过滤效率低下,表格存储支持配置过滤器在服务端按条件筛选数据,减少网络传输提升查询性能。

使用方式

表格存储提供三种过滤器类型,分别用于单列值判断、正则匹配和多条件组合。通过查询请求的setFilter方法设置过滤器实例,即可在服务端进行数据过滤,减少网络传输开销并提升查询效率。

  • SingleColumnValueFilter:单属性列值过滤器。判断单个属性列的值是否符合条件。

  • SingleColumnValueRegexFilter:单属性列正则过滤器。将 String 类型的属性列按照指定的正则表达式匹配子字符串后转换成指定的数据类型,再判断是否符合条件。

  • CompositeColumnValueFilter:组合过滤器。将多个条件组合进行数据过滤。

单属性列值过滤器

public class SingleColumnValueFilter extends ColumnValueFilter

点击查看参数说明

名称

类型

说明

operator(必选)

CompareOperator

关系运算符,包括 EQUAL(等于)、NOT_EQUAL(不等于)、GREATER_THAN(大于)、GREATER_EQUAL(大于等于)、LESS_THAN(小于)、LESS_EQUAL(小于等于)。

columnName(必选)

String

待判断的属性列名称。

columnValue(必选)

ColumnValue

比较判断的值。

passIfMissing

boolean

行数据不包含判断的属性列时,是否返回该行,默认值为 true,即返回该行数据。

latestVersionsOnly

boolean

是否只判断最新的数据版本,默认值为 true,即当参考的属性列存在多个数据版本时,只判断最新的数据版本是否符合过滤条件。

单属性列正则过滤器

只有 String 类型的属性列支持使用正则过滤器。

public class SingleColumnValueRegexFilter extends ColumnValueFilter

参数说明

名称

类型

说明

operator(必选)

CompareOperator

关系运算符,包括 EQUAL(等于)、NOT_EQUAL(不等于)、GREATER_THAN(大于)、GREATER_EQUAL(大于等于)、LESS_THAN(小于)、LESS_EQUAL(小于等于)。

columnName(必选)

String

待判断的属性列名称。

columnValue(必选)

ColumnValue

比较判断的值。

regexRule(必选)

OptionalValue<RegexRule>

正则匹配规则,包含以下参数。

  • regex:正则表达式,用于匹配子字符串,长度不能超过 256 个字节。

    • 支持 Perl 正则表达式和单字节正则表达式。

    • 不支持中文正则匹配。

    • 支持分组语法,当正则表达式中包含分组时,将返回第一个匹配的子字符串。例如待匹配列值为 1aaa51bbb5,正则表达式为 1([a-z]+)5,返回结果为 aaa

  • castType:子字符串转换的类型,包括 VT_INTEGER(整型)、VT_DOUBLE(双精度浮点型) 和 VT_STRING(字符串)。

组合过滤器

最多支持 32 个条件的组合。

public class CompositeColumnValueFilter extends ColumnValueFilter

参数说明

名称

类型

说明

type(必选)

LogicOperator

逻辑运算符,包括 NOT(非)、AND(与)、OR(或)。

filters(必选)

List<ColumnValueFilter>

参与逻辑运算的过滤器,包括单属性列值过滤器单属性列正则过滤器,也可以是组合过滤器本身。

示例代码

运行代码前,请先在环境变量中配置访问凭证TABLESTORE_ACCESS_KEY_IDTABLESTORE_ACCESS_KEY_SECRET

单属性列值过滤器

以下示例代码以范围查询为例查询主键值为[row1, row3)的行数据,并在查询后进行过滤,返回col1属性列的值等于val1的行数据。

import com.alicloud.openservices.tablestore.SyncClient;
import com.alicloud.openservices.tablestore.core.ResourceManager;
import com.alicloud.openservices.tablestore.core.auth.CredentialsProvider;
import com.alicloud.openservices.tablestore.core.auth.DefaultCredentialProvider;
import com.alicloud.openservices.tablestore.core.auth.DefaultCredentials;
import com.alicloud.openservices.tablestore.core.auth.V4Credentials;
import com.alicloud.openservices.tablestore.model.Column;
import com.alicloud.openservices.tablestore.model.ColumnValue;
import com.alicloud.openservices.tablestore.model.GetRangeRequest;
import com.alicloud.openservices.tablestore.model.GetRangeResponse;
import com.alicloud.openservices.tablestore.model.PrimaryKeyBuilder;
import com.alicloud.openservices.tablestore.model.PrimaryKeyValue;
import com.alicloud.openservices.tablestore.model.RangeRowQueryCriteria;
import com.alicloud.openservices.tablestore.model.Row;
import com.alicloud.openservices.tablestore.model.filter.SingleColumnValueFilter;

public class SingleValueFilter {

    public static void main(String[] args) {

        // 从环境变量中获取访问凭证(需要配置TABLESTORE_ACCESS_KEY_ID和TABLESTORE_ACCESS_KEY_SECRET)
        final String accessKeyId = System.getenv("TABLESTORE_ACCESS_KEY_ID");
        final String accessKeySecret = System.getenv("TABLESTORE_ACCESS_KEY_SECRET");

        // TODO: 根据实例信息修改以下配置
        final String region = "cn-hangzhou"; // 填写实例所属的地域ID,例如 "cn-hangzhou"
        final String instanceName = "your_instance_name"; // 填写实例名称
        final String endpoint = "your_endpoint"; // 填写实例访问地址

        SyncClient client = null;
        try {
            // 构造凭证
            DefaultCredentials credentials = new DefaultCredentials(accessKeyId, accessKeySecret);
            V4Credentials credentialsV4 = V4Credentials.createByServiceCredentials(credentials, region);
            CredentialsProvider provider = new DefaultCredentialProvider(credentialsV4);

            // 创建客户端实例
            client = new SyncClient(endpoint, provider, instanceName, null, new ResourceManager(null, null));

            // 构造查询条件
            // TODO: 修改表名称
            RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria("test_table");
            // 设置查询起始主键
            // TODO: 修改主键名和值
            PrimaryKeyBuilder startKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
            startKeyBuilder.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row1"));
            rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startKeyBuilder.build());
            // 设置查询结束主键,返回结果不包含结束主键
            // TODO: 修改主键名和值
            PrimaryKeyBuilder endKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
            endKeyBuilder.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row3"));
            rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endKeyBuilder.build());
            // 设置查询版本
            rangeRowQueryCriteria.setMaxVersions(1);

            // 构造过滤器,条件为 col1 == "val1"
            // TODO: 修改过滤字段和值
            SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter("col1", SingleColumnValueFilter.CompareOperator.EQUAL, ColumnValue.fromString("val1"));
            rangeRowQueryCriteria.setFilter(singleColumnValueFilter);

            // 调用getRange方法查询数据
            GetRangeRequest getRangeRequest = new GetRangeRequest(rangeRowQueryCriteria);
            GetRangeResponse getRangeResponse = client.getRange(getRangeRequest);

            // 返回结果处理
            System.out.println("查询完成,结果统计:");
            System.out.println("RequestId: " + getRangeResponse.getRequestId());
            System.out.println("Read CU Cost: " + getRangeResponse.getConsumedCapacity().getCapacityUnit().getReadCapacityUnit());
            System.out.println("Write CU Cost: " + getRangeResponse.getConsumedCapacity().getCapacityUnit().getWriteCapacityUnit());
            
            // 输出查询结果
            if (getRangeResponse.getRows() != null && !getRangeResponse.getRows().isEmpty()) {
                System.out.println("共找到 " + getRangeResponse.getRows().size() + " 行符合条件的数据:");
                for (Row row : getRangeResponse.getRows()) {
                    // 获取并打印主键信息
                    // TODO: 根据主键数据类型进行修改
                    String primaryKeyInfo = row.getPrimaryKey().toString();
                    System.out.println("- 主键: " + primaryKeyInfo);

                    // 遍历并打印该行的所有属性列 (当MaxVersions=1时,每个Column即为最新版本)
                    if (row.getColumns() != null && row.getColumns().length > 0) {
                        System.out.println("  属性列:");
                        for (Column column : row.getColumns()) {
                            // 打印列的名称、值和时间戳
                            String columnName = column.getName();
                            // TODO: 根据属性列数据类型进行修改
                            String columnValue = column.getValue().toString();
                            long timestamp = column.getTimestamp();
                            System.out.println(
                                    String.format("    - %s: %s (版本时间戳: %d)", columnName, columnValue, timestamp)
                            );
                        }
                    } else {
                        System.out.println("  (该行没有属性列)");
                    }
                }
            } else {
                System.out.println("没有找到符合过滤条件的数据");
            }
            
            System.out.println("过滤查询操作执行完成");

        } catch (Exception e) {
            System.err.println("查询失败,详细信息如下:");
            e.printStackTrace();
        } finally {
            // 关闭客户端
            if (client != null) {
                client.shutdown();
            }
        }
    }
}

单属性列正则过滤器

以下示例代码以范围查询为例查询主键值为[row1, row3)的行数据,并在查询后进行正则匹配过滤,返回col1属性列的值满足正则表达式1([a-z]+)5且匹配到的子字符串为aaa的行数据。

import com.alicloud.openservices.tablestore.SyncClient;
import com.alicloud.openservices.tablestore.core.ResourceManager;
import com.alicloud.openservices.tablestore.core.auth.CredentialsProvider;
import com.alicloud.openservices.tablestore.core.auth.DefaultCredentialProvider;
import com.alicloud.openservices.tablestore.core.auth.DefaultCredentials;
import com.alicloud.openservices.tablestore.core.auth.V4Credentials;
import com.alicloud.openservices.tablestore.model.Column;
import com.alicloud.openservices.tablestore.model.ColumnValue;
import com.alicloud.openservices.tablestore.model.GetRangeRequest;
import com.alicloud.openservices.tablestore.model.GetRangeResponse;
import com.alicloud.openservices.tablestore.model.PrimaryKeyBuilder;
import com.alicloud.openservices.tablestore.model.PrimaryKeyValue;
import com.alicloud.openservices.tablestore.model.RangeRowQueryCriteria;
import com.alicloud.openservices.tablestore.model.Row;
import com.alicloud.openservices.tablestore.model.filter.RegexRule;
import com.alicloud.openservices.tablestore.model.filter.SingleColumnValueRegexFilter;

public class SingleValueRegexFilter {

    public static void main(String[] args) {

        // 从环境变量中获取访问凭证(需要配置TABLESTORE_ACCESS_KEY_ID和TABLESTORE_ACCESS_KEY_SECRET)
        final String accessKeyId = System.getenv("TABLESTORE_ACCESS_KEY_ID");
        final String accessKeySecret = System.getenv("TABLESTORE_ACCESS_KEY_SECRET");

        // TODO: 根据实例信息修改以下配置
        final String region = "cn-hangzhou"; // 填写实例所属的地域ID,例如 "cn-hangzhou"
        final String instanceName = "your_instance_name"; // 填写实例名称
        final String endpoint = "your_endpoint"; // 填写实例访问地址

        SyncClient client = null;
        try {
            // 构造凭证
            DefaultCredentials credentials = new DefaultCredentials(accessKeyId, accessKeySecret);
            V4Credentials credentialsV4 = V4Credentials.createByServiceCredentials(credentials, region);
            CredentialsProvider provider = new DefaultCredentialProvider(credentialsV4);

            // 创建客户端实例
            client = new SyncClient(endpoint, provider, instanceName, null, new ResourceManager(null, null));

            // 构造查询条件
            // TODO: 修改表名称
            RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria("test_table");
            // 设置查询起始主键
            // TODO: 修改主键名和值
            PrimaryKeyBuilder startKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
            startKeyBuilder.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row1"));
            rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startKeyBuilder.build());
            // 设置查询结束主键,返回结果不包含结束主键
            // TODO: 修改主键名和值
            PrimaryKeyBuilder endKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
            endKeyBuilder.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row3"));
            rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endKeyBuilder.build());
            // 设置查询版本
            rangeRowQueryCriteria.setMaxVersions(1);

            // 构造正则过滤器,条件为 cast<String>(reg(col1)) == "aaa"
            // TODO: 修改正则表达式、过滤字段和匹配值
            RegexRule regexRule = new RegexRule("1([a-z]+)5", RegexRule.CastType.VT_STRING);
            SingleColumnValueRegexFilter singleColumnValueRegexFilter = new SingleColumnValueRegexFilter("col1", regexRule, SingleColumnValueRegexFilter.CompareOperator.EQUAL, ColumnValue.fromString("aaa"));
            rangeRowQueryCriteria.setFilter(singleColumnValueRegexFilter);

            // 调用getRange方法查询行数据
            GetRangeRequest getRangeRequest = new GetRangeRequest(rangeRowQueryCriteria);
            GetRangeResponse getRangeResponse = client.getRange(getRangeRequest);

            // 返回结果处理
            System.out.println("正则过滤查询完成,结果统计:");
            System.out.println("RequestId: " + getRangeResponse.getRequestId());
            System.out.println("Read CU Cost: " + getRangeResponse.getConsumedCapacity().getCapacityUnit().getReadCapacityUnit());
            System.out.println("Write CU Cost: " + getRangeResponse.getConsumedCapacity().getCapacityUnit().getWriteCapacityUnit());
            
            // 输出查询结果
            if (getRangeResponse.getRows() != null && !getRangeResponse.getRows().isEmpty()) {
                System.out.println("共找到 " + getRangeResponse.getRows().size() + " 行符合正则过滤条件的数据:");
                for (Row row : getRangeResponse.getRows()) {
                    // 获取并打印主键信息
                    // TODO: 根据主键数据类型进行修改
                    String primaryKeyInfo = row.getPrimaryKey().toString();
                    System.out.println("- 主键: " + primaryKeyInfo);

                    // 遍历并打印该行的所有属性列 (当MaxVersions=1时,每个Column即为最新版本)
                    if (row.getColumns() != null && row.getColumns().length > 0) {
                        System.out.println("  属性列:");
                        for (Column column : row.getColumns()) {
                            // 打印列的名称、值和时间戳
                            String columnName = column.getName();
                            // TODO: 根据属性列数据类型进行修改
                            String columnValue = column.getValue().toString();
                            long timestamp = column.getTimestamp();
                            System.out.println(
                                    String.format("    - %s: %s (版本时间戳: %d)", columnName, columnValue, timestamp)
                            );
                        }
                    } else {
                        System.out.println("  (该行没有属性列)");
                    }
                }
            } else {
                System.out.println("没有找到符合正则过滤条件的数据");
            }
            
            System.out.println("正则过滤查询操作执行完成");

        } catch (Exception e) {
            System.err.println("正则过滤查询失败,详细信息如下:");
            e.printStackTrace();
        } finally {
            // 关闭客户端
            if (client != null) {
                client.shutdown();
            }
        }
    }
}

组合过滤器

以下示例代码以范围查询为例查询主键值为[row1, row3)的行数据,并使用组合过滤器进行数据过滤。

import com.alicloud.openservices.tablestore.SyncClient;
import com.alicloud.openservices.tablestore.core.ResourceManager;
import com.alicloud.openservices.tablestore.core.auth.CredentialsProvider;
import com.alicloud.openservices.tablestore.core.auth.DefaultCredentialProvider;
import com.alicloud.openservices.tablestore.core.auth.DefaultCredentials;
import com.alicloud.openservices.tablestore.core.auth.V4Credentials;
import com.alicloud.openservices.tablestore.model.Column;
import com.alicloud.openservices.tablestore.model.ColumnValue;
import com.alicloud.openservices.tablestore.model.GetRangeRequest;
import com.alicloud.openservices.tablestore.model.GetRangeResponse;
import com.alicloud.openservices.tablestore.model.PrimaryKeyBuilder;
import com.alicloud.openservices.tablestore.model.PrimaryKeyValue;
import com.alicloud.openservices.tablestore.model.RangeRowQueryCriteria;
import com.alicloud.openservices.tablestore.model.Row;
import com.alicloud.openservices.tablestore.model.filter.CompositeColumnValueFilter;
import com.alicloud.openservices.tablestore.model.filter.RegexRule;
import com.alicloud.openservices.tablestore.model.filter.SingleColumnValueFilter;
import com.alicloud.openservices.tablestore.model.filter.SingleColumnValueRegexFilter;

public class CompositeFilter {

    public static void main(String[] args) {

        // 从环境变量中获取访问凭证(需要配置TABLESTORE_ACCESS_KEY_ID和TABLESTORE_ACCESS_KEY_SECRET)
        final String accessKeyId = System.getenv("TABLESTORE_ACCESS_KEY_ID");
        final String accessKeySecret = System.getenv("TABLESTORE_ACCESS_KEY_SECRET");

        // TODO: 根据实例信息修改以下配置
        final String region = "cn-hangzhou"; // 填写实例所属的地域ID,例如 "cn-hangzhou"
        final String instanceName = "your_instance_name"; // 填写实例名称
        final String endpoint = "your_endpoint"; // 填写实例访问地址

        SyncClient client = null;
        try {
            // 构造凭证
            DefaultCredentials credentials = new DefaultCredentials(accessKeyId, accessKeySecret);
            V4Credentials credentialsV4 = V4Credentials.createByServiceCredentials(credentials, region);
            CredentialsProvider provider = new DefaultCredentialProvider(credentialsV4);

            // 创建客户端实例
            client = new SyncClient(endpoint, provider, instanceName, null, new ResourceManager(null, null));

            // 构造查询条件
            // TODO: 修改表名称
            RangeRowQueryCriteria rangeRowQueryCriteria = new RangeRowQueryCriteria("test_table");
            // 设置查询起始主键
            // TODO: 修改主键名和值
            PrimaryKeyBuilder startKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
            startKeyBuilder.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row1"));
            rangeRowQueryCriteria.setInclusiveStartPrimaryKey(startKeyBuilder.build());
            // 设置查询结束主键,返回结果不包含结束主键
            // TODO: 修改主键名和值
            PrimaryKeyBuilder endKeyBuilder = PrimaryKeyBuilder.createPrimaryKeyBuilder();
            endKeyBuilder.addPrimaryKeyColumn("id", PrimaryKeyValue.fromString("row3"));
            rangeRowQueryCriteria.setExclusiveEndPrimaryKey(endKeyBuilder.build());
            // 设置查询版本
            rangeRowQueryCriteria.setMaxVersions(1);

            // 构造单属性列值过滤器1,条件为 col1 == "val1"
            // TODO: 修改过滤字段和值
            SingleColumnValueFilter singleColumnValueFilter1 = new SingleColumnValueFilter("col1", SingleColumnValueFilter.CompareOperator.EQUAL, ColumnValue.fromString("val1"));
            
            // 构造单属性列正则过滤器1,条件为 cast<String>(reg(col2)) >= "aaa"
            // TODO: 修改正则表达式、字段名和比较值
            RegexRule regexRule = new RegexRule("1([a-z]+)5", RegexRule.CastType.VT_STRING);
            SingleColumnValueRegexFilter singleColumnValueRegexFilter = new SingleColumnValueRegexFilter("col2", regexRule, SingleColumnValueRegexFilter.CompareOperator.GREATER_EQUAL, ColumnValue.fromString("aaa"));
            
            // 构造组合过滤器1,条件为 col1 == "val1" OR cast<String>(reg(col2)) >= "aaa"
            CompositeColumnValueFilter compositeColumnValueFilter1 = new CompositeColumnValueFilter(CompositeColumnValueFilter.LogicOperator.OR);
            compositeColumnValueFilter1.addFilter(singleColumnValueFilter1);
            compositeColumnValueFilter1.addFilter(singleColumnValueRegexFilter);
            
            // 构造单属性列值过滤器2,条件为 col3 == "val3"
            // TODO: 修改过滤字段和值
            SingleColumnValueFilter singleColumnValueFilter2 = new SingleColumnValueFilter("col3", SingleColumnValueFilter.CompareOperator.EQUAL, ColumnValue.fromString("val3"));
            
            // 构造组合过滤器2,条件为 组合过滤器1 AND 单属性列值过滤器2
            // 即 (col1 == "val1" OR cast<String>(reg(col2)) >= "aaa") AND col3 == "val3"
            CompositeColumnValueFilter compositeColumnValueFilter2 = new CompositeColumnValueFilter(CompositeColumnValueFilter.LogicOperator.AND);
            compositeColumnValueFilter2.addFilter(compositeColumnValueFilter1);
            compositeColumnValueFilter2.addFilter(singleColumnValueFilter2);
            
            // 查询内容添加过滤器
            rangeRowQueryCriteria.setFilter(compositeColumnValueFilter2);

            // 调用getRange方法查询数据
            GetRangeRequest getRangeRequest = new GetRangeRequest(rangeRowQueryCriteria);
            GetRangeResponse getRangeResponse = client.getRange(getRangeRequest);

            // 返回结果处理
            System.out.println("查询完成,结果统计:");
            System.out.println("RequestId: " + getRangeResponse.getRequestId());
            System.out.println("Read CU Cost: " + getRangeResponse.getConsumedCapacity().getCapacityUnit().getReadCapacityUnit());
            System.out.println("Write CU Cost: " + getRangeResponse.getConsumedCapacity().getCapacityUnit().getWriteCapacityUnit());
            
            // 输出查询结果
            if (getRangeResponse.getRows() != null && !getRangeResponse.getRows().isEmpty()) {
                System.out.println("共找到 " + getRangeResponse.getRows().size() + " 行符合条件的数据:");
                for (Row row : getRangeResponse.getRows()) {
                    // 获取并打印主键信息
                    // TODO: 根据主键数据类型进行修改
                    String primaryKeyInfo = row.getPrimaryKey().toString();
                    System.out.println("- 主键: " + primaryKeyInfo);

                    // 遍历并打印该行的所有属性列 (当MaxVersions=1时,每个Column即为最新版本)
                    if (row.getColumns() != null && row.getColumns().length > 0) {
                        System.out.println("  属性列:");
                        for (Column column : row.getColumns()) {
                            // 打印列的名称、值和时间戳
                            String columnName = column.getName();
                            // TODO: 根据属性列数据类型进行修改
                            String columnValue = column.getValue().toString();
                            long timestamp = column.getTimestamp();
                            System.out.println(
                                    String.format("    - %s: %s (版本时间戳: %d)", columnName, columnValue, timestamp)
                            );
                        }
                    } else {
                        System.out.println("  (该行没有属性列)");
                    }
                }
            } else {
                System.out.println("没有找到符合过滤条件的数据");
            }
            
            System.out.println("组合过滤查询操作执行完成");

        } catch (Exception e) {
            System.err.println("查询失败,详细信息如下:");
            e.printStackTrace();
        } finally {
            // 关闭客户端
            if (client != null) {
                client.shutdown();
            }
        }
    }
}

列不存在时的过滤行为

通过setPassIfMissing方法设置行数据不包含判断的属性列时,是否返回该行。

// 行数据不包含判断的属性列时,不返回该行
singleColumnValueFilter.setPassIfMissing(false);

过滤历史版本数据

通过setLatestVersionsOnly方法设置是否判断所有版本的数据。此时只要有一个版本的数据符合条件,即返回该行数据。

// 判断所有版本的数据
singleColumnValueFilter.setLatestVersionsOnly(false);

相关文档

读取数据