The ai_query and ai_embedding_multimodal functions in EMR Serverless Spark provide multimodal capabilities for image understanding and embedding vector generation.
Supported versions
These functions are supported only in Spark 3.5.2. You must use EMR Serverless Spark esr-4.7.0 or a later version.
ai_embedding_multimodal and its related model services are available only in specific regions. See the notes in ai_embedding_multimodal for details.
Function signatures
ai_query
The ai_query function calls a large language model for inference and supports image data as multimodal input. The function signature:
ai_query(prompt [, service_name] [, options][, data][, data_type])
The following table describes the parameters.
|
Parameter |
Required |
Description |
|
|
Yes |
The full prompt sent to the model. It should include context, instructions, and input data. We recommend explicitly specifying the output format to improve stability. |
|
|
No |
Specifies the model service to call. If omitted, the default model |
|
|
No |
A JSON string containing additional parameters to control the generation behavior. For more information about the supported parameters, see the documentation for the options parameter. |
|
|
No |
The column containing the image data to process. This parameter is required only when processing image data. The value to pass depends on the
|
|
|
No |
Specifies how the image data is passed. The following values are supported:
|
Named parameter example:
ai_query(
'your prompt',
service_name => 'your_model_service_name',
options => '{"temperature":0.1}',
data => image_col,
data_type => 'binary'
)
Supported named parameters: service_name, options, data, and data_type.
ai_embedding_multimodal
This AI Function is only available in the following regions: China (Beijing), China (Shanghai), China (Hangzhou), China (Shenzhen), China (Ulanqab), China (Chengdu), and China (Zhangjiakou).
The ai_embedding_multimodal function generates an embedding vector from an image for similarity calculations, retrieval, and other tasks. The function signature:
ai_embedding_multimodal(data [, service_name] [, options] [, data_type])
The following table describes the parameters.
|
Parameter |
Required |
Description |
|
|
Yes |
The column containing the image data from which to generate an embedding vector. The value to pass depends on the
|
|
|
No |
Specifies the embedding model service to call. If omitted, the default model |
|
|
No |
A JSON string containing additional parameters to control the generation behavior. The supported parameters depend on the target embedding service. |
|
|
No |
Specifies how the image data is passed. The following values are supported:
|
Named parameter example:
ai_embedding_multimodal(
image_col,
service_name => 'tongyi-embedding-vision-plus',
data_type => 'binary'
)
Supported named parameters: service_name, options, and data_type.
Notes
The ai_query function is a chat-type request and has the following default behavior:
-
If you do not pass
enable_thinkingin theoptionsparameter, the system automatically adds{"enable_thinking": false}. -
If you explicitly pass
enable_thinking, your specified setting is used.
For example, the following two queries are equivalent and both disable thinking:
-- Method 1: Omit options. Thinking is disabled by default.
SELECT ai_query('Describe the image content', data => content) FROM image_table;
-- Method 2: Explicitly disable thinking.
SELECT ai_query(
'Describe the image content',
data => content,
options => '{"enable_thinking": false}'
) FROM image_table;
To enable thinking, you must explicitly pass the parameter:
SELECT ai_query(
'Describe the image content',
data => content,
options => '{"enable_thinking": true}'
) FROM image_table;
The ai_embedding_multimodal function is not a chat-type request. Support for a specific options field depends on the target embedding service.
Use cases
Use case 1: Process data by image path
If your table contains only image paths pointing to OSS, HDFS, or another Hadoop-compatible file system, use the uri mode to have the function read file content internally.
Example: Identify license plate numbers from images based on their file paths.
SELECT
path,
ai_query(
'Return the license plate number in the image. IMPORTANT: Reply with only the plate number; if the image is too blurry to recognize, reply ''Unable to recognize''.',
service_name => 'qwen3.5-plus',
data => path,
data_type => 'uri'
) AS plate_number
FROM (
SELECT /*+ REPARTITION(10) */ path
FROM ccpd_1m_1000
) t;
-
data => pathspecifies the path column, anddata_type => 'uri'indicates that the function reads files by path. -
It is recommended to control the number of partitions by using the
REPARTITIONhint in an inner subquery, instead of specifying it directly on the outer projection that contains an AI function. -
If you do not specify
options.enable_thinking, it defaults tofalse.
To explicitly control the thinking configuration, use the options parameter:
SELECT
path,
ai_query(
'Return the license plate number in the image. IMPORTANT: Reply with only the plate number; if the image is too blurry to recognize, reply ''Unable to recognize''.',
service_name => 'qwen3.5-plus',
data => path,
data_type => 'uri',
options => '{"enable_thinking": false}'
) AS plate_number
FROM (
SELECT /*+ REPARTITION(10) */ path
FROM ccpd_1m_1000
) t;
Use case 2: Process data with binary content
Use the read_files function to read images in bulk from a directory, then pass the returned content column (BINARY type) as multimodal input.
Example: Read images in bulk from an OSS directory and identify license plate numbers.
SELECT
path,
ai_query(
'Return the license plate number in the image. IMPORTANT: Reply with only the plate number.',
service_name => 'qwen3.5-plus',
data => content
) AS plate_number
FROM read_files(
'oss://bucket/path/to/images/',
suffix => 'jpg,jpeg,png'
);
-
The
read_filesfunction returns four columns:path,content,modificationTime, andlength. Thecontentcolumn is of the BINARY type and can be passed directly to thedataparameter. -
This scenario uses the default
data_type => 'binary', which does not need to be explicitly specified. -
suffixspecifies a comma-separated list of case-insensitive suffixes. For example, bothjpgand.jpgare valid. -
By default,
read_filesdoes not recursively read subdirectories. To read them recursively, passrecursive => true. -
The
read_filesoperation generally does not require an additional manualREPARTITION. You can control the scan partition granularity by using thespark.sql.files.maxPartitionBytesparameter.
Use case 3: Generate image embedding vectors
Use the ai_embedding_multimodal function to convert images into embedding vectors for tasks such as similarity search and cluster analysis. Both uri mode and binary mode are supported.
Method 1: Generate an embedding vector from an image path (uri mode).
SELECT
path,
ai_embedding_multimodal(
path,
service_name => 'tongyi-embedding-vision-plus',
data_type => 'uri'
) AS embedding
FROM image_paths_table;
Method 2: Generate an embedding vector from image binary content (binary mode).
SELECT
path,
ai_embedding_multimodal(
content,
service_name => 'tongyi-embedding-vision-plus'
) AS embedding
FROM read_files(
'oss://bucket/path/to/images/',
suffix => 'jpg,png'
);
read_files function
The read_files function reads file content in bulk from a file system and is commonly used with multimodal functions. The function signature:
read_files(path [, suffix] [, recursive])
The following table describes the parameters.
|
Parameter |
Required |
Description |
|
|
Yes |
The path to a directory or a single file. |
|
|
No |
A comma-separated list of file suffixes, such as |
|
|
No |
BOOLEAN. Specifies whether to recursively read subdirectories. The default value is |
Returned columns
|
Column Name |
Type |
Description |
|
|
STRING |
The full path of the file. |
|
|
BINARY |
The binary content of the file. |
|
|
TIMESTAMP |
The time the file was last modified. |
|
|
BIGINT |
The size of the file in bytes. |
Examples:
-- Read all files in a directory
SELECT * FROM read_files('oss://bucket/images/');
-- Filter files by suffix
SELECT path, content, length
FROM read_files('oss://bucket/images/', suffix => 'jpg,jpeg,png');
-- Recursively read subdirectories
SELECT path, content
FROM read_files(
'oss://bucket/images/',
suffix => 'jpg,png',
recursive => true
);
-
read_filessupports only the named parameterssuffixandrecursive. -
The
suffixfilter is pushed down to the file scanning stage to avoid reading other large files in the directory. -
read_filescurrently does not support theformatHintparameter.
Usage example
The following example creates a temporary view to control partitioning before calling a multimodal function:
CREATE OR REPLACE TEMPORARY VIEW car_images AS
SELECT /*+ REPARTITION(8) */ path
FROM ccpd_1m_1000;
SELECT
path,
ai_query(
'Return the license plate number in the image. IMPORTANT: Reply with only the plate number; if the image is too blurry to recognize, reply ''Unable to recognize''.',
service_name => 'qwen3.5-plus',
data => path,
data_type => 'uri'
) AS plate_number
FROM car_images
LIMIT 20;
Common errors
|
Error Message |
Cause |
Solution |
|
|
The image format is not supported. |
Use common formats such as JPEG, PNG, or WebP. Confirm that the target model service supports the corresponding MIME type. |
|
|
The file content is incomplete or not a valid image. |
Check whether the source file is corrupted. Confirm that the |
|
|
The |
Check whether the model service name exists or confirm that the default model service is configured correctly. |
|
|
|
For path columns, change the parameter to |
Performance optimization
Control partitions for path-based tables
Place the REPARTITION hint in an inner subquery and run the AI function in the outer query. You can also use a CTE or CREATE TEMPORARY VIEW:
-- Method 1: Subquery
SELECT
path,
ai_query('Describe the image content', service_name => 'qwen3.5-plus', data => path, data_type => 'uri') AS result
FROM (
SELECT /*+ REPARTITION(32) */ path FROM large_image_dataset
) t;
-- Method 2: CTE
WITH car_images AS (
SELECT /*+ REPARTITION(32) */ path FROM ccpd_1m_1000
)
SELECT
path,
ai_query('Describe the image content', service_name => 'qwen3.5-plus', data => path, data_type => 'uri') AS result
FROM car_images;
-- Method 3: Temporary view
CREATE OR REPLACE TEMPORARY VIEW car_images AS
SELECT /*+ REPARTITION(32) */ path FROM ccpd_1m_1000;
SELECT
path,
ai_query('Describe the image content', service_name => 'qwen3.5-plus', data => path, data_type => 'uri') AS result
FROM car_images;
Control parallelism for read_files
When read_files scans a directory directly, manual REPARTITION is usually unnecessary. To increase parallelism or reduce partition size, adjust spark.sql.files.maxPartitionBytes instead.
SET spark.sql.files.maxPartitionBytes = 134217728;
Filter by suffix during file reading
Filter file types with the suffix parameter to reduce unnecessary file scans and downstream AI requests. To recursively read subdirectories, add recursive => true:
SELECT path, content
FROM read_files('oss://bucket/images/', suffix => 'jpg,jpeg,png');
Supported image formats
|
Format |
MIME type |
Magic number detection |
|
JPEG |
|
|
|
PNG |
|
|
|
GIF |
|
|
|
WebP |
|
|
|
BMP |
|
|
|
TIFF |
|
|
|
ICO |
|
|
|
AVIF |
|
|
|
HEIF |
|
|