Particiones y depósitos de Hive con ejemplo

⚡ Resumen inteligente

Las particiones y los cubos son las dos formas en que Apache Hive divide los datos de las tablas en el disco: una partición crea un directorio por cada valor de clave, mientras que un cubo aplica un hash a las filas para dividirlas en un número fijo de archivos.

  • 🗂️ Una partición es un directorio: Cada valor distinto de la clave de partición se convierte en su propio subdirectorio dentro de la carpeta de la tabla en HDFS.
  • ✂️ Poda de particiones: Una consulta que filtra por la clave de partición lee solo los directorios coincidentes en lugar de escanear toda la tabla.
  • ⚙️ Se requiere el modo dinámico: Para cargar varias particiones desde una sentencia SELECT, es necesario establecer hive.exec.dynamic.partition.mode en nonstrict.
  • 🧮 El bucket es un archivo: CLUSTERED BY aplica una función hash a la columna elegida y escribe cada fila en uno de un número fijo de archivos.
  • 🔍 Muestreo y uniones: Las tablas con particiones admiten lecturas TABLESAMPLE eficientes y uniones de particiones en el lado del mapa que las tablas simples no pueden.
  • 📐 Elegir por cardinalidad: Particione las columnas de baja cardinalidad, como el estado o la fecha, y agrupe las columnas de alta cardinalidad, como los identificadores de usuario.

Explicación de particiones y buckets de Hive con un ejemplo práctico.

Las tablas, las particiones y los buckets son los componentes del modelado de datos de Hive. Una tabla define el esquema, una partición divide esa tabla en directorios en el disco y un bucket divide los datos dentro de un directorio en un número fijo de archivos.

¿Qué son las particiones?

Hive Partitions es una forma de organizar las tablas en particiones, dividiéndolas en diferentes partes según las claves de partición. Físicamente, cada partición es un subdirectorio independiente dentro de la carpeta de la tabla en HDFS, lo que permite a Hive omitir los datos que no necesita.

La partición resulta útil cuando la tabla tiene una o más claves de partición. Las claves de partición son elementos básicos que determinan cómo se almacenan los datos en la tabla. Una clave de partición no se almacena dentro de los archivos de datos; su valor está codificado en el nombre del directorio, por lo que una consulta que filtre por esa clave puede descartar directorios completos antes de leer cualquier fila. Esto se conoce como poda de particiones.

Por ejemplo: -

El cliente dispone de datos de comercio electrónico correspondientes a operaciones en India, donde se mencionan las operaciones de cada estado (38 estados) en su conjunto. Si utilizamos la columna de estado como clave de partición y realizamos particiones en esos datos de India en su totalidad, obtendremos 38 particiones, que equivalen al número de estados (38) presentes en India. De esta forma, los datos de cada estado se pueden visualizar por separado en tablas de particiones.

Muestra Code Fragmento para particiones

Las seis instrucciones que aparecen a continuación se ejecutan en orden en la consola de Hive. Cada una representa un paso independiente, y las capturas de pantalla que se muestran a continuación ilustran la misma secuencia ejecutándose en un clúster en funcionamiento.

  1. Creación de la tabla allstates
    create table allstates(state string, District string,Enrolments string)
    
    row format delimited
    
    fields terminated by ',';
    
  2. Cargando datos en la tabla creada allstates
    Load data local inpath '/home/hduser/Desktop/AllStates.csv' into table allstates;
  3. Creación de tabla de particiones.
    create table state_part(District string,Enrolments string) PARTITIONED BY(state string);
  4. Para la partición tenemos que establecer esta propiedad.
    set hive.exec.dynamic.partition.mode=nonstrict
  5. Cargando datos en la tabla de particiones
    INSERT OVERWRITE TABLE state_part PARTITION(state)
    SELECT district,enrolments,state from  allstates;
  6. Procesamiento real y formación de tablas de particiones basadas en el estado como clave de partición

Habrá 38 particiones de salida en el almacenamiento HDFS con el mismo nombre de archivo que el estado. Lo comprobaremos en este paso.

Las siguientes capturas de pantalla muestran la ejecución del código mencionado anteriormente.

En la primera pantalla, el paso 1 se ejecuta en el colmena> solicita y crea el todos los estados Tabla con sus tres columnas y una coma como delimitador de campos.

Hive shell creando la tabla allstates con tres columnas delimitadas

La siguiente pantalla cubre los pasos 2 y 3: el archivo AllStates.csv se carga en todos los estadosy la tabla particionada parte_estado se crea con el estado declarado como clave de partición.

Cargando AllStates.csv en allstates y creando la tabla particionada state_part.

A continuación aparecen los pasos 4 y 5. El modo de partición dinámica se establece en no estricto, y la instrucción INSERT OVERWRITE inicia un trabajo MapReduce cuyas líneas de registro muestran que se carga una partición para cada valor de estado.

Salida del trabajo MapReduce cargando una partición de Hive por valor de estado

Listar el directorio del almacén en HDFS confirma el resultado del paso 6: el shell informa 38 elementos, uno parte_estado/estado= Directorio por estado.

Listado de HDFS que muestra 38 directorios de partición state_part en el almacén de Hive.

A partir del código anterior, hacemos lo siguiente

  1. Creación de la tabla allstates con 3 columnas cuyos nombres serán estado, distrito y matrículas.
  2. Cargando datos en la tabla allstates
  3. Creación de tabla de particiones con estado como clave de partición.
  4. En este paso, configure el modo de partición como no estricto (este modo activará el modo de partición dinámica).
  5. Cargando datos en la tabla de partición state_part
  6. Procesamiento real y formación de tablas de particiones basadas en el estado como clave de partición
  7. Habrá 38 particiones de salida en el almacenamiento HDFS con el nombre del archivo como nombre de estado. En este paso, vemos las 38 particiones de salida en HDFS.

Particionamiento estático frente a particionamiento dinámico en Hive

El ejemplo anterior utiliza particionamiento dinámico, pero Hive admite dos estilos de carga y la diferencia decide cuánto...ping – y cuánto riesgo conlleva cada carga.

Particionamiento estático El valor de la partición se especifica en la propia instrucción, por lo que dicho valor debe conocerse antes de que se ejecute la carga y una instrucción llena exactamente una partición. Particionamiento dinámico Esto permite que Hive lea el valor de partición de la última columna de la lista SELECT y cree los directorios en tiempo de ejecución, razón por la cual el ejemplo solo necesita una única instrucción INSERT para producir 38 directorios.

Aspecto Particionamiento estático Particionamiento dinámico
Valor de partición Suministrado a mano en la cláusula PARTICIÓN Leer en tiempo de ejecución desde la columna SELECT
Particiones por instrucción Un Muchos
Configuration Funciona en el modo estricto predeterminado. Es necesario que hive.exec.dynamic.partition.mode esté configurado como nonstrict.
Velocidad de carga Más rápido, porque no se necesita escanear ningún valor. Más lento, porque el trabajo agrupa las filas por clave
Mejores adecuados para Conjuntos pequeños y conocidos, como una carga diaria. Conjuntos de claves grandes o desconocidos, como 38 estados

Las cargas dinámicas también tienen límites. Hive limita la cantidad de particiones que puede crear un trabajo (por defecto, 100 por mapeador o reductor y 1000 para toda la instrucción), y el trabajo falla una vez que se supera cualquiera de estos límites, por lo que una clave de cardinalidad muy alta requiere que se aumenten esos límites o que se utilice un diseño diferente.

¿Qué son los cubos?

En Hive, los buckets se utilizan para separar los datos de las tablas en varios archivos o directorios. Permiten realizar consultas de forma eficiente y, a diferencia de una partición, el número de buckets es fijo al crear la tabla, por lo que nunca aumenta con los datos.

  • Los datos presentes en esas particiones se pueden dividir aún más en cubetas.
  • La división se realiza en función del hash de columnas específicas que hemos seleccionado en la tabla.
  • Los buckets utilizan algún tipo de algoritmo de hash en el backend para leer cada registro y colocarlo en buckets.
  • El cubo en el que cae una fila lo decide función_hash(columna_de_cubetas) mod num_cubetas, por lo que los valores iguales siempre terminan en el mismo archivo.
  • En Hive 0.x y 1.x, el bucketing debía habilitarse con establecer hive.enforce.bucketing=true; antes de la inserción

Esa última configuración es el historial en un clúster actual: el manual de Apache Hive Se señala que no es necesario a partir de Hive 2.x, ya que el motor ahora selecciona automáticamente el recuento de reductores y la columna cluster-by de la definición de la tabla.

Paso 1) Creando un depósito como se muestra a continuación.

La pantalla que aparece a continuación muestra la instrucción CREATE TABLE para cubo de muestras, con la cláusula CLUSTERED BY en la parte inferior que fija el número de cubetas.

Sentencia CREATE TABLE de Hive que agrupa samplebucket en cuatro buckets.

De la captura de pantalla anterior

  • Estamos creando un samplebucket con nombres de columna como first_name, job_id, department, salary y country.
  • Estamos creando 4 cubos aquí
  • Una vez cargados los datos, se colocan automáticamente en 4 categorías.
  • La columna de país es la columna de agrupación, por lo que cada fila de un país se escribe en el mismo archivo de depósito.

Paso 2) Cargando datos en la tabla samplebucket

Suponiendo que la tabla "employees" ya esté creada en el sistema Hive, en este paso veremos la carga de datos desde la tabla employees a la tabla samplebucket.

Antes de comenzar a mover los datos de los empleados a categorías, asegúrese de que consten de nombres de columna como first_name, job_id, department, salary y country.

Aquí estamos cargando datos en samplebucket desde la tabla employees; la siguiente pantalla muestra la instrucción INSERT OVERWRITE que realiza la copia.

Sentencia INSERT OVERWRITE que copia las filas de empleados en la tabla samplebucket.

Paso 3) Mostrando los 4 cubos creados en el Paso 1

Al listar el directorio de tablas en HDFS se observa el resultado físico: cuatro archivos de datos numerados en lugar de uno.

Listado HDFS de los cuatro archivos de bucket creados en el directorio samplebucket.

En la captura de pantalla anterior, podemos ver que los datos de la tabla de empleados se transfieren a los 4 depósitos creados en el paso 1.

Particionamiento vs. agrupamiento en cubos de Hive: Diferencias clave

Ambas funciones dividen una tabla en fragmentos más pequeños, pero lo hacen en diferentes niveles del sistema de archivos y resuelven problemas distintos. La tabla que aparece a continuación las compara.

Punto de comparación Separador de ambientes Cubos
Unidad creada Un directorio por valor de clave Un archivo por cubo hash
Declarado con PARTIDO POR AGRUPADOS POR … EN n CUBOS
Numero de piezas Crece con el número de valores distintos. Corregido en la creación de la tabla
Columna almacenada en archivos de datos No, el valor reside en el nombre del directorio. Sí, la columna sigue siendo una columna normal.
Mejores tipo de columna Cardanalidad baja, como estado, año o país. Alta cardinalidad, como user_id o transaction_id
Principal beneficio La eliminación de particiones omite los directorios innecesarios. Tamaños de archivo uniformes, muestreo económico y uniones del lado del mapa.

No son rivales. Un diseño de producción común particiona una tabla de hechos por fecha y luego agrupa cada día según la clave de unión, de modo que una consulta se limita a un directorio y luego realiza las uniones entre los grupos dentro de él.

Cuándo usar particionamiento, agrupamiento o ambos

La elección entre ellas comienza con la cardinalidad de la columna y la estructura de las consultas que leerán la tabla.

  • tabique cuando las consultas casi siempre filtran por la misma columna de baja cardinalidad, y cuando el número de valores distintos se mantiene en los cientos en lugar de los millones.
  • Cubo cuando la columna útil tiene demasiados valores distintos para ser un directorio, o cuando la tabla se une o se muestrea repetidamente en esa columna.
  • Usa ambos Para tablas de hechos grandes: particione por fecha y luego clasifique dentro de cada partición según la clave de unión.

El modo de fallo que hay que tener en cuenta es el problema de los archivos pequeños. El particionamiento basado en una columna con una cardinalidad muy alta (una marca de tiempo o un identificador de cliente) genera miles de directorios diminutos, cada uno con un archivo muy inferior al tamaño del bloque de HDFS. Esto aumenta la memoria del NameNode y ralentiza cada escaneo, que es precisamente lo que el particionamiento pretendía evitar. El bucketing evita este problema porque la definición de la tabla limita el número de archivos.

El agrupamiento tiene su propia advertencia: el diseño solo es correcto si cada escritor lo respeta. El número de cubetas declarado al crear la tabla es metadatos, por lo que un trabajo que escribe en la tabla sin agrupar correctamente puede dejar archivos que no coinciden con el diseño declarado, y el muestreo posterior o las uniones de cubetas leerán filas incorrectas.

Preguntas Frecuentes

Ejecuta SHOW PARTITIONS table_name en la consola de Hive. Lee el metastore e imprime una línea por directorio de partición, lo cual es más rápido que listar la ruta del almacén en HDFS y también confirma que el metastore está sincronizado.

ALTER TABLE table_name ADD PARTITION (state='Goa') registra un nuevo directorio, y ALTER TABLE table_name DROP PARTITION (state='Goa') lo elimina.ping una partición administrada elimina sus datos, mientras que dropping Una opción externa solo borra la entrada del metastore.

Hive limita las particiones dinámicas a 100 por nodo y 1000 por instrucción de forma predeterminada. Una clave con más valores distintos supera el límite y detiene la tarea. Aumente los valores de hive.exec.max.dynamic.partitions.pernode y hive.exec.max.dynamic.partitions, o seleccione una clave menos restrictiva.

No. Era necesario en Hive 0.x y 1.x para forzar que el número de reductores coincidiera con el número de cubetas. HIVE-12331 lo eliminó en Hive 2.0, y ahora el motor obtiene tanto el número de reductores como la columna cluster-by de la tabla.

TABLESAMPLE(BUCKET x OUT OF y ON column) lee solo los archivos de bucket coincidentes en lugar de escanear todo. Dado que las filas se codificaron mediante hash en la misma columna al momento de la escritura, el muestreo es repetible y mucho más económico que un filtro de filas aleatorias.

Dividir una tabla en miles de archivos pequeños consume memoria del NameNode e inicia una tarea por archivo, lo que ralentiza los escaneos. Generalmente, esto se debe a una clave de partición con una cardinalidad muy alta. El uso de claves menos precisas, la segmentación o la compactación de archivos solucionan el problema.

Sí. El análisis de registros de consultas y los modelos de aprendizaje automático en herramientas como Cloudera Workload XM clasifican las columnas según la frecuencia de filtrado, la asimetría y la cardinalidad, y luego sugieren un diseño. La sugerencia aún necesita revisión, ya que no puede tener en cuenta las cargas de trabajo planificadas.

Copilot genera rápidamente sentencias PARTITIONED BY y CLUSTERED BY a partir de un comentario, y los asistentes de agente pueden generar un script de carga completo. Siempre verifique la cantidad de cubetas y la clave generadas con respecto a la cardinalidad real, ya que el modelo realiza inferencias basándose únicamente en los nombres.

Resumir este post con: