文档

使用标量检索基于元数据属性查询OSS中的文件

更新时间:

标量检索是OSS对外提供的文件(Object)元数据索引能力。您可以利用Object的元数据自定义索引的条件,从而快速获取Object列表。标量检索可以帮助您更好地管理与了解数据结构,方便您后续查询、统计和管理Object。

使用场景

数据审计场景

通过标量检索,您可以快速定位文件,以满足数据审计或监管需求。例如,在金融服务行业,您可以通过自定义标签、访问权限等元数据进行筛选,从而找到具有特定敏感性级别或特定权限的文件,以提升数据审计的效率。

企业备份与归档场景

企业在进行数据备份和归档时,可以利用标量检索,例如根据文件的创建时间、存储类型或自定义标签等元数据,迅速检索到特定日期或类型的文件,从而快速恢复历史数据或归档记录。

注意事项

  • 地域限制

    华东1(杭州)、华北2(北京)、华北3(张家口)、华南1(深圳)、华南3(广州)、中国香港、新加坡地域的Bucket支持使用标量检索功能。

  • Bucket限制

    默认只支持为文件数量在100亿以下的Bucket开启元数据管理功能。

  • 费用说明

    标量检索目前是公测阶段。使用标量检索功能时,需要开启元数据管理。开启元数据管理功能会产生Object的元数据管理费用以及检索次数费用,但公测期间暂不收费。关于数据索引计费项的更多信息,请参见数据索引费用

  • 建立索引所需时间

    开启元数据管理功能时,建立索引所需时间与Bucket内存量的文件数量成正比。文件数量越多,建立索引的时间越长。 一般来说,1000万个文件初次建立索引的时间约为1小时,10亿个文件初次建立索引的时间约为1天,100亿个文件初次建立索引的时间约为2~3 天,该时间仅供参考。

  • 分片上传

    对于通过分片上传生成的Object,查询结果中只显示已通过CompleteMultipartUpload操作将碎片(Part)合成的完整Object,不显示已初始化但未完成(Complete)或者未中止(Abort)的碎片。

操作步骤

使用OSS控制台

以查找所有文件大小小于500KB,最后更新时间在2024年9月11日0:00至2024年9月12日0:00的文件,输出结果按文件大小升序排列,并按文件大小统计最大值为例:

  1. 登录OSS管理控制台

  2. 单击Bucket 列表,然后单击目标Bucket名称。

  3. 在左侧导航栏, 选择文件管理 > 数据索引

  4. 数据索引页面,单击立即开启

  5. 选择标量检索,单击确认开启

    开启元数据管理需要等待一定的时间,具体等待时长取决于Bucket中Object的数量。

  6. 按以下说明设置OSS元数据检索条件,其他参数保留默认设置。

    • 最后修改时间设置为2024年9月11日0:00至2024年9月12日0:00。

    • 文件大小设置为小于500KB。

    image

  7. 设置输出方式

    • 对象排序方式选择按照文件大小升序排列。

    • 数据聚合选择按照文件大小最大值聚合输出

      image

  8. 单击立即查询。符合检索条件的所有文件共2个,如下图所示,文件最大为434KB。

    image

更多设置请参见检索条件和输出设置

使用阿里云SDK

仅Java SDK、Python SDK以及Go SDK支持通过标量检索功能查询满足指定条件的Object。使用标量检索功能前,您需要为指定Bucket开启元数据管理功能。关于标量检索的代码示例,请参见SDK简介

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import java.util.ArrayList;
import java.util.List;

public class Demo {

    // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
    private static String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
    // 填写Bucket名称,例如examplebucket。
    private static String bucketName = "examplebucket";

    public static void main(String[] args) throws Exception {
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            // 查询满足指定条件的文件(Object),并按照指定字段和排序方式列举文件信息。
            int maxResults = 20;
            // 指定查询小于1048576字节的文件,且最多返回20个结果,返回结果按升序排列。
            String query = "{\"Field\": \"Size\",\"Value\": \"1048576\",\"Operation\": \"lt\"}";
            String sort = "Size";
            DoMetaQueryRequest doMetaQueryRequest = new DoMetaQueryRequest(bucketName, maxResults, query, sort);
            Aggregation aggregationRequest = new Aggregation();
            Aggregations aggregations = new Aggregations();
            List<Aggregation> aggregationList = new ArrayList<Aggregation>();
            // 指定聚合操作的字段名称。
            aggregationRequest.setField("Size");
            // 指定聚合操作的操作符,max表示最大值。
            aggregationRequest.setOperation("max");
            aggregationList.add(aggregationRequest);
            aggregations.setAggregation(aggregationList);

            // 设置聚合操作。
            doMetaQueryRequest.setAggregations(aggregations);
            doMetaQueryRequest.setOrder(SortOrder.ASC);
            DoMetaQueryResult doMetaQueryResult = ossClient.doMetaQuery(doMetaQueryRequest);
            if(doMetaQueryResult.getFiles() != null){
                for(ObjectFile file : doMetaQueryResult.getFiles().getFile()){
                    System.out.println("Filename: " + file.getFilename());
                    // 获取标识Object的内容。
                    System.out.println("ETag: " + file.getETag());
                    // 获取Object的访问权限
                    System.out.println("ObjectACL: " + file.getObjectACL());
                    // 获取Object的类型。
                    System.out.println("OssObjectType: " + file.getOssObjectType());
                    // 获取Object的存储类型。
                    System.out.println("OssStorageClass: " + file.getOssStorageClass());
                    // 获取Object的标签个数。
                    System.out.println("TaggingCount: " + file.getOssTaggingCount());
                    if(file.getOssTagging() != null){
                        for(Tagging tag : file.getOssTagging().getTagging()){
                            System.out.println("Key: " + tag.getKey());
                            System.out.println("Value: " + tag.getValue());
                        }
                    }
                    if(file.getOssUserMeta() != null){
                        for(UserMeta meta : file.getOssUserMeta().getUserMeta()){
                            System.out.println("Key: " + meta.getKey());
                            System.out.println("Value: " + meta.getValue());
                        }
                    }
                }
            } else if(doMetaQueryResult.getAggregations() != null){
                for(Aggregation aggre : doMetaQueryResult.getAggregations().getAggregation()){
                    // 获取聚合字段名称。
                    System.out.println("Field: " + aggre.getField());
                    // 获取聚合字段的操作符。
                    System.out.println("Operation: " + aggre.getOperation());
                    // 获取聚合操作的结果值。
                    System.out.println("Value: " + aggre.getValue());
                    if(aggre.getGroups() != null && aggre.getGroups().getGroup().size() > 0){
                        // 获取分组聚合的值。
                        System.out.println("Groups value: " + aggre.getGroups().getGroup().get(0).getValue());
                        // 获取分组聚合的总个数。
                        System.out.println("Groups count: " + aggre.getGroups().getGroup().get(0).getCount());
                    }
                }
            } else {
                System.out.println("NextToken: " + doMetaQueryResult.getNextToken());
            }
        } catch (OSSException oe) {
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Error Message: " + ce.getMessage());
        } finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }
    }
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
from oss2.models import MetaQuery, AggregationsRequest
# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())

# Endpoint以杭州为例,其它Region请按实际情况填写。
# 填写Bucket名称,例如examplebucket。
bucket = oss2.Bucket(auth, 'http://oss-cn-hangzhou.aliyuncs.com', 'examplebucket')

# 查询满足指定条件的Object,并按照指定字段和排序方式列举Object信息。
# 指定查询小于1 MB的文件,且最多返回十个结果,返回结果按升序排列。
do_meta_query_request = MetaQuery(max_results=10, query='{"Field": "Size","Value": "1048576","Operation": "lt"}', sort='Size', order='asc')
result = bucket.do_bucket_meta_query(do_meta_query_request)

# 打印Object名称。
print(result.files[0].file_name)
# 打印Object对应的ETag。
print(result.files[0].etag)
# 打印Object类型。
print(result.files[0].oss_object_type)
# 打印Object存储类型。
print(result.files[0].oss_storage_class)
# 打印Object的64位CRC值。
print(result.files[0].oss_crc64)
# 打印Object的访问权限。
print(result.files[0].object_acl)
package main

import (
    "fmt"
    "github.com/aliyun/aliyun-oss-go-sdk/oss"
    "os"
)
func main()  {
    // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
    provider, err := oss.NewEnvironmentVariableCredentialsProvider()
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    // 创建OSSClient实例。
    // yourEndpoint填写Bucket对应的Endpoint,以华东1(杭州)为例,填写为https://oss-cn-hangzhou.aliyuncs.com。其它Region请按实际情况填写。
    client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider))
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }    
    // 指定查询大于30字节的文件,且最多返回十个结果,返回结果按升序排列。
    query := oss.MetaQuery{
        NextToken: "",
        MaxResults: 10,
        Query: `{"Field": "Size","Value": "30","Operation": "gt"}`,
        Sort: "Size",
        Order: "asc",
    }
    // 查询满足指定条件的Object,并按照指定字段和排序方式列举Object信息。
    result,err := client.DoMetaQuery("examplebucket",query)
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    fmt.Printf("NextToken:%s\n", result.NextToken)
    for _, file := range result.Files {
        fmt.Printf("File name: %s\n", file.Filename)
        fmt.Printf("size: %d\n", file.Size)
        fmt.Printf("File Modified Time:%s\n", file.FileModifiedTime)
        fmt.Printf("Oss Object Type:%s\n", file.OssObjectType)
        fmt.Printf("Oss Storage Class:%s\n", file.OssStorageClass)
        fmt.Printf("Object ACL:%s\n", file.ObjectACL)
        fmt.Printf("ETag:%s\n", file.ETag)
        fmt.Printf("Oss CRC64:%s\n", file.OssCRC64)
        fmt.Printf("Oss Tagging Count:%d\n", file.OssTaggingCount)
        for _, tagging := range  file.OssTagging {
            fmt.Printf("Oss Tagging Key:%s\n", tagging.Key)
            fmt.Printf("Oss Tagging Value:%s\n", tagging.Value)
        }
        for _, userMeta := range  file.OssUserMeta {
            fmt.Printf("Oss User Meta Key:%s\n", userMeta.Key)
            fmt.Printf("Oss User Meta Key Value:%s\n", userMeta.Value)
        }
    }
}

使用REST API

如果您的程序自定义要求较高,您可以直接发起REST API请求。直接发起REST API请求需要手动编写代码计算签名。更多信息,请参见DoMetaQuery

检索条件及输出设置

检索条件

以下是完整的检索条件,您可以根据需要进行单独或组合设置。

OSS元数据检索条件

检索条件

说明

存储类型

默认选中OSS支持的标准、低频访问、归档、冷归档和深度冷归档多种存储类型。您可以按需选择希望在查询结果中显示的Object存储类型。

读写权限

默认选中OSS支持的四种读写权限ACL,即继承Bucket、私有、公共读以及公共读写。您可以按需选择希望在查询结果中显示的Object读写权限。

文件名

支持模糊匹配等于。如果您希望在查询结果中显示某个文件名,例如exampleobject.txt。您可以通过以下两种方式匹配目标文件:

  • 选择等于,然后输入完整的文件名称exampleobject.txt

  • 选择模糊匹配,然后输入文件前缀或者后缀,例如example或者.txt

    重要

    模糊匹配可命中Object名称的任意字符,例如输入test,则查询结果中将显示localfolder/test/.example.jpglocalfolder/test.jpg等。

上传类型

默认选中OSS支持的四种Object类型,您可以按需选择希望在查询结果中显示的Object类型。Object类型说明如下:

  • Normal:通过简单上传方式生成的Object。

  • Multipart:通过分片上传方式生成的Object。

  • Appendable:通过追加上传方式生成的Object。

  • Symlink:为快速访问Object创建的软链接。

最后修改时间

指定Object被最后修改的起始日期结束日期,时间精确到秒。

文件大小

支持等于大于大于等于小于小于等于五种筛选条件,文件大小单位为KB。

对象版本

仅支持查询当前版本Object。

对象Etag及标签检索条件

如需根据对象Etag及标签进行过滤查找,可输入您希望在查询结果中显示的Object对应的ETag或标签信息。

  • ETag仅支持精确匹配。ETag必须带引号,示例值为"5B3C1A2E0563E1B002CC607C6689"。可输入多个ETag,每行一个。

  • 以键值对(Key-Value)的形式指定对象标签。对象标签的Key和Value均区分大小写。关于标签规则的更多信息,请参见对象标签

结果输出设置

您可对输出结果进行排序和简单统计。

  • 对象排序方式:支持根据最后修改时间、文件名和文件大小进行升序、降序及默认排序。您可以按需选择并排序检索结果,便于快速找到所需文件。

  • 数据聚合:支持多种输出类型,您可以对检索结果进行去重统计、分组计数、最大值、最小值、平均值和求和等计算,便于高效分析和管理数据。

常见问题

Bucket内文件数量达到上亿级别时,为什么很长时间都没有成功建立数据索引?

1秒内大约可以为600个文件建立索引。您可以结合Bucket内的文件数量,预估建立索引所需时间。

相关文档

标量检索支持多项过滤条件,例如文件最后修改时间、存储类型、读写权限、文件大小等。如果您希望从OSS Bucket的海量Object中筛选出指定时间范围内的Object,请参见如何筛选OSS指定时间范围内的文件?。