8. Acceso secuencial indexado y B+Trees

8.1 Indices para búsquedas y reportes


Hasta el momento hemos estudiado 2 tipos de estructuras de archivos (organización de archivos):


Problemas:

En la práctica en muchas situaciones se requieren de ambas cosas (búsquedas y accesos secuenciales), por ejemplo:
Las 2 soluciones existentes:
  • ISAM indexed sequential access method
  • B+ Tree

8.2 Indexed Sequential Access Method (ISAM)

Básicamente es la idea de tener un índice esparcido, de manera que el archivo de datos lo agrupamos por bloques y en cada bloque existe un "rango" ordenado de los datos (Figura 8.1).

 


Figura 8.1

Lo importante a resaltar aquí es que los bloques no necesariamente están formando una secuencia en el archivo, es decir, dentro del archivo de datos los bloques pueden estar desordenados, aquí el detalle es mantener un apuntador a cada bloque subsecuente como se muestra en la figura 8.2.


Figura 8.2

Reglas generales para un índice ISAM:


La creación del índice puede ser muy simple como el que se muestra en la tabla 8.1, donde sólo se guardan los máximos valores de cada bloque; quizás si las llaves fueran numéricas todo sería muy simple y podría quedar bien este esquema, pero en especial para cadenas (aunque también aplica para números) lo que en realidad se busca es tener separadores que sirvan para varios casos ya que si eliminamos el máximo valor de un bloque entonces tendremos que alterar el índice.
Key Block number
BERNE 1
CAGE 2
DUTTON 3
EVANS 4
FOLK 5
GADDIS 6

Tabla 8.1

La figura 8.3 muestra una primer solución de separadores basándose en los prefijos de las palabras. De esta manera nos evitamos el tener que estar actualizando constantemente el índice. Estos separadores de rangos nos son únicos, dependerá del programador el definirlos, la figura 8.4 nos muestra una lista de opciones para el caso de los bloques 3 y 4.


Figura 8.3



Figura 8.4


8.3 B+ Trees



Estas necesidades son el origen de los B+ Trees.
Un B+ Tree es muy similar a un BTree en muchos aspectos, la principal diferencia es que en las "hojas" se encuentran todas las llaves ordenadas, mientras que en los demás nodos se encuentran sólo algunas de ellas que sirven de camino para llegar rápidamente al nivel más bajo.

Aquí el orden se define como el número máximo de llaves que puede tener un nodo, cada nodo debe estar siempre al 50 % de su capacidad, excepto la raíz que al menos deberá tener 2 llaves (2 ligas); esto último después de haber pasado las inserciones iniciales donde obviamente la raíz podrá tener 1 sola llave.
Para el ejemplo de la Figura 8.5 el orden que estamos considerando es 4.

Inserción
Lo primero que se debe hacer es buscar en qué nodo hoja debe insertarse, analizando desde la raíz algunos de los nodos del árbol.
El insertar una llave en un nodo que no esta lleno es fácil sólo se actualiza el nodo, recordando que la llave "más grande" debe promoverse siempre al nivel superior.
Si se inserta en un nodo lleno entonces ocurre un "overfull" y el nodo deberá partirse en 2, promoviendo al nivel superior las llaves más grandes de los nuevos nodos.
Recordar que al igual que los b-trees muchas de estas operaciones pueden causar acciones recursivas al alterar los niveles superiores y en caso de llegar a la raíz entonces el árbol crecerá en un nivel.



Figura 8.5



Figura 8.6


Eliminación:

El proceso de eliminación se puede deducir del proceso de inserción.
Al eliminar una llave localizamos la hoja donde se encuentra la llave a eliminar y la eliminamos, aquí tendremos 2 opciones:

Para el primer caso lo único que se debe revisar es si la llave más grande sigue siendo la misma, si la llave que eliminamos era la más grande debemos actualizar el nivel superior (quizás sucesivamente si es el caso)
Para el segundo caso debemos "concatenar" dos nodos hermanos, teniendo 2 casos:

Nuevamente es importante recordar que las eliminaciones pueden caer en un proceso recursivo que llegue a la raíz en cuyo caso el árbol se reducirá en un nivel.


Figura 8.7

En esta sección se analizó el modelo conceptual de los B+ Tree y se omitieron detalles de implementación tales como la  relación que debe existir entre los nodos "hoja" para poder realizar un acceso secuencial (Figura 8.7) en ese nivel.

Resumiendo:
Nota: es importante mencionar que en la literatura muchos autores definen de maneras diferentes a los árboles, lo que para nosotros es un B+Tree para otros es un B-Tree, la nomenclatura empleada aquí es tomada del concepto original propuesto por Bayer, McCreight, Knuth y Comer.



8.4 Prefix B+ -Trees


Como su nombre lo indica son una modificación al algoritmo de B+ Trees

La característica de estos árboles radica en que el conjunto de llaves que NO son hojas del árbol (index set), no son llaves completas sino un "prefijo" (prefix) de dichas llaves, de manera que las llaves completas sólo existen en el nives más bajo (hojas del árbol).

Similar a B+ Tree las hojas del árbol en realidad son "bloques" de datos que se van ligando unos con otros por ejemplo:


Block
Next
INDEX
1
2
ADAMS...BAIRD...BIXBY...BOONE...
2
4
BYNUM...CARSON...CARTER...
3
-1
DENVER...ELLIS...
4
3
COLE...DAVIS...
Tabla 8.2

Lo que se pretende es que este prefijo sea del menor tamaño posible ya que recordemos que para cada nodo hoja la referencia que se tiene con el nodo superior es la llave de mayor tamaño. En el ejemplo de la figura 8.8 (un prefix b+tree de orden 2) podemos ver que la llave más grande del primer bloque sería "Berne" y el prefijo que nos sirve de separador es "Bo" de ahí lo que mencionábamos de la relación menor-mayor.



Figura 8.8

A diferencia de los árboles que hemos visto, aquí al eliminar una llave únicamente la eliminamos del nodo hoja, no se alteran los prefijos del resto del árbol. Esto facilita enormemente el proceso de eliminación y permite que de una manera sencilla se siga aprovechando ese prefijo para las nuevas inserciones.


Figura 8.9

Por otro lado el proceso de inserción si produce las operaciones que se explicaron anteriormente, en el ejemplo podemos ver que al agrega una llave nueva, se aumenta un nuevo bloque (7) y en consecuencia se agregar un nuevo separador (AY) al index set, formando el nodo (AY,BO,CAM) lo cual resulta en una división del nodo, produciendo entonces (AY) (CAM) y la promoción de (BO).


Figura 8.10

Finalmente una eliminación del bloque 3 puede causar un "underflow" y en consecuencia el bloque 2 y 3 deberán unirse para formar uno solo, en cuyo caso el separador (CAM) deja de utilizarse y forza a (BO) a que baje nuevamente.

Figura 8.11

Resumiendo: