Big Data

Hive views and indexing

This lecture saves SELECT results as views and speeds up filtered queries with indexes. It covers view creation and alteration, compact and bitmap indexes, and deferred rebuilds. After this page you can build bitmap vectors by hand and answer AND, OR and NOT queries on them. You can also run the full CREATE, SHOW, ALTER and DROP index cycle.

Views in HiveSearch on YouTube

A Hive view is a searchable object defined by a query. It behaves like a Hive table. It stores no data of its own. For this reason it is also called a virtual table.

A view stores its defining query, not data. Query it like a table. Combine data from more than one table with joins inside the view. Keep only a subset of rows or columns to hide the rest from some users.

The slides list the same uses as SQL views. They are: save any result set, run operations through the view, and expose a subset of the data.

base table stores the data emp_tab, 6 rows saved query view no stored data reruns SELECT fresh on every read
A view stores the query, not the rows. Every read reruns the SELECT on the base table.

Creating a Hive viewSearch on YouTube

CREATE VIEW [IF NOT EXISTS] view_name
  [(column_name [COMMENT column_comment], ...)]
  [COMMENT table_comment]
AS SELECT ...;

Name the view. List output columns if the SELECT names need overrides. End with the SELECT that defines the rows.

Base table emp_tabSearch on YouTube

The slides build every view demo on one table, emp_tab, with 7 columns and 6 rows:

col1col2col3col4col5col6col7
1281ShawnArchitect7890148110IXZ
1381JacobAdmin4560148120POI
1481flinkMgr9580168110IXZ
1581RichardDeveloper1000168140LKJ
1681MiraMgr5098148110IKZ
1781JohnDeveloper6500168110IXZ
SELECT * FROM emp_tab;
emp_tab.col1  emp_tab.col2  emp_tab.col3  emp_tab.col4  emp_tab.col5  emp_tab.col6  emp_tab.col7
1281  Shawn    Architect  7890  1481  10  IXZ
1381  Jacob    Admin      4560  1481  20  POI
1481  flink    Mgr        9580  1681  10  IXZ
1581  Richard  Developer  1000  1681  40  LKJ
1681  Mira     Mgr        5098  1481  10  IKZ
1781  John     Developer  6500  1681  10  IXZ
Time taken: 2.176 seconds, Fetched: 6 row(s)

Narrow view emp_view2Search on YouTube

The first view keeps only 3 of the 7 columns:

CREATE VIEW emp_view2 AS SELECT col1, col2, col3 FROM emp_tab;
SELECT * FROM emp_view2;
emp_view2.col1  emp_view2.col2  emp_view2.col3
1281  Shawn    Architect
1381  Jacob    Admin
1481  flink    Mgr
1581  Richard  Developer
1681  Mira     Mgr
1781  John     Developer
Time taken: 0.773 seconds, Fetched: 6 row(s)

Worked example. Check the narrow view against the base table.

All 6 rows survive. Columns col4 through col7 are gone. Nothing else changes: row 3 is still 1481 flink Mgr, row 5 is still 1681 Mira Mgr. A view that drops columns keeps every row.

Full view emp_view1Search on YouTube

The second view keeps the whole table. The slide hides its query text. The output matches a full-table select:

CREATE VIEW emp_view1 AS SELECT * FROM emp_tab;
SELECT * FROM emp_view1;
emp_view1.col1  emp_view1.col2  emp_view1.col3  emp_view1.col4  emp_view1.col5  emp_view1.col6  emp_view1.col7
1281  Shawn    Architect  7890  1481  10  IXZ
1381  Jacob    Admin      4560  1481  20  POI
1481  flink    Mgr        9580  1681  10  IXZ
1581  Richard  Developer  1000  1681  40  LKJ
1681  Mira     Mgr        5098  1481  10  IKZ
1781  John     Developer  6500  1681  10  IXZ
Time taken: 0.424 seconds, Fetched: 6 row(s)

(The reconstructing query above is marked (extra): the slide shows the output, not the query.)

Salary-filter view emp_35000Search on YouTube

The last view demo filters rows. The base table is employee:

IDNameSalaryDesignationDept
1201Michel45000Technical managerTP
1202Chandler45000ProofreaderPR
1203Ross40000Technical writerTP
1204Joey40000Hr AdminHR
1205Monika35000Op AdminAdmin
CREATE VIEW emp_35000 AS
SELECT * FROM employee
WHERE salary > 35000;

Worked example. Which rows pass salary > 35000?

1201: 45000>35000  ⇒  kept1202: 45000>35000  ⇒  kept1203: 40000>35000  ⇒  kept1204: 40000>35000  ⇒  kept1205: 35000>35000  ⇒  dropped (strict test)\begin{aligned} 1201&:\ 45000 \gt 35000 \;\Rightarrow\; \text{kept}\\ 1202&:\ 45000 \gt 35000 \;\Rightarrow\; \text{kept}\\ 1203&:\ 40000 \gt 35000 \;\Rightarrow\; \text{kept}\\ 1204&:\ 40000 \gt 35000 \;\Rightarrow\; \text{kept}\\ 1205&:\ 35000 \gt 35000 \;\Rightarrow\; \text{dropped (strict test)} \end{aligned}

The view holds 4 rows: 1201, 1202, 1203, 1204. Monika drops out because the test is strict. A salary equal to the limit fails it.

Altering a viewSearch on YouTube

Two ALTER forms appear on the slides. One replaces the defining query. The other renames the view.

ALTER VIEW emp_view1 AS SELECT col1 FROM emp_tab;
SELECT * FROM emp_view1;
emp_view1.col1
1281
1381
1481
1581
1681
1781
Time taken: 0.175 seconds, Fetched: 6 row(s)

The view now has one column. All 6 ids survive.

ALTER VIEW emp_view1 RENAME TO emp_view_new;
SELECT * FROM emp_view_new;
emp_view_new.col1
1281
1381
1481
1581
1681
1781
Time taken: 0.72 seconds, Fetched: 6 row(s)

Rename changes the name. The rows stay the same.

Worked example. Trace the shape of emp_view1 through both ALTER steps.

Start: 6 rows ×\times 7 columns (full table). After ALTER ... AS SELECT col1: 6 rows ×\times 1 column. After RENAME TO emp_view_new: still 6 rows ×\times 1 column, under the new name. ALTER changes the query or the name, never the base table.

Indexing in HiveSearch on YouTube

An index speeds up queries that filter on a column. Use one when the dataset is very large, when a query runs longer than expected, when speed matters, and while building a data model.

A Hive index lives in a separate table. It never touches the data inside the base table. Like a table, an index can itself be partitioned when the data is large.

An index is a pointer to a column of a table. The user creates it by hand. The index does not track base-table changes. Run ALTER INDEX ... REBUILD after the data changes.

Compact and bitmap index typesSearch on YouTube

The slides name two index types:

  • Compact index. Stores pairs of indexed column value and block id. A query on the value goes straight to the listed blocks.
  • Bitmap index. Stores each distinct value together with a bit vector over the rows. Bit ii is 1 when row ii holds the value, else 0.

Both serve the same purpose. Fetch time differs with the data in the indexed column. A later section times both on the same query.

compact AISQUAD + block id AIM + block id value + block id one row per value per block bitmap, first 6 rows AISQUAD -> 110011 AIM -> 001100 value + bit vector one bit per row 1 means row has it
Compact stores value-block pairs. Bitmap vectors cover the first 6 rows: one bit per row.

Creating an indexSearch on YouTube

CREATE INDEX index_name
ON TABLE base_table_name (col_name, ...)
AS index_type
[WITH DEFERRED REBUILD]
[IN TABLE index_table_name]
[COMMENT 'index comment'];

index_type is the full handler class for a compact index, or the word BITMAP for a bitmap index. WITH DEFERRED REBUILD leaves the new index empty until an ALTER rebuilds it.

Example 1: an attendance table with columns roll_id, class, days_attended:

CREATE INDEX index_attendance ON TABLE mark_sheet(days_attended)
AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'
WITH DEFERRED REBUILD;

Example 2: a compact index on an employee id:

CREATE INDEX idx_EmpID_Emp ON TABLE Emp(EmpID)
AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'
WITH DEFERRED REBUILD;

The same name with a bitmap index on the department column instead:

CREATE INDEX idx_EmpID_Emp ON TABLE Emp(DeptNo)
AS 'BITMAP'
WITH DEFERRED REBUILD;

The slides use both the full class name and the short words COMPACT and BITMAP as the index type. Both forms appear in the demo commands below.

The EMP_INFO demo tableSearch on YouTube

The timing demo indexes a 20-row table, EMP_INFO (emp_id, emp_name, dept, joining_year):

emp_idemp_namedeptjoining_year
249972SwatiAISQUAD2010
249973TanjilaAISQUAD2010
249974ShwetaAIM2010
149975SheelaAIM2012
249976RajeshAISQUAD2010
249977SuvarnaAISQUAD2012
249978DalveerAIM2013
249979PriyankAIM2013
249980KritiAISQUAD2013
249981SanjanaAIM2012
249982SnehaAISQUAD2010
249983RasikaAIM2010
249984RenuAISQUAD2012
249985SheetalAIM2013
249986SanamAISQUAD2010
249987VaishuAIM2012
249988VidyaAISQUAD2010
249989RamaAIM2013
249990ShyamAISQUAD2013
249991ReshamAIM2010

The demo creates the index with the short type word:

CREATE INDEX ind_dept ON TABLE EMP_INFO(dept)
AS 'COMPACT' WITH DEFERRED REBUILD;

Two more variants change only the storage of the index table:

CREATE INDEX ind_dept2 ON TABLE EMP_INFO(dept)
AS 'COMPACT' WITH DEFERRED REBUILD STORED AS RCFILE;
CREATE INDEX ind_dept3 ON TABLE EMP_INFO(dept)
AS 'COMPACT' WITH DEFERRED REBUILD
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\n'
STORED AS TEXTFILE;

Showing an indexSearch on YouTube

SHOW FORMATTED INDEX ON EMP_INFO;

The output lists one row per index on the table: the index name, the base table, the indexed columns, the index table, and the type:

idx_nametab_namecol_namesidx_tab_nameidx_type
ind_deptemp_infodeptdefault__emp_info_ind_dept__compact
ind_dept2emp_infodeptdefault__emp_info_ind_dept2__compact
ind_dept3emp_infodeptdefault__emp_info_ind_dept3__compact
ind_dept4emp_infodeptdefault__emp_info_ind_dept4__bitmap

Four indexes sit on the same column here. The slides allow any number of indexes of any type on one table and one column.

Rebuilding an indexSearch on YouTube

WITH DEFERRED REBUILD creates an empty index, even when the table holds data. The index table fills only after an explicit rebuild. A rebuild is needed again whenever rows are overwritten or appended, because the index table does not track the change on its own.

ALTER INDEX ind_dept ON EMP_INFO REBUILD;

If the base table has partitions, the REBUILD needs the partition details. Name the Hive partition in the ALTER INDEX statement.

Write ON before the table name. The slides show the missing-ON form failing first: ALTER INDEX ind_dept EMP_INFO REBUILD raises ParseException, then the same command with ON runs.

The ALTER launches a MapReduce job, because the index is itself a table. The slide job reads the base table and writes the index table:

Table default.default__emp_info_ind_dept__ stats:
  [numFiles=1, numRows=2, totalSize=245, rawDataSize=243]
Time taken: 369.636 seconds

Worked example. Why does the rebuilt index hold exactly 2 rows?

The compact index stores one entry per indexed value per block as a (value, block id) pair. dept has 2 distinct values: AISQUAD and AIM. EMP_INFO holds one block (numFiles=1). So the index holds 2 rows. The 20 base-table rows collapse into 2 index rows.

CREATE with DEFERRED index empty ALTER ... REBUILD MR job runs index filled 2 rows
Deferred rebuild in three states: empty at creation, a MapReduce job on ALTER, filled after.

Bitmap indexing in detailSearch on YouTube

A bitmap index suits read-only queries over large datasets. Each distinct value of the indexed column gets one bit vector. The vector has one bit per row of the table. Bit ii is 1 when row ii holds the value. A 0 means the row lacks it.

The slides demo on a 4-row employee table:

EmpNoEmpNameJobNew_EmpSalary
1AliceAnalystYes15000
2JoeSalespersonNo10000
3KatyClerkNo12000
4AnnieManagerYes25000

Vectors for New_EmpSearch on YouTube

New_Emp has 2 distinct values, so it gets 2 vectors of 4 bits. Read rows 1 to 4 left to right.

Yes=1001No=0110\text{Yes} = 1001 \qquad\qquad \text{No} = 0110

Rows 1 and 4 hold Yes, so bits 1 and 4 are 1: 1001. Rows 2 and 3 hold No, so bits 2 and 3 are 1: 0110. Each row sets exactly one of the two vectors.

Vectors for JobSearch on YouTube

Job has 4 distinct values, so it gets 4 vectors. Each value occurs once, so each vector has a single 1.

Analyst=1000Salesperson=0100Clerk=0010Manager=0001\text{Analyst} = 1000 \qquad \text{Salesperson} = 0100 \qquad \text{Clerk} = 0010 \qquad \text{Manager} = 0001

Row 1 is the Analyst, row 2 the Salesperson, row 3 the Clerk, row 4 the Manager. The position of the 1 marks the row.

AND query on two bitmapsSearch on YouTube

Find employees who are not new and are salespeople:

SELECT *
FROM Employee
WHERE New_Emp = 'No' AND Job = 'Salesperson';

The engine fetches two vectors and ANDs them bit by bit. No table scan runs.

Worked example. AND the two vectors.

No=0110Salesperson=01000110 AND 0100=0100\begin{aligned} \text{No} &= 0110\\ \text{Salesperson} &= 0100\\ 0110 \text{ AND } 0100 &= \mathbf{0100} \end{aligned}

Bit by bit: 0,1∧1=1,1∧0=0,00, 1 \land 1 = 1, 1 \land 0 = 0, 0. Only bit 2 survives. The answer is row 2: Joe, Salesperson, No, 10000.

Worked example (extra). OR and NOT on the same vectors.

OR keeps rows that satisfy either predicate. NOT flips every bit.

Yes OR Salesperson=1001 OR 0100=1101NOT No=NOT 0110=1001\begin{aligned} \text{Yes OR Salesperson} &= 1001 \text{ OR } 0100 = \mathbf{1101}\\ \text{NOT No} &= \text{NOT } 0110 = \mathbf{1001} \end{aligned}

1101 marks rows 1, 2, 4: Alice, Joe, Annie. 1001 marks rows 1 and 4, the same rows as the Yes vector. OR unions the row sets. NOT complements them.

0 1 1 0 0 1 0 0 0 1 0 0 No Salesperson AND: row 2
Two vectors in, one AND out. Only bit 2 stays 1, so only row 2 (Joe) matches.

Features of bitmap indexingSearch on YouTube

#FeatureMeaning
1Space efficiencyOne bit per row per value; compact for large datasets with many attributes
2Fast query processingSet operations (AND, OR, NOT) replace full table scans
3Low maintenance overheadUpdates apply incrementally as data changes
4FlexibilityWorks for numeric and categorical data; text via term-vector methods such as TF-IDF
5Reduced I/O overheadCompressed form keeps disk reads small
6Ideal choiceStrong fit for warehouses and read-heavy analytics where fast queries matter

Compact versus bitmap storageSearch on YouTube

Both index types answer the same queries. They differ only in how the index rows are stored, and sometimes in fetch time.

CompactBitmap
Stores the indexed value with its block idStores the indexed value with a row list as a bitmap
Points at the HDFS block holding the rowsPoints at individual rows with bits
One entry per value per blockOne vector per value over all rows

HDFS spreads data across nodes in blocks. The query must reach the right block without scanning. Compact indexing names the block. Bitmap indexing names the rows, and the engine maps rows to blocks.

Timing experiment: 276.815 s against 197.424 sSearch on YouTube

The slides run the same query twice on EMP_INFO: once with three compact indexes on dept, once with only a bitmap index. The three compact indexes are dropped first so that only the bitmap index stays.

The bitmap run uses a fourth index on the same column. Create it first with deferred rebuild, then rebuild it:

CREATE INDEX ind_dept4 ON TABLE EMP_INFO(dept)
AS 'BITMAP' WITH DEFERRED REBUILD;
ALTER INDEX ind_dept4 ON EMP_INFO REBUILD;
SELECT MAX(emp_id) AS Latest_Employee
FROM EMP_INFO WHERE dept = 'AISQUAD';

Both runs return the same answer:

249986
Time taken: 276.815 seconds, Fetched: 1 row(s)
249986
Time taken: 197.424 seconds, Fetched: 1 row(s)

The screenshot prints 249986, but the table above gives MAX = 249990. Trust the table in a hand calculation.

Worked example. How much faster is the bitmap run?

saved=276.815−197.424=79.391 sratio=276.815/197.424=1.40saving=79.391/276.815=0.287=28.7%\begin{aligned} \text{saved} &= 276.815 - 197.424 = \mathbf{79.391}\text{ s}\\ \text{ratio} &= 276.815 / 197.424 = \mathbf{1.40}\\ \text{saving} &= 79.391 / 276.815 = 0.287 = \mathbf{28.7\%} \end{aligned}

The bitmap index answers the same MAX query about 79 s sooner, a 1.40x speedup. The slides warn the gap looks small here only because the table is tiny: 20 rows. On gigabyte and terabyte tables the difference becomes considerable.

When to index and when to skipSearch on YouTube

Use indexing when the dataset is large (gigabytes or more), when speed matters for query execution, and when SELECT statements use WHERE clauses often.

Skip indexing when the dataset is small. Building the index then costs more than it saves. Many indexes also degrade queries. Skip it too when rows are almost all unique, and when WHERE clauses are rare.

L-S-F yes, S-U-R no

Large data, Speed needed, Frequent WHERE: build it. Small data, Unique rows, Rare WHERE: skip it.

Dropping an indexSearch on YouTube

DROP INDEX ind_dept ON EMP_INFO;

The command deletes the index and the table that stores it. Two automatic cases need no command. Dropping the base table deletes its indexes. Dropping a Hive partition deletes that Hive partition's index entries too.

Hive 3.0: indexes are goneSearch on YouTube

Hive supported CREATE INDEX before version 3.0. Since 3.0 the feature is dropped. Two replacements give similar speedups for filtered queries:

  • Materialized views with automatic rewriting. Pre-compute an expensive result once; the optimizer answers matching queries from it. (Views and materialized views covers the before-and-after REBUILD behaviour.)
  • Columnar file formats (Parquet, ORC). They scan selected columns and skip whole files or blocks that cannot match.

Two design rules from the closing slides still apply. Choose bucket columns with high cardinality: many distinct values spread rows evenly. Choose Hive partition columns with low cardinality: few distinct values keep the directory count small.

Quick self-testSearch on YouTube

1. What is a Hive view, and what does it never store?

A view is a searchable object defined by a query. It never stores data. Each read reruns the defining SELECT on the base tables.

2. emp_view2 selects col1, col2, col3 from a 7-column table. How many rows and columns does it show?

6 rows and 3 columns. Dropping columns keeps every row: 1281 Shawn Architect through 1781 John Developer.

3. The employee table holds salaries 45000, 45000, 40000, 40000, 35000. Which rows does emp_35000 (salary greater than 35000) keep?

The first 4 rows. Monika at exactly 35000 fails the strict test 35000>3500035000 \gt 35000. The view holds 1201, 1202, 1203, 1204.

