- Data Model
- Query Language
- Data Storage
- System Architecture and Component
- Future Work
Hive is an open-source data warehousing solution built on top of Hadoop. It supports an SQL-like query language called HiveQL. These queries are compiled into MapReduce jobs that are executed on Hadoop. While Hive uses Hadoop for execution of queries, it reduces the effort that goes into writing and maintaining MapReduce jobs.
Hive supports database concepts like tables, columns, rows and partitions. Both primitive (integer, float, string) and complex data-types(map, list, struct) are supported. Moreover, these types can be composed to support structures of arbitrary complexity. The tables are serialized/deserialized using default serializers/deserializer. Any new data format and type can be supported by implementing SerDe and ObjectInspector java interface.
Hive query language (HiveQL) consists of a subset of SQL along with some extensions. The language is very SQL-like and supports features like subqueries, joins, cartesian product, group by, aggregation, describe and more. MapReduce programs can also be used in Hive queries. A sample query using MapReduce would look like this:
FROM (MAP inputdata USING 'python mapper.py' AS (word, count)FROM inputtableCLUSTER BY word)REDUCE word, count USING 'python reduce.py';
This query uses mapper.py for transforming inputdata into (word, count) pair, distributes data to reducers by hashing on word column (given by CLUSTER) and uses reduce.py.
Notice that Hive allows the order of FROM and SELECT/MAP/REDUCE to be changed within a sub-query. This allows insertion of different transformation results into different tables/partitions/hdfs/local directory as part of the same query and reduces the number of scans on the input data.
INSERT INTO, UPDATE, and DELETE are not supported which makes it easier to handle reader and writer concurrency.
While a table is the logical data unit in Hive, the data is actually stored into hdfs directories. A table is stored as a directory in hdfs, partition of a table as a subdirectory within a directory and bucket as a file within the table/partition directory. Partitions can be created either when creating tables or by using INSERT/ALTER statement. The partitioning information is used to prune data when running queries. For example, suppose we create partition for day=monday using the query
ALTER TABLE dummytable ADD PARTITION (day='monday')
Next, we run the query -
SELECT * FROM dummytable WHERE day='monday'
Suppose the data in dummytable is stored in /user/hive/data/dummytable directory. This query will only scan the subdirectory /user/hive/data/dummytable/day=monday within the dummytable directory.
A bucket is a file within the leaf directory of a table or a partition. It can be used to prune data when the user runs a SAMPLE query.
Any data stored in hdfs can be queried using the EXTERNAL TABLE clause by specifying its location with the LOCATION clause. When dropping an external table, only its metadata is deleted and not the data itself.
Hive implements the LazySerDe as the default SerDe. It deserializes rows into internal objects lazily so that the cost of Deserialization of a column is incurred only when it is needed. Hive also provides a RegexSerDe which allows the use of regular expressions to parse columns out from a row. Hive also supports various formats like TextInputFormat, SequenceFileInputFormat and RCFileInputFormat. Other formats can also be implemented and specified in the query itself. For example,
CREATE TABLE dummytable(key INT, value STRING)STORED ASINPUTFORMATorg.apache.hadoop.mapred.SequenceFileInputFormatOUTPUTFORMATorg.apache.hadoop.mapred.SequenceFileOutputFormat
Life Cycle of a query
The query is submitted via CLI/web UI/any other interface. This query goes to the compiler and undergoes parse, type-check and semantic analysis phases using the metadata from Metastore. The compiler generates a logical plan which is optimized by the rule-based optimizer and an optimized plan in the form of DAG of MapReduce and hdfs tasks is generated. The execution engine executes these tasks in the correct order using Hadoop.
It stores all information about the tables, their partitions, schemas, columns and their types, etc. Metastore runs on traditional RDBMS (so that latency for metadata query is very small) and uses an open source ORM layer called DataNuclues. Matastore is backed up regularly. To make sure that the system scales with the number of queries, no metadata queries are made the mapper/reducer of a job. Any metadata needed by the mapper or the reducer is passed through XML plan files that are generated by the compiler.
Hive Query Compiler works similar to traditional database compilers.
Some optimizations are not enabled by default but can be activated by setting certain flags. These include:
Execution Engine executes the tasks in order of their dependencies. A MapReduce task first serializes its part of the plan into a plan.xml file. This file is then added to the job cache and mappers and reducers are spawned to execute relevant sections of the operator DAG. The final results are stored to a temporary location and then moved to the final destination (in the case of say INSERT INTO query).
The paper mentions the following areas for improvements: