全部產品
Search
文件中心

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

更新時間:Dec 31, 2024

通過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 (
	"fmt"
	"os"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

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執行個體。
	// yourRegion填寫Bucket所在地區,以華南3(廣州)為例,填寫為cn-guangzhou。其它Region請按實際情況填寫。
	clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
	clientOptions = append(clientOptions, oss.Region("yourRegion"))
	// 設定簽名版本為V4(推薦版本)。
	clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
    // yourEndpoint填寫Bucket對應的Endpoint,以華南3(廣州)為例,填寫為https://oss-cn-guangzhou.aliyuncs.com。其它Region請按實際情況填寫。
	client, err := oss.New("yourEndpoint", "", "", clientOptions...)
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	//開啟資料索引功能。
	//填寫需要開啟資料索引的bucket名稱,以examplebucket為例。
	err = client.OpenMetaQuery("examplebucket")
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}
	fmt.Println("Open data query success")
}

步驟二:發起檢索和統計

使用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 (
	"encoding/json" // 匯入 json 包
	"fmt"
	"os"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
	// 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
	provider, err := oss.NewEnvironmentVariableCredentialsProvider()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	region := "cn-guangzhou"                            // 設定Region,以華南3(廣州)為例,填寫cn-guangzhou
	endpoint := "https://oss-cn-guangzhou.aliyuncs.com" // 設定Bucket對應的Endpoint,以華南3(廣州)為例,填寫https://oss-cn-guangzhou.aliyuncs.com
	bucketName := "examplebucket"                       // 設定Bucket名稱,例如examplebucket

	// 建立OSSClient執行個體。
	clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
	clientOptions = append(clientOptions, oss.Region(region))
	// 設定簽名版本V4
	clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
	client, err := oss.New(endpoint, "", "", clientOptions...)
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	// 構建查詢條件,檔案名稱包含"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 {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

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

	// 建立MetaQuery請求對象
	metaQueryRequest := oss.MetaQuery{
		MaxResults:   20,                 // 返回最多20個檔案
		Query:        string(queryJSON),  // 設定查詢條件
		Sort:         "FileModifiedTime", // 按檔案修改時間排序
		Order:        "desc",             // 降序排序
		Aggregations: aggregations,       // 設定彙總操作
	}

	// 執行Meta查詢請求,擷取查詢結果
	result, err := client.DoMetaQuery(bucketName, metaQueryRequest)
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	// 列印NextToken(用於分頁查詢)
	if result.NextToken != "" {
		fmt.Printf("NextToken: %s\n", result.NextToken)
	}

	// 列印查詢結果中滿足條件的檔案資訊
	for _, file := range result.Files {
		fmt.Printf("Filename: %s\n", file.Filename)
		fmt.Printf("ETag: %s\n", file.ETag)
		fmt.Printf("ObjectACL: %s\n", file.ObjectACL)
		fmt.Printf("OssObjectType: %s\n", file.OssObjectType)
		fmt.Printf("OssStorageClass: %s\n", file.OssStorageClass)
		fmt.Printf("TaggingCount: %d\n", file.OssTaggingCount)

		// 列印檔案標籤資訊
		for _, tag := range file.OssTagging {
			fmt.Printf("Key: %s\n", tag.Key)
			fmt.Printf("Value: %s\n", tag.Value)
		}

		// 列印使用者中繼資料
		for _, meta := range file.OssUserMeta {
			fmt.Printf("Key: %s\n", meta.Key)
			fmt.Printf("Value: %s\n", meta.Value)
		}
	}

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

步驟三:結果驗證

使用OSS控制台

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

image

使用阿里雲SDK

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

image

瞭解更多

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