4. After ALTER VIEW emp_view1 AS SELECT col1 FROM emp_tab, what does SELECT * FROM emp_view1 return? Then it is renamed to emp_view_new. What changes?

One column with 6 values: 1281, 1381, 1481, 1581, 1681, 1781. The rename changes only the name to emp_view_new.col1. The rows stay the same.

5. A 4-row table has New_Emp values Yes, No, No, Yes. Write both bitmap vectors.

Yes =1001= 1001 (rows 1 and 4). No =0110= 0110 (rows 2 and 3). Each row sets exactly one of the two vectors.

6. Job values are Analyst, Salesperson, Clerk, Manager in rows 1 to 4. A query asks for No AND Salesperson. Compute the result vector and name the row.

0110 AND 0100=01000110 \text{ AND } 0100 = \mathbf{0100}. Only bit 2 survives, so the answer is row 2: Joe.

7. Differentiate compact and bitmap index storage.

Compact stores value-block pairs: each entry names the HDFS block holding the value. Bitmap stores value-bit-vector pairs: each entry has one bit per row. Both answer the same queries with different fetch times.

8. The same MAX query takes 276.815 s with a compact index and 197.424 s with a bitmap index. How many seconds are saved, and what is the speedup ratio?

276.815−197.424=79.391276.815 - 197.424 = \mathbf{79.391} s saved. Ratio 276.815/197.424=1.40276.815 / 197.424 = \mathbf{1.40}. Same answer (249986) in both runs; the gap grows on larger datasets.

9. Why does ALTER INDEX ... REBUILD launch a MapReduce job, and why did the demo index hold 2 rows?

The index is itself a table, so building it is a distributed job. It holds 2 rows because dept has 2 distinct values (AISQUAD, AIM): one compact entry per value.

10. When should you skip indexing? What replaced CREATE INDEX in Hive 3.0?

Skip it for small datasets, near-unique rows, and rare WHERE clauses. Hive 3.0 dropped CREATE INDEX. Use materialized views with automatic rewriting and columnar formats (Parquet, ORC) with selective scanning instead.

  • A Hive view is a saved query (a virtual table). It stores no data. Reads rerun the SELECT. Views combine tables with joins and expose row or column subsets.
  • CREATE VIEW v AS SELECT ... names the view and its query. emp_view2 keeps 3 of 7 columns and all 6 rows. emp_35000 keeps 4 of 5 rows (salary > 35000 drops exactly 35000).
  • ALTER VIEW v AS SELECT ... replaces the query. ALTER VIEW v RENAME TO w renames it. ALTER never changes the base table.
  • Index when data is large, speed matters, and WHERE clauses are frequent (L-S-F). Skip for small data, near-unique rows, rare WHERE (S-U-R).
  • A Hive index is a separate table of pointers to an indexed column. It records column changes. It can itself be partitioned.
  • Compact index: value plus block id pairs. Bitmap index: one bit vector per distinct value, one bit per row.
  • CREATE INDEX ... AS handler-class | BITMAP ... WITH DEFERRED REBUILD. Deferred means empty until rebuilt.
  • SHOW FORMATTED INDEX ON t lists all indexes on a table. One table can carry any number of compact and bitmap indexes.
  • ALTER INDEX i ON t REBUILD fills the index via a MapReduce job. Rebuild again after overwrite or append. Missing ON raises ParseException.
  • Bitmap vectors: Yes =1001= 1001, No =0110= 0110; each Job value has one 1 (0100 marks the Salesperson). AND intersects, OR unions, NOT complements.
  • Same MAX query: compact 276.815 s, bitmap 197.424 s. Saving 79.391 s, ratio 1.40.
  • DROP INDEX deletes the index and its table. Dropping the base table or a Hive partition drops its indexes too.
  • Hive 3.0 removed CREATE INDEX. Replacements: materialized views with automatic rewriting, Parquet/ORC selective scans. Bucket high-cardinality columns; Hive-partition low-cardinality ones.