This topic describes how to create an OSS external table by using a custom storage handler and how to read from and write to the table.
Usage notes
OSS external tables do not support the cluster property.
The size of a single file cannot exceed 2 GB. You must split files that are larger than 2 GB.
Create an external table
Syntax
CREATE EXTERNAL TABLE [IF NOT EXISTS] mc_oss_extable_name
(
col_name data_type,
...
)
[comment table_comment]
[partitioned BY (col_name data_type, ...)]
stored BY '<YOUR_DEFINED_STORAGEHANDLER>'
WITH serdeproperties (
['property_name'='property_value',...]
)
location 'oss_location'
USING 'jar_name';By default, a custom storage handler does not perform data sharding. This prevents potential correctness issues. If you confirm that your handler can process sharded data, run the following command to enable data sharding and start multiple mappers.
SET odps.sql.unstructured.data.single.file.split.enabled=true;Common parameters
For more information about common parameters, see Basic syntax parameters.
Specific parameters
Parameter | Required | Description |
your_defined_storagehandler | Yes | A custom storage handler that you implement as a MaxCompute user-defined function (UDF). For more information about how to develop a UDF, see Develop UDFs. |
jar_name | Yes | The JAR package that contains the code for the custom storage handler. You must add this JAR package as a resource to your MaxCompute project. For more information about how to add a resource, see Resource operations. |
resource_name | No | If you use a custom SerDe class, specify its dependent JAR resources. These resources must contain the custom SerDe class and be added as resources to your MaxCompute project. For more information about how to add resources, see Resource operations. |
Write data
For more information about the MaxCompute write syntax, see Write data to OSS.
Query and analyze data
For more information about the SELECT syntax, see Read data from OSS.
For more information about how to optimize query plans, see Query optimization.
Example: Create an OSS external table
This example shows how to map an external table to the SampleData/ directory described in Appendix: Prepare sample data. The directory is prepared for use with a custom storage handler. The procedure is as follows:
Prerequisites
An OSS bucket and folder are available. For more information, see Create a bucket and Manage folders.
MaxCompute supports automatic folder creation in OSS. If an SQL statement involves external tables and user-defined functions (UDFs), you can use a single statement to read from and write to the tables and use the UDFs. You can also create folders manually.
MaxCompute is deployed only in specific regions. To avoid potential issues with cross-region data connections, ensure that your OSS bucket is in the same region as your MaxCompute project.
Authorization
You must have permissions to access OSS. You can use an Alibaba Cloud account, a Resource Access Management (RAM) user, or a RAM role to access OSS external tables. For more information about authorization, see Authorize access in STS mode for OSS.
You must have the CreateTable permission in the MaxCompute project. For more information about table permissions, see MaxCompute permissions.
Use MaxCompute Studio to create the TextExtractor.java, TextOutputer.java, SplitReader.java, and TextStorageHandler.java Java classes. For more information about how to develop Java programs, see Develop UDFs.
Use the one-click packaging feature of MaxCompute Studio to package TextStorageHandler.java and upload the package as a MaxCompute resource.
Assume that the resource is named
javatest-1.0-SNAPSHOT.jar. For more information about how to package, upload, and register a resource, see Package, upload, and register.NoteIf you have multiple dependencies, package each one and upload it as a separate MaxCompute resource.
Run the following command to create the OSS external table:
CREATE EXTERNAL TABLE ambulance_data_txt_external ( vehicleId INT, recordId INT, patientId INT, calls INT, locationLatitute DOUBLE, locationLongtitue DOUBLE, recordTime STRING, direction STRING ) stored BY 'com.aliyun.odps.udf.example.text.TextStorageHandler' WITH serdeproperties ( 'delimiter'='|', 'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole' ) location 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/SampleData/' USING 'javatest-1.0-SNAPSHOT.jar'; -- You can run the 'desc extended ambulance_data_txt_external;' command to view the schema of the created external table.NoteThe delimiter parameter is a custom property that defines the column separator in the OSS file. You can specify any valid string as the delimiter.
Read data from OSS. Sample command:
SELECT recordId, patientId, direction FROM ambulance_data_txt_external WHERE patientId > 25;The following result is returned:
+----------+-----------+-----------+ | recordid | patientid | direction | +----------+-----------+-----------+ | 1 | 51 | S | | 3 | 48 | NE | | 4 | 30 | W | | 5 | 47 | S | | 7 | 53 | N | | 8 | 63 | SW | | 10 | 31 | N | +----------+-----------+-----------+Write data to the OSS external table.
INSERT INTO ambulance_data_txt_external VALUES (1,16,76,1,'46.81006','-92.08174','9/14/2014 0:10','SW'); -- Query the table again to check whether the data is written. You can also check whether a new file is generated in the OSS directory. SELECT * FROM ambulance_data_txt_external WHERE recordId='16';
FAQ
Why do I receive error ODPS-0123131 when I read a DATETIME field from unstructured data by using a custom extractor?
Symptom
When you use a custom extractor to read unstructured data, if a field is of the DATETIME type, such as 2019-11-11 06:43:36, the following error occurs:
FAILED: ODPS-0123131:User defined function exception - Traceback: java.lang.IllegalArgumentException at java.sql.Date.valueOf(Date.java:143) at com.aliyun.odps.udf.example.text.TextExtractor.textLineToRecord(TextExtractor.java:194) at com.aliyun.odps.udf.example.text.TextExtractor.extract(TextExtractor.java:153) at com.aliyun.odps.udf.ExtractorHandler.extract(ExtractorHandler.java:120)Cause
The error is caused by the
Date.valueOf(parts[i])code. Thejava.sql.Date.valueOf()function accepts only strings in the"yyyy-[m]m-[d]d"format and does not support strings that include time information.Solution
Add the Joda-Time dependency and import the required classes in your code.
-- Dependency. <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.10</version> </dependency> -- Import information. import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat;Use the Joda-Time
DateTimeFormat.forPattern()function to parse the string that contains both date and time. Then, create a java.sql.Date object from the parsed value.record.setDate(index, new Date(DateTime.parse(parts[i], DateTimeFormat.forPattern("yyyy-MM-dd HH:mi:ss")).getMillis()));Use the MaxCompute client to upload the JAR package that is generated for the extractor project.
add jar /Users/gary/big_data/odps/text_extractor/target/text_extractor-1.0-SNAPSHOT.jarThe
/Users/gary/big_data/odps/text_extractor/target/text_extractor-1.0-SNAPSHOT.jarpath is the local path of the JAR package.Use the MaxCompute client to upload the third-party Joda-Time JAR package.
add jar /Users/gary/.m2/repository/joda-time/joda-time/2.10/joda-time-2.10.jarThe
/Users/gary/.m2/repository/joda-time/joda-time/2.10/joda-time-2.10.jarpath is the local path of the third-party Joda-Time JAR package.Upload test data to the specified directory in OSS. Assume that the file is named
video_play_log.txt. Sample data:5c661071dba64d5080c91da085ff1073^music-click-fast_forward^26.12.XX.XX^2019-11-11 06:43:36Read data from the external table.
select * from <project_name>.video_play_log;The following result is returned:
+------+-------+---+----------------+ | uuid | action | ip | time | +------+-------+---+----------------+ | 5c661071dba64d5080c91da085ff1073 | music-click-fast_forward | 26.12.XX.XX | 2019-11-11 06:43:36 | +------+-------+---+----------------+