Data that needs to be processed by AsterixDB could be residing outside AsterixDB storage. Examples include data files on a distributed file system such as HDFS or on the local file system of a machine that is part of an AsterixDB cluster. For AsterixDB to process such data, an end-user may create a regular dataset in AsterixDB (a.k.a. an internal dataset) and load the dataset with the data. AsterixDB also supports ‘‘external datasets’’ so that it is not necessary to “load” all data prior to using it. This also avoids creating multiple copies of data and the need to keep the copies in sync.
External data is accessed using wrappers (adapters in AsterixDB) that abstract away the mechanism of connecting with an external service, receiving its data and transforming the data into ADM records that are understood by AsterixDB. AsterixDB comes with built-in adapters for common storage systems such as HDFS or the local file system.
As an example we consider the Lineitem dataset from the TPCH schema. We assume that you have successfully created an AsterixDB instance following the instructions at Installing AsterixDB Using Managix. For constructing an example, we assume a single machine setup..
Similar to a regular dataset, an external dataset has an associated datatype. We shall first create the datatype associated with each record in Lineitem data. Paste the following in the query textbox on the webpage at http://127.0.0.1:19001 and hit ‘Execute’.
create dataverse ExternalFileDemo; use dataverse ExternalFileDemo; create type LineitemType as closed { l_orderkey:int32, l_partkey: int32, l_suppkey: int32, l_linenumber: int32, l_quantity: double, l_extendedprice: double, l_discount: double, l_tax: double, l_returnflag: string, l_linestatus: string, l_shipdate: string, l_commitdate: string, l_receiptdate: string, l_shipinstruct: string, l_shipmode: string, l_comment: string}
Here, we describe two scenarios.
Prerequisite: The host is a part of the ASTERIX cluster.
Earlier, we assumed a single machine ASTERIX setup. To satisfy the prerequisite, log-in to the machine running ASTERIX.
ASTERIX provides a built-in adapter for data residing on the local file system. The adapter is referred by its alias- 'localfs'. We create an external dataset named Lineitem and use the 'localfs' adapter.
create external dataset Lineitem(LineitemType) using localfs
Above, the definition is not complete as we need to provide a set of parameters that are specific to the source file.
As we are using a single single machine ASTERIX instance, we use 127.0.0.1 as host in the path parameter. We complete the create dataset statement as follows.
use dataverse ExternalFileDemo; create external dataset Lineitem(LineitemType) using localfs (("path"="127.0.0.1://SOURCE_PATH"), ("format"="delimited-text"), ("delimiter"="|"));
Please substitute SOURCE_PATH with the absolute path to the source file on the local file system.
An incorrect value for the path parameter will give the following exception message when the dataset is used in a query.
edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException: edu.uci.ics.hyracks.api.exceptions.HyracksDataException: edu.uci.ics.hyracks.api.exceptions.HyracksDataException: Job failed.
Verify the correctness of the path parameter provided to the localfs adapter. Note that the path parameter must be an absolute path to the data file. For e.g. if you saved your file in your home directory (assume it to be /home/joe), then the path value should be
127.0.0.1:///home/joe/lineitem.tbl.
In your web-browser, navigate to 127.0.0.1:19001 and paste the above to the query text box. Finally hit 'Execute'.
Next we move over to the the section Writing Queries against an External Dataset and try a sample query against the external dataset.
rerequisite: It is required that the Namenode and HDFS Datanodes are reachable from the hosts that form the AsterixDB cluster. AsterixDB provides a built-in adapter for data residing on HDFS. The HDFS adapter can be referred (in AQL) by its alias - ‘hdfs’. We can create an external dataset named Lineitem and associate the HDFS adapter with it as follows;
create external dataset Lineitem(LineitemType) using hdfs((“hdfs”:”hdfs://localhost:54310”),(“path”:”/asterix/Lineitem.tbl”),...,(“input- format”:”rc-format”));
The expected parameters are described below:
Difference between 'input-format' and 'format'
input-format: Files stored under HDFS have an associated storage format. For example, TextInputFormat represents plain text files. SequenceFileInputFormat indicates binary compressed files. RCFileInputFormat corresponds to records stored in a record columnar fashion. The parameter ‘input-format’ is used to distinguish between these and other HDFS input formats.
format: The parameter ‘format’ refers to the type of the data contained in the file. For example, data contained in a file could be in json or ADM format, could be in delimited-text with fields separated by a delimiting character or could be in binary format.
As an example. consider the data file. The file is a text file with each line representing a record. The fields in each record are separated by the '|' character.
We assume the HDFS URL to be hdfs://localhost:54310. We further assume that the example data file is copied to HDFS at a path denoted by “/asterix/Lineitem.tbl”.
The complete set of parameters for our example file are as follows. ((“hdfs”=“hdfs://localhost:54310”,(“path”=“/asterix/Lineitem.tbl”),(“input-format”=“text- input-format”),(“format”=“delimited-text”),(“delimiter”=“|”))
if a user wants to create an external dataset that uses hive-parser to parse HDFS records, it is important that the datatype associated with the dataset matches the actual data in the Hive table for the correct initialization of the Hive SerDe. Here is the conversion from the supported Hive data types to AsterixDB data types:
Example 1: We can modify the create external dataset statement as follows:
create external dataset Lineitem('LineitemType) using hdfs(("hdfs"="hdfs://localhost:54310"),("path"="/asterix/Lineitem.tbl"),("input-format"="text- input-format"),("format"="delimited-text"),("delimiter"="|"));
Example 2: Here, we create an external dataset of lineitem records stored in sequence files that has content in ADM format:
create external dataset Lineitem('LineitemType) using hdfs(("hdfs"="hdfs://localhost:54310"),("path"="/asterix/SequenceLineitem.tbl"),("input- format"="sequence-input-format"),("format"="adm"));
Example 3: Here, we create an external dataset of lineitem records stored in record-columnar files that has content in binary format parsed using hive-parser with hive ColumnarSerde:
create external dataset Lineitem('LineitemType) using hdfs(("hdfs"="hdfs://localhost:54310"),("path"="/asterix/RCLineitem.tbl"),("input-format"="rc-input-format"),("format"="binary"),("parser"="hive-parser"),("hive- serde"="org.apache.hadoop.hive.serde2.columnar.ColumnarSerde"));
You may write AQL queries against an external dataset in exactly the same way that queries are written against internal datasets. The following is an example of an AQL query that applies a filter and returns an ordered result.
use dataverse ExternalFileDemo; for $c in dataset('Lineitem') where $c.l_orderkey <= 3 order by $c.l_orderkey, $c.l_linenumber return $c
AsterixDB supports building B-Tree and R-Tree indexes over static data stored in the Hadoop Distributed File System. To create an index, first create an external dataset over the data as follows
create external dataset Lineitem(LineitemType) using hdfs(("hdfs"="hdfs://localhost:54310"),("path"="/asterix/Lineitem.tbl"),("input-format"="text-input- format"),("format"="delimited-text"),("delimiter"="|"));
You can then create a B-Tree index on this dataset instance as if the dataset was internally stored as follows:
create index PartkeyIdx on Lineitem(l_partkey);
You could also create an R-Tree index as follows:
create index IndexName on DatasetName(attribute-name) type rtree;
After building the indexes, the AsterixDB query compiler can use them to access the dataset and answer queries in a more cost effective manner. AsterixDB can read all HDFS input formats, but indexes over external datasets can currently be built only for HDFS datasets with 'text-input-format', 'sequence-input-format' or 'rc-input-format'.
An external data snapshot represents the status of a dataset's files in HDFS at a point in time. Upon creating the first index over an external dataset, AsterixDB captures and stores a snapshot of the dataset in HDFS. Only records present at the snapshot capture time are indexed, and any additional indexes created afterwards will only contain data that was present at the snapshot capture time thus preserving consistency across all indexes of a dataset. To update all indexes of an external dataset and advance the snapshot time to be the present time, a user can use the refresh external dataset command as follows:
refresh external dataset DatasetName;
After a refresh operation commits, all of the dataset's indexes will reflect the status of the data as of the new snapshot capture time.
Q. I added data to my dataset in HDFS, Will the dataset indexes in AsterixDB be updated automatically?
A. No, you must use the refresh external dataset statement to make the indexes aware of any changes in the dataset files in HDFS.
Q. Why doesn't AsterixDB update external indexes automatically?
A. Since external data is managed by other users/systems with mechanisms that are system dependent, AsterixDB has no way of knowing exactly when data is added or deleted in HDFS, so the responsibility of refreshing indexes are left to the user. A user can use internal datasets for which AsterixDB manages the data and its indexes.
Q. I created an index over an external dataset and then added some data to my HDFS dataset. Will a query that uses the index return different results from a query that doesn't use the index?
A. No, queries' results are access path independent and the stored snapshot is used to determines which data are going to be included when processing queries.
Q. I created an index over an external dataset and then deleted some of my dataset's files in HDFS, Will indexed data access still return the records in deleted files?
A. No. When AsterixDB accesses external data, with or without the use of indexes, it only access files present in the file system at runtime.
Q. I submitted a refresh command on a an external dataset and a failure occurred, What has happened to my indexes?
A. External Indexes Refreshes are treated as a single transaction. In case of a failure, a rollback occurs and indexes are restored to their previous state. An error message with the cause of failure is returned to the user.
Q. I was trying to refresh an external dataset while some queries were accessing the data using index access method. Will the queries be affected by the refresh operation?
A. Queries have access to external dataset indexes state at the time where the queries are submitted. A query that was submitted before a refresh commits will only access data under the snapshot taken before the refresh; queries that are submitted after the refresh commits will access data under the snapshot taken after the refresh.
Q. What happens when I try to create an additional index while a refresh operation is in progress or vice versa?
A. The create index operation will wait until the refresh commits or aborts and then the index will be built according to the external data snapshot at the end of the refresh operation. Creating indexes and refreshing datasets are mutually exclusive operations and will not be run in parallel. Multiple indexes can be created in parallel, but not multiple refresh operations.