隨着人工智能技術的深入發展,企業對數據的利用已不再侷限於傳統的結構化數據分析。越來越多的行業開始依賴多模態數據進行智能決策,涵蓋商品推薦、駕駛行為分析、金融風控、教育個性化等多個場景。這些場景普遍具備一個共同特徵:數據形態多樣、分析需求複雜、檢索方式多元。Hologres 4.0的整體架構圍繞“多模態分析檢索 all-in-one”設計,實現“一份數據、一份計算、多模分析”的一站式目標,一條SQL即可完成從數據接入、AI加工到多模查詢的全流程。

基於 Hologres 構建智能駕駛圖像高性能分析系統_多模態分析

智能駕駛場景中,可以看到採集的車機各種信號數據,以大寬表的形式存儲在數據庫中。這些信號數據通常會包含結構化數據(車輛狀態、車機版本等)、半結構化數據(車機信號)、非結構化數據(軌跡照片等)。在業務應用的時候,要進行點查、OLAP分析、全文檢索、向量檢索、混合檢索等多種場景。

傳統架構往往依賴多個獨立引擎協同工作,導致系統複雜、成本高昂、數據不一致等問題頻發。AI時代的應用需要在一個統一平台上完成OLAP分析、點查服務、全文檢索、向量搜索以及AI推理等多種能力的融合使用。本文以自動駕駛圖像數據集為例,介紹Hologres如何在傳統的結構化分析的基礎上,完成文搜圖、圖搜圖等多模態分析場景。

基於 Hologres 構建智能駕駛圖像高性能分析系統_SQL_02

基於Hologres構建自動駕駛圖像高性能分析系統

在自動駕駛系統中,車輛圖片分析是環境感知模塊的核心場景之一,主要用於實時解析車輛內外部攝像頭捕捉的視覺信息,以實現對周圍環境的精準理解與決策。本文以BDD自動駕駛數據集為例模擬自動駕駛場景,模擬真實駕駛場景,採集10萬張包括駕駛區域、地理、環境、天氣多樣性等數據的圖片,通過對圖片的分析與檢索,進行了行駛軌跡分析、環境感知優化及行人車輛識別精度提升等全棧技術驗證,提升系統對複雜交通場景的適應能力、安全性和用户體驗。

基於Hologres構建自動駕駛圖像高性能分析系統包含的主要能力如下:

  • 非結構化數據(Object Table):支持通過表的形式讀取OSS中非結構化數據(PDF、IMAGE、PPT等)。
  • AI Function:在Hologres中可以用標準SQL的方式調用Function,自動調用內置大模型,完成AI服務建設場景。
  • 數據加工:提供Embed、Chunk算子,可以對非結構化數據加工成結構化數據存儲,無需使用外部算法就能自動Embed。
  • 數據檢索和分析:提供<font style="background-color:rgba(0, 0, 0, 0.04);">ai_gen</font><font style="background-color:rgba(0, 0, 0, 0.04);">ai_summarize</font>等算子,使用SQL就能對數據進行推理、問題總結以及翻譯等能力。
  • Dynamic Table 介紹:支持增量刷新模式對非結構化數據自動加工,每次只計算增量的數據有效減少重複計算,降低資源利用率。
  • 向量檢索:支持標準SQL的向量檢索,用於非結構化數據的相似度搜索、場景識別等,在同一個查詢中可以自由地實現向量和標量的檢索。
  • 全文檢索:通過倒排索引、分詞等機制實現對非結構化數據的高效檢索,支持關鍵詞匹配、短語檢索等豐富的檢索方式,實現更加靈活的檢索。

方案優勢

通過如上核心能力,在Hologres中對圖片檢索的核心優勢如下:

  • 完整的AI數據處理流程:涵蓋從數據Embed、Chunk、增量加工和檢索/分析的全流程,與使用大數據系統一樣輕鬆構建AI應用。
  • 標準SQL加工圖片數據:無需使用專用開發語言,純SQL就能完成圖片數據提取、加工。
  • 一個平台支持跨模態檢索:支持以文搜圖、以圖搜圖,語義理解突破關鍵詞侷限,在Hologres就能實現跨模態檢索。
  • 檢索更精準、靈活和智能:可以輕鬆構建“關鍵詞+語義+多模態”的混合檢索鏈路,覆蓋從精準搜索到意圖理解的全場景需求。還能結合AI Function實現對用户意圖的深度理解,語義關聯和上下文推理,實現更智能的檢索能力。
  • 數據不出庫,安全性更高:不需要將數據導出到外部系統,與Hologres的多種安全能力無縫集成,並高效保護數據安全。


方案流程

本次方案的流程如下:

  1. 數據集準備。
    將圖片數據上傳至OSS存儲。
  2. 圖片加工。
    使用Object Table讀取圖片的元數據信息,然後創建增量刷新的Dynamic Table對數據進行Embed,併為Dynamic Table構建向量索引,以便後續檢索能夠充分利用索引的功能。
  3. 使用<font style="color:rgb(24, 24, 24);background-color:rgba(0, 0, 0, 0.04);">ai_embed</font>算子將自然語言的問題進行Embedding,然後使用向量檢索輸出Top N的結果。

基於 Hologres 構建智能駕駛圖像高性能分析系統_數據分析_03

準備工作

  • 數據準備
    本文使用ModelScope公開的BDD100K 自動駕駛圖像數據集中val.zip文件,模擬多個車輛真是行駛數據。
  • 環境準備
  • 購買Hologres V4.0及以上版本實例並創建數據庫。
  • 購買AI資源。

本文以large-96core-512GB-384GB、1個節點為例。

  • 模型部署。本次方案使用的模型以及分配的資源為:

基於 Hologres 構建智能駕駛圖像高性能分析系統_Hologres_04

説明:上述模型的資源均為默認分配的資源。

操作步驟

  1. 下載圖片數據並導入至OSS。
  • 下載BDD100K 自動駕駛圖像數據集中的<font style="color:#000000;background-color:rgba(0, 0, 0, 0.04);">val.zip</font>文件。
  • 登錄OSS管理控制枱,創建Bucket並將已下載的<font style="color:#000000;background-color:rgba(0, 0, 0, 0.04);">val.zip</font>文件上傳至該Bucket路徑下。上傳操作詳情,請參見簡單上傳。

説明:文件夾名稱請使用小寫。


  1. 賬號授權。

a. 登錄RAM控制枱,創建阿里雲RAM角色並授予OSS的相關權限。

推薦授予AliyunOSSReadOnlyAccess權限。

b. 為上述阿里雲RAM角色添加登錄和Hologres的訪問權限。

  • 阿里雲賬號(主賬號)

修改RAM角色的信任策略。重點需更新如下參數:

  • Action:更新為sts:AssumeRole
  • Service:更新為hologres.aliyuncs.com
{
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "RAM": [
          "acs:ram::1866xxxx:root"
        ],
        "Service": [
          "hologres.aliyuncs.com"
        ]
      }
    }
  ],
  "Version": "1"
}
  • RAM用户(子賬號)

a. 為RAM用户授權。

  • 權限管理 > 權限策略頁面,單擊創建權限策略,並選擇腳本編輯模式創建權限策略。具體操作,請參見創建自定義權限策略

Hologres可通過該策略判斷當前RAM用户是否具備創建對應RAM角色的權限。權限策略內容如下。

{
  "Version": "1",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "hologram:GrantAssumeRole",
      "Resource": "<arn賬號>"
    }
  ]
}
  • 份管理 > 用户頁面,單擊目標RAM用户操作列中的添加權限,為RAM用户(子賬號)授予上述步驟已創建的權限策略。具體操作,請參見為RAM用户授權。

b. 為已創建的RAM角色授權。

修改RAM角色的信任策略。重點需更新如下參數:

  • Action:更新為sts:AssumeRole
  • Service:更新為hologres.aliyuncs.com
{
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "RAM": [
          "acs:ram::1866xxxx:root"
        ],
        "Service": [
          "hologres.aliyuncs.com"
        ]
      }
    }
  ],
  "Version": "1"
}
  1. 對圖片進行Embedding。

創建Object Table和Dynamic Table讀取圖片元數據,並對圖片加工Embedding。因為流程較長,Hologres直接將過程封裝成附錄:存儲過程。該存儲過程包括的能力如下:

  • 創建一張Object Table,用於讀取圖片的元數據。
  • 創建一張增量刷新的Dynamic Table結果表,用於存儲加工後的數據,並設置向量索引。該Dynamic Table未設置自動刷新,需要手動刷新。
  • Dynamic Table的刷新過程中會使用ai_embed對圖片進行Embedding。

該存儲過程的使用如下:

--存儲過程,創建Object Table和Dynamic Table,使用dt對圖片進行Embedding
CALL create_image_table_from_oss(
    oss_path => 'oss://xxxx/bdd100k/val/images',
    oss_endpoint => 'oss-cn-hangzhou-internal.aliyuncs.com',
    oss_role_arn => 'acs:ram::1xxxx:role/xxxx',
    image_table => 'public.dt_image_bdd100k',
    embedding_model =>'image_embed'
);
  1. 刷新結果表。

通過上述步驟創建的Object Table和Dynamic Table都需要手動刷新,才能完成數據加工。該步驟已被封裝為附錄:存儲過程,該存儲過程包括的能力如下:

  • 刷新一次Object Table獲取圖片元數據。
  • 刷新一次Dynamic Table,進行圖片的Embedding加工。

該存儲過程的使用如下:

--刷新Dynamic Table,將圖片Embedding
CALL refresh_image_table(
    image_table => 'public.dt_image_bdd100k'
);
  1. 圖片檢索。

圖片數據處理過後可以使用向量檢索和AI Function進行檢索。

以文搜圖:

如果使用clip-ViT-B-32模型進行以文搜圖,問題請使用英文。如果是中文問題,請換成LLM模型。以文搜圖的示例SQL如下:

--以文搜圖
SELECT
    object_uri,
    approx_cosine_distance (embedding_vector, ai_embed ('image_embed', 'a red car in the rain')) AS score
FROM
    public.dt_image_bdd100k
ORDER BY
    score DESC
LIMIT 1;

                            object_uri                         |  score   
---------------------------------------------------------------+-------
 oss://****/bd****k/val/images/b836b14a-fb13****.jpg| 0.322337151
(5 rows)

在OSS中找到第一個結果的圖片如下:

基於 Hologres 構建智能駕駛圖像高性能分析系統_SQL_05

以圖搜圖:

以圖搜圖的示例SQL如下:

--以圖搜圖
SELECT
    object_uri,
    approx_cosine_distance (embedding_vector, ai_embed ('image_embed', to_file ('oss://xxxx/val/images/b9b53753-91a5d5f8.jpg', 'oss-cn-hangzhou-internal.aliyuncs.com', 'acs:ram::18xxx:role/xxx'))) AS score
FROM
    public.dt_image_bdd100k
WHERE
    object_uri <> 'oss://hm-**-hangzhou/bd****k/val/images/b9b53753-91a5****.jpg' --排除自身
ORDER BY
    score DESC
LIMIT 1;

                          object_uri                           |  score   
---------------------------------------------------------------+------
 oss://****/bd****k/val/images/c0e9b7c4-cd8b****.jpg | 0.918008327

在OSS中找到召回的圖片,並做對比,結果如下:

基於 Hologres 構建智能駕駛圖像高性能分析系統_Hologres_06

附錄:存儲過程

  • 創建Object Table和Dynamic Table
-- Query查詢結果默認限制200行,如需更多數據請修改limit,最多展示10000行或20M。
CREATE OR REPLACE PROCEDURE create_image_table_from_oss(
    oss_path TEXT,
    oss_endpoint TEXT,
    oss_role_arn TEXT,
    image_table TEXT,
    embedding_model TEXT DEFAULT NULL,
    overwrite BOOLEAN DEFAULT FALSE
)
AS $$
DECLARE
    image_schema_name TEXT;
    image_table_name TEXT;
    obj_table_name TEXT;
    full_image_table_ident TEXT;
    full_obj_ident TEXT;
    embed_expr TEXT;
    create_sql TEXT;
    embedding_dims INT;
BEGIN
    -- 1. 拆 schema name + table name
    IF position('.' in image_table) > 0 THEN
        image_schema_name := split_part(image_table, '.', 1);
        image_table_name  := split_part(image_table, '.', 2);
    ELSE
        image_schema_name := 'public';
        image_table_name  := image_table;
    END IF;

    obj_table_name := image_table_name || '_obj_table';

    full_image_table_ident := format('%I.%I', image_schema_name, image_table_name);
    full_obj_ident    := format('%I.%I', image_schema_name, obj_table_name);
    
    -- 2. 如果需要覆蓋,先刪表和索引
    IF overwrite THEN
        DECLARE
            dyn_table_exists BOOLEAN;
            rec RECORD;
        BEGIN
            -- 檢查 dynamic table 是否存在
            SELECT EXISTS (
                SELECT 1
                FROM pg_class c
                JOIN pg_namespace n ON n.oid = c.relnamespace
                WHERE c.relname = image_table_name
                AND n.nspname = image_schema_name
            )
            INTO dyn_table_exists;

            IF dyn_table_exists THEN
                -- 2.1 關閉動態表自動刷新
                -- RAISE NOTICE 'Disabling auto refresh for %', full_image_table_ident;
                -- EXECUTE format('ALTER TABLE IF EXISTS %s SET (auto_refresh_enable=false)', full_image_table_ident);

                -- 2.2 查找 RUNNING 刷新任務並取消
                FOR rec IN
                    EXECUTE format(
                        $f$
                        SELECT query_job_id
                            FROM hologres.hg_dynamic_table_refresh_log(%L)
                            WHERE status = 'RUNNING';
                        $f$,
                        image_table
                    )
                LOOP
                    RAISE NOTICE 'Found running refresh job: %', rec.query_job_id;
                    IF hologres.hg_internal_cancel_query_job(rec.query_job_id::bigint) THEN
                        RAISE NOTICE 'Cancel job % succeeded.', rec.query_job_id;
                    ELSE
                        RAISE WARNING 'Cancel job % failed.', rec.query_job_id;
                    END IF;
                END LOOP;

                -- 2.3 刪除 Dynamic Table
                EXECUTE format('DROP TABLE IF EXISTS %s;', full_image_table_ident);
            ELSE
                RAISE NOTICE 'Dynamic table % does not exist, skip cancel job and drop.', full_image_table_ident;
            END IF;

            -- 2.4 無論如何,Object Table 都要刪除
            EXECUTE format('DROP OBJECT TABLE IF EXISTS %s;', full_obj_ident);
        END;
    END IF;

    -- 3. 創建 Object Table
    RAISE NOTICE 'Create object table: %', obj_table_name;
    EXECUTE format(
        $f$
        CREATE OBJECT TABLE %s
        WITH (
            path = %L,
            oss_endpoint = %L,
            role_arn = %L
        );
        $f$,
        full_obj_ident,
        oss_path,
        oss_endpoint,
        oss_role_arn
    );

    COMMIT;

    -- 4. 刷新 Object Table
    RAISE NOTICE 'Refresh object table: %', obj_table_name;
    EXECUTE format('REFRESH OBJECT TABLE %s;', full_obj_ident);

    COMMIT;

    -- 5. embedding 模型選擇
    IF embedding_model IS NULL OR length(trim(embedding_model)) = 0 THEN
        embed_expr := 'ai_embed(file)';

        EXECUTE 'SELECT array_length(ai_embed(''dummy''), 1)'
        INTO embedding_dims;
    ELSE
        embed_expr := format('ai_embed(%L, file)', embedding_model);

        EXECUTE format(
            'SELECT array_length(ai_embed(%L, ''dummy''), 1)',
            embedding_model
        )
        INTO embedding_dims;
    END IF;

    RAISE NOTICE 'embedding dimension is: %', embedding_dims;

    -- 6. 創建 RAG 輸出動態表
    RAISE NOTICE 'create dynamic table: %', image_table_name;
    EXECUTE format(
        $f$
        CREATE DYNAMIC TABLE %s(
            CHECK(array_ndims(embedding_vector) = 1 AND array_length(embedding_vector, 1) = %s)
        )
        WITH (
            vectors = '{
                "embedding_vector": {
                    "algorithm": "HGraph",
                    "distance_method": "Cosine",
                    "builder_params": {
                    "base_quantization_type": "sq8_uniform",
                    "max_degree": 64,
                    "ef_construction": 400,
                    "precise_quantization_type": "fp32",
                    "use_reorder": true
                    }
                }
            }',
            auto_refresh_mode = 'incremental',
            freshness = '5 minutes',
            auto_refresh_enable = 'false'
        ) AS
        SELECT
            object_uri,
            etag,
            %s AS embedding_vector
        FROM %s;
        $f$,
        full_image_table_ident,
        embedding_dims,
        embed_expr,
        obj_table_name
    );

    COMMIT;

    RAISE NOTICE '';
    RAISE NOTICE 'Create image table success: %', image_table;
    RAISE NOTICE '    Vector index is: %.embedding_vector', image_table;
END;
$$ LANGUAGE plpgsql;
  • Object Table和Dynamic Table
CREATE OR REPLACE PROCEDURE refresh_image_table(
    image_table TEXT
)
AS $$
DECLARE
    image_schema_name TEXT;
    image_table_name   TEXT;
    obj_table_name TEXT;
    full_image_table_ident TEXT;
    full_obj_ident    TEXT;
BEGIN
    -- 1. 解析 schema 和表名
    IF position('.' in image_table) > 0 THEN
        image_schema_name := split_part(image_table, '.', 1);
        image_table_name  := split_part(image_table, '.', 2);
    ELSE
        image_schema_name := 'public';
        image_table_name  := image_table;
    END IF;

    obj_table_name := image_table_name || '_obj_table';

    full_image_table_ident := format('%I.%I', image_schema_name, image_table_name);
    full_obj_ident    := format('%I.%I', image_schema_name, obj_table_name);

    -- 2. 刷新 Object Table
    RAISE NOTICE 'Refreshing Object Table: %', obj_table_name;
    EXECUTE format('REFRESH OBJECT TABLE %s;', full_obj_ident);

    -- 3. 刷新 Dynamic Table
    RAISE NOTICE 'Refreshing Dynamic Table: %', image_table_name;
    EXECUTE format('REFRESH TABLE %s;', full_image_table_ident);

    RAISE NOTICE 'Refresh image table complete: %', image_table;
END;
$$ LANGUAGE plpgsql;
  • 刪除存儲過程
CREATE OR REPLACE PROCEDURE drop_image_table(
    image_table TEXT
)
AS $$
DECLARE
    image_schema_name TEXT;
    image_table_name   TEXT;
    obj_table_name TEXT;
    full_image_table_ident TEXT;
    full_obj_ident    TEXT;
    rec RECORD;
BEGIN
    -- 1. 解析 schema 和表名
    IF position('.' in image_table) > 0 THEN
        image_schema_name := split_part(image_table, '.', 1);
        image_table_name   := split_part(image_table, '.', 2);
    ELSE
        image_schema_name := 'public';
        image_table_name   := image_table;
    END IF;

    obj_table_name := image_table_name || '_obj_table';

    full_image_table_ident := format('%I.%I', image_schema_name, image_table_name);
    full_obj_ident    := format('%I.%I', image_schema_name, obj_table_name);

    -- 2. 刪除表
    -- 2.1 關閉動態表自動刷新
    -- RAISE NOTICE 'Disabling auto refresh for %', full_image_table_ident;
    -- EXECUTE format('ALTER TABLE IF EXISTS %s SET (auto_refresh_enable=false)', full_image_table_ident);

    -- 2.2 查找 RUNNING 刷新任務並取消
    FOR rec IN
        EXECUTE format(
            $f$
            SELECT query_job_id
                FROM hologres.hg_dynamic_table_refresh_log(%L)
                WHERE status = 'RUNNING';
            $f$,
            image_table
        )
    LOOP
        RAISE NOTICE 'Found running refresh job: %', rec.query_job_id;
        IF hologres.hg_internal_cancel_query_job(rec.query_job_id::bigint) THEN
            RAISE NOTICE 'Cancel job % succeeded.', rec.query_job_id;
        ELSE
            RAISE WARNING 'Cancel job % failed.', rec.query_job_id;
        END IF;
    END LOOP;

    -- 2.3 刪除 Dynamic Table
    RAISE NOTICE 'Dropping Dynamic Table: %', image_table_name;
    EXECUTE format('DROP TABLE IF EXISTS %s;', full_image_table_ident);

    -- 2.4 刪除 Object Table
    RAISE NOTICE 'Dropping Object Table: %', obj_table_name;
    EXECUTE format('DROP OBJECT TABLE IF EXISTS %s;', full_obj_ident);

    RAISE NOTICE 'Drop image table complete: %', image_table;
END;
$$ LANGUAGE plpgsql;

如果想體驗更多操作流程,歡迎到阿里雲官網領取Hologres免費試用,開通Hologres4.0,並按照操作文檔實踐。

https://help.aliyun.com/zh/hologres/user-guide/visual-data-analysis-for-autonomous-driving