全部產品
Search
文件中心

Object Storage Service:使用OSS資料索引進行大規模資料統計

更新時間:Jan 08, 2025

通過OSS資料索引,您可以高效統計海量檔案的數量、大小等資訊,相較傳統的ListObjects介面統計方式,顯著提升統計效率,簡化操作流程,適用於大規模資料統計情境。

方案優勢

A企業在華南3(廣州)地區名為mybucket的儲存空間(Bucket)中,儲存了2億個按業務首碼分類的檔案,共計180萬個目錄。使用OSS資料索引後,檔案統計時間可減少83%。

傳統方式

OSS資料索引

耗時

每日統計花費 2 小時

每日統計花費 20 分鐘

複雜度

對於檔案數量大於1000的目錄,需要多次調用ListObject介面。

每個目錄只需調用一次DoMetaQuery介面。

方案概覽

使用OSS資料索引進行大規模資料統計的過程如下:

要實現以上過程,您只需要:

  1. 開啟資料索引:OSS會幫您自動建立索引表,包含OSS中繼資料、自訂中繼資料和對象標籤。

  2. 發起檢索和統計:您需要設定檢索條件,然後調用DoMetaQuery介面,OSS會進行快速檢索。

最後,OSS會返回符合條件檔案的數量、總大小和平均檔案大小等統計資訊,供您分析使用。

快速體驗

步驟一:開啟OSS資料索引

使用OSS控制台

  1. 登入OSS管理主控台

  2. 單擊Bucket 列表,然後單擊目標Bucket名稱。

  3. 在左側導覽列, 選擇檔案管理 > 資料索引

  4. 資料索引頁面,單擊立即開啟

  5. 選擇標量檢索,單擊確認開啟

    image

使用阿里雲SDK

僅Java SDK、Python SDK以及Go SDK支援通過標量檢索功能查詢滿足指定條件的Object。

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;

public class Demo {

    // Endpoint以華南3(廣州)為例,其它Region請按實際情況填寫。
    private static String endpoint = "https://oss-cn-guangzhou.aliyuncs.com";
    // 填寫Bucket名稱,例如examplebucket。
    private static String bucketName = "examplebucket";

    public static void main(String[] args) throws com.aliyuncs.exceptions.ClientException {
        // 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填寫Bucket所在地區。以華南3(廣州)為例,Region填寫為cn-guangzhou。
        String region = "cn-guangzhou";

        // 建立OSSClient執行個體。
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(credentialsProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .region(region)
                .build();

        try {
            // 開啟資料索引功能。
            ossClient.openMetaQuery(bucketName);
        } 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

# 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())

# 填寫Bucket所在地區對應的Endpoint。以華南3(廣州)為例,Endpoint填寫為https://oss-cn-guangzhou.aliyuncs.com。
endpoint = "https://oss-cn-guangzhou.aliyuncs.com"
# 填寫Endpoint對應的Region資訊,例如cn-guangzhou。注意,v4簽名下,必須填寫該參數
region = "cn-guangzhou"

# examplebucket填寫儲存空間名稱。
bucket = oss2.Bucket(auth, endpoint, "examplebucket", region=region)

# 開啟資料索引功能。
bucket.open_bucket_meta_query()
package main

import (
	"context"
	"flag"   
	"log"     

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"          
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials" 
)

var (
	region     string // 定義一個變數來儲存從命令列擷取的地區(Region)資訊
	bucketName string // 定義一個變數來儲存從命令列擷取的儲存空間名稱
)

// init函數在main函數之前執行,用來初始化程式
func init() {
	// 設定命令列參數來指定region
	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
	// 設定命令列參數來指定bucket名稱
	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
}

func main() {
	flag.Parse() // 解析命令列參數

	// 檢查是否提供了儲存空間名稱,如果沒有提供,則輸出預設參數並退出程式
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, bucket name required") // 記錄錯誤並終止程式
	}

	// 檢查是否提供了地區資訊,如果沒有提供,則輸出預設參數並退出程式
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, region required") // 記錄錯誤並終止程式
	}

	// 建立用戶端配置,並使用環境變數作為憑證提供者
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	client := oss.NewClient(cfg) // 使用配置建立一個新的OSS用戶端執行個體

	// 構建一個OpenMetaQuery請求,用於開啟特定儲存空間的中繼資料查詢功能
	request := &oss.OpenMetaQueryRequest{
		Bucket: oss.Ptr(bucketName), // 指定要操作的儲存空間名稱
	}
	result, err := client.OpenMetaQuery(context.TODO(), request) // 執行請求以開啟儲存空間的中繼資料查詢功能
	if err != nil {
		log.Fatalf("failed to open meta query %v", err) // 如果有錯誤發生,記錄錯誤資訊並終止程式
	}

	log.Printf("open meta query result:%#v\n", result) // 列印開啟中繼資料查詢的結果
}

步驟二:發起檢索和統計

使用OSS控制台

檢索條件設定

  1. 在左側導覽列, 選擇檔案管理 > 資料索引

  2. 儲存類型選擇標準儲存,讀寫權限選擇私人

  3. 通過模糊比對目錄首碼“a/b”來指定目錄。

    image

結果輸出設定

  1. 按對象的最後修改時間降序排序結果。

  2. 對篩選後檔案大小進行求和平均值的計算。

  3. 儲存類型進行分組計數,以統計檔案數量。

image

  1. 單擊立即查詢

使用阿里雲SDK

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.*;

import java.util.ArrayList;
import java.util.List;

public class Demo {

    // Endpoint以華南3(廣州)為例,其它Region請按實際情況填寫。
    private static String endpoint = "https://oss-cn-guangzhou.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();
        // 填寫Bucket所在地區。以華南3(廣州)為例,Region填寫為cn-guangzhou。
        String region = "cn-guangzhou";

        // 建立OSSClient執行個體。
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(credentialsProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .region(region)
                .build();

        try {
            // 設定查詢參數,指定返迴文件的最大數量(20個)
            int maxResults = 20;
            // 設定查詢條件:檔案名稱包含"a/b",且檔案儲存體類型為"Standard",存取權限為"private"
            // 查詢語句使用邏輯運算子"and"來串連多個子查詢條件
            String query = "{\n" +
                    "  \"Operation\": \"and\",\n" +
                    "  \"SubQueries\": [\n" +
                    "    {\n" +
                    "      \"Field\": \"Filename\",\n" +
                    "      \"Value\": \"a/b\",\n" +
                    "      \"Operation\": \"match\"\n" +
                    "    },\n" +
                    "    {\n" +
                    "      \"Field\": \"OSSStorageClass\",\n" +
                    "      \"Value\": \"Standard\",\n" +
                    "      \"Operation\": \"eq\"\n" +
                    "    },\n" +
                    "    {\n" +
                    "      \"Field\": \"ObjectACL\",\n" +
                    "      \"Value\": \"private\",\n" +
                    "      \"Operation\": \"eq\"\n" +
                    "    }\n" +
                    "  ]\n" +
                    "}";
            String sort = "FileModifiedTime";// 設定按檔案修改時間排序

            // 建立彙總操作執行個體,用於統計檔案的大小(Size)的總和、數量和平均值
            Aggregation aggregationRequest1 = new Aggregation();
            aggregationRequest1.setField("Size");// 設定彙總欄位為檔案大小
            aggregationRequest1.setOperation("sum");// 計算檔案大小的總和

            Aggregation aggregationRequest2 = new Aggregation();
            aggregationRequest2.setField("Size");// 設定彙總欄位為檔案大小
            aggregationRequest2.setOperation("count");// 計算檔案數量

            Aggregation aggregationRequest3 = new Aggregation();
            aggregationRequest3.setField("Size");// 設定彙總欄位為檔案大小
            aggregationRequest3.setOperation("average");// 計算檔案大小的平均值

            // 將所有彙總請求添加到一個列表中
            Aggregations aggregations = new Aggregations();
            List<Aggregation> aggregationList = new ArrayList<>();
            aggregationList.add(aggregationRequest1);// 添加求和彙總
            aggregationList.add(aggregationRequest2);// 添加計數彙總
            aggregationList.add(aggregationRequest3);// 添加平均值彙總
            aggregations.setAggregation(aggregationList);// 將所有彙總操作設定到Aggregations對象中

            // 建立DoMetaQueryRequest請求對象,傳入Bucket名稱、最大返迴文件數、查詢條件和定序
            DoMetaQueryRequest doMetaQueryRequest = new DoMetaQueryRequest(bucketName, maxResults, query, sort);

            // 將彙總操作添加到Meta查詢請求中
            doMetaQueryRequest.setAggregations(aggregations);
            // 設定排序方式為降序(DESC)
            doMetaQueryRequest.setOrder(SortOrder.DESC);

            // 執行Meta查詢請求,擷取查詢結果
            DoMetaQueryResult doMetaQueryResult = ossClient.doMetaQuery(doMetaQueryRequest);
            // 判斷查詢結果
            if (doMetaQueryResult.getFiles() != null) {
                // 如果檔案清單不為空白,遍曆檔案資訊並列印
                for (ObjectFile file : doMetaQueryResult.getFiles().getFile()) {
                    System.out.println("Filename: " + file.getFilename()); // 檔案名稱
                    System.out.println("ETag: " + file.getETag());// 檔案ETag
                    System.out.println("ObjectACL: " + file.getObjectACL()); // 檔案存取權限
                    System.out.println("OssObjectType: " + file.getOssObjectType());// 檔案類型
                    System.out.println("OssStorageClass: " + file.getOssStorageClass());// 儲存類型
                    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) {
            // 捕獲OSS異常並輸出相關資訊
            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  
import json
# 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())

# 填寫Bucket所在地區對應的Endpoint。以華南3(廣州)為例,Endpoint填寫為https://oss-cn-guangzhou.aliyuncs.com。
endpoint = "https://oss-cn-guangzhou.aliyuncs.com"
# 填寫Endpoint對應的Region資訊,例如cn-guangzhou。注意,v4簽名下,必須填寫該參數
region = "cn-guangzhou"

# 填寫儲存空間名稱,以examplebucket為例。
bucket = oss2.Bucket(auth, endpoint, "examplebucket", region=region)

# 查詢條件:檔案名稱包含"a/b",且檔案儲存體類型為"Standard",存取權限為"private"
query = {
    "Operation": "and",
    "SubQueries": [
        {"Field": "Filename", "Value": "a/b", "Operation": "match"},
        {"Field": "OSSStorageClass", "Value": "Standard", "Operation": "eq"},
        {"Field": "ObjectACL", "Value": "private", "Operation": "eq"}
    ]
}
# 將字典轉換為JSON字串
query_json = json.dumps(query)

# 建立彙總操作執行個體,用於統計檔案的大小(Size)的總和、數量和平均值
aggregations = [
    AggregationsRequest(field="Size", operation="sum"),  # 計算檔案大小的總和
    AggregationsRequest(field="Size", operation="count"),  # 計算檔案的數量
    AggregationsRequest(field="Size", operation="average")  # 計算檔案大小的平均值
]


# 建立MetaQuery請求對象,指定查詢條件、最大返迴文件數、排序欄位和方式以及彙總操作
do_meta_query_request = MetaQuery(
    max_results=20,  # 返回最多20個檔案
    query=query_json,  # 設定查詢條件
    sort="FileModifiedTime",  # 按檔案修改時間排序
    order="desc",  # 降序排序
    aggregations=aggregations  # 設定彙總操作
)

# 執行Meta查詢請求,擷取查詢結果
result = bucket.do_bucket_meta_query(do_meta_query_request)

# 列印查詢結果中滿足條件的檔案資訊
if result.files:
    for file in result.files:
        print(f"Filename: {file.file_name}")  # 列印檔案名
        print(f"ETag: {file.etag}")  # 列印檔案的ETag
        print(f"ObjectACL: {file.object_acl}")  # 列印檔案的存取控制清單(ACL)
        print(f"OssObjectType: {file.oss_object_type}")  # 列印檔案的OSS物件類型
        print(f"OssStorageClass: {file.oss_storage_class}")  # 列印檔案的儲存類型
        print(f"TaggingCount: {file.oss_tagging_count}")  # 列印檔案的標籤數量
        
        # 列印檔案的所有標籤
        if file.oss_tagging:
            for tag in file.oss_tagging:
                print(f"Key: {tag.key}")  # 列印標籤的Key
                print(f"Value: {tag.value}")  # 列印標籤的Value
        
        # 列印檔案的使用者中繼資料
        if file.oss_user_meta:
            for meta in file.oss_user_meta:
                print(f"Key: {meta.key}")  # 列印使用者中繼資料的Key
                print(f"Value: {meta.value}")  # 列印使用者中繼資料的Value


# 列印彙總結果
if result.aggregations:
    for aggre in result.aggregations:
        print(f"Field: {aggre.field}")  # 列印彙總操作欄位
        print(f"Operation: {aggre.operation}")  # 列印彙總操作類型(如sum、count、average)
        print(f"Value: {aggre.value}")  # 列印彙總結果值
package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"log"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

var (
	region     string // 定義一個變數來儲存從命令列擷取的地區(Region)資訊
	bucketName string // 定義一個變數來儲存從命令列擷取的儲存空間名稱
)

// init函數在main函數之前執行,用來初始化程式
func init() {
	// 設定命令列參數來指定region,預設為空白字串
	flag.StringVar(&region, "region", "", "The region in which the bucket is located.")
	// 設定命令列參數來指定bucket名稱,預設為空白字串
	flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
}

func main() {
	flag.Parse() // 解析命令列參數

	// 檢查是否提供了儲存空間名稱,如果沒有提供,則輸出預設參數並退出程式
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, bucket name required")
	}

	// 檢查是否提供了地區資訊,如果沒有提供,則輸出預設參數並退出程式
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("invalid parameters, region required")
	}

	// 建立用戶端配置,並使用環境變數作為憑證提供者和指定的地區
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	client := oss.NewClient(cfg) // 使用配置建立一個新的OSS用戶端執行個體

	// 構建查詢條件,檔案名稱包含"a/b",儲存類型為"Standard",存取權限為"private"
	query := map[string]interface{}{
		"Operation": "and",
		"SubQueries": []map[string]interface{}{
			{"Field": "Filename", "Value": "a/b", "Operation": "match"},
			{"Field": "OSSStorageClass", "Value": "Standard", "Operation": "eq"},
			{"Field": "ObjectACL", "Value": "private", "Operation": "eq"},
		},
	}
	// 將查詢條件轉為JSON字串
	queryJSON, err := json.Marshal(query)
	if err != nil {
		log.Fatalf("failed to marshal query %v", err)
	}

	// 建立彙總操作,用於統計檔案大小的總和、數量和平均值
	aggregations := []oss.MetaQueryAggregation{
		{Field: oss.Ptr("Size"), Operation: oss.Ptr("sum")},     // 計算檔案大小總和
		{Field: oss.Ptr("Size"), Operation: oss.Ptr("count")},   // 計算檔案數量
		{Field: oss.Ptr("Size"), Operation: oss.Ptr("average")}, // 計算檔案大小平均值
	}

	// 構建一個DoMetaQuery請求,用於執行中繼資料查詢
	request := &oss.DoMetaQueryRequest{
		Bucket: oss.Ptr(bucketName), // 指定要查詢的儲存空間名稱
		MetaQuery: &oss.MetaQuery{
			MaxResults: oss.Ptr(int64(20)),         // 最大返回結果數:20個結果
			Query:      oss.Ptr(string(queryJSON)), // 查詢條件:大小大於1MB的對象
			Sort:       oss.Ptr("Size"),            // 排序欄位:按對象大小排序
			Order:      oss.MetaQueryOrderAsc,      // 排序次序:升序
			Aggregations: &oss.MetaQueryAggregations{
				Aggregations: aggregations}, // 彙總操作:計算檔案大小的總和、數量和平均值
		},
	}
	result, err := client.DoMetaQuery(context.TODO(), request) // 發送請求以執行中繼資料查詢
	if err != nil {
		log.Fatalf("failed to do meta query %v", err)
	}

	// 列印NextToken,用於分頁查詢下一頁的資料
	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)
		if file.OSSTaggingCount != nil {
			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)
		}
	}

	// 列印彙總結果
	for _, aggregation := range result.Aggregations {
		fmt.Printf("Aggregation Field:%s\n", *aggregation.Field)
		fmt.Printf("Aggregation Operation:%s\n", *aggregation.Operation)
		fmt.Printf("Aggregation Value:%f\n", *aggregation.Value)
	}

}

步驟三:結果驗證

使用OSS控制台

如圖所示,合格100個標準儲存類型檔案總大小為19.53MB,平均每個檔案約200KB。

image

使用阿里雲SDK

如圖所示,合格100個標準儲存類型檔案總大小為19.53MB,平均每個檔案約200KB。

image

瞭解更多

  • 如果您的程式自訂要求較高,您可以直接發起REST API請求。直接發起REST API請求需要手動編寫代碼計算簽名。更多資訊,請參見簽名版本4DoMetaQuery API