En informática , los árboles M son estructuras de datos en forma de árbol similares a los árboles R y B. Se construyen utilizando una métrica y se basan en la desigualdad triangular para consultas eficientes de rango y de k-vecinos más cercanos (k-NN). Si bien los árboles M pueden funcionar bien en muchas condiciones, el árbol también puede tener una gran superposición y no existe una estrategia clara sobre cómo evitar mejor la superposición. Además, solo se puede utilizar para funciones de distancia que satisfacen la desigualdad triangular, mientras que muchas funciones de disimilitud avanzadas utilizadas en la recuperación de información no la satisfacen. [1]
Como en cualquier estructura de datos basada en árboles, el árbol M está compuesto de nodos y hojas. En cada nodo hay un objeto de datos que lo identifica de forma única y un puntero a un subárbol donde residen sus hijos. Cada hoja tiene varios objetos de datos. Para cada nodo hay un radio que define una bola en el espacio métrico deseado. Por lo tanto, cada nodo y hoja que reside en un nodo particular está a una distancia máxima de , y cada nodo y hoja con un nodo padre mantiene la distancia con respecto a él.
Un árbol M tiene estos componentes y subcomponentes:
La idea principal es encontrar primero un nodo hoja N al que pertenece el nuevo objeto O. Si N no está lleno, simplemente adjúntelo a N. Si N está lleno, invoque un método para dividir N. El algoritmo es el siguiente:
Inserción de algoritmo Entrada: Nodo N del M-Tree MT , Entrada Salida: Una nueva instancia de MT que contiene todas las entradas en el MT original más
Los objetos de ruta o los objetos si N no es una hoja entonces { /* Busque entradas en las que encaje el nuevo objeto */ Sea un objeto de enrutamiento del conjunto de objetos de enrutamiento de tal manera que si no está vacío entonces { /* Si hay una o más entradas, entonces busque una entrada que esté más cerca del nuevo objeto */ } demás { /* Si no existe tal entrada, entonces busque un objeto con una distancia mínima de */ /* el borde de su radio de cobertura hasta el nuevo objeto */ /*Actualizar los nuevos radios de la entrada*/ } /*Continuar insertando en el siguiente nivel*/ devolver insertar( ); de lo contrario { /* Si el nodo tiene capacidad entonces simplemente inserte el nuevo objeto */ Si N no está lleno entonces { store( ) } /* El nodo está a plena capacidad, entonces es necesario hacer una nueva división en este nivel */ de lo contrario { dividir( ) } }
Si el método split llega a la raíz del árbol, entonces elige dos objetos de ruta de N y crea dos nuevos nodos que contienen todos los objetos en el N original y los almacena en la nueva raíz. Si el método split llega a un nodo N que no es la raíz del árbol, el método elige dos nuevos objetos de ruta de N , reorganiza cada objeto de ruta en N en dos nuevos nodos y y almacena estos nuevos nodos en el nodo padre del N original . La división debe repetirse si no tiene suficiente capacidad para almacenar . El algoritmo es el siguiente:
Algoritmo de división Entrada: Nodo N del M-Tree MT , Entrada Salida: Una nueva instancia de MT que contiene una nueva partición.
/* Los nuevos objetos de enrutamiento ahora son todos los del nodo más el nuevo objeto de enrutamiento */ sean NN entradas de si N no es la raíz entonces { /*Obtener el nodo principal y el objeto de enrutamiento principal*/ sea el objeto de enrutamiento padre de N sea el nodo padre de N } /* Este nodo contendrá parte de los objetos del nodo a dividir */ Crear un nuevo nodo N' /* Promocionar dos objetos de enrutamiento del nodo que se va a dividir para que sean nuevos objetos de enrutamiento */ Crea nuevos objetos y . Promote( ) /* Elija qué objetos del nodo que se está dividiendo actuarán como nuevos objetos de enrutamiento */ Partición( ) /* Almacenar entradas en cada nuevo objeto de enrutamiento */ Almacene las entradas de en N y las entradas de en N si N es la raíz actual , entonces { /* Crea un nuevo nodo y configúralo como nueva raíz y almacena los nuevos objetos de enrutamiento */ Crea un nuevo nodo raíz y almacena en } demás { /* Ahora use el objeto de enrutamiento principal para almacenar uno de los nuevos objetos */ Reemplazar entrada con entrada en si no está completo entonces { /* El segundo objeto de enrutamiento se almacena en el padre solo si tiene capacidad libre */ Guardar en } demás { /*Si no hay capacidad libre entonces divide el nivel*/ dividir( ) } }
Una consulta de rango es aquella en la que se especifica un valor de similitud mínima/distancia máxima. Para un objeto de consulta dado y una distancia de búsqueda máxima , la consulta de rango range ( Q, r(Q)) selecciona todos los objetos indexados de manera que . [ 2 ]
El algoritmo RangeSearch comienza desde el nodo raíz y recorre recursivamente todas las rutas que no se pueden excluir de conducir a objetos calificados.
Algoritmo de búsqueda por rangoEntrada: Nodo N del M-Tree MT, Q : objeto de consulta, : radio de búsqueda
Salida: todos los objetos de la base de datos tales que
{ sea el objeto padre del nodo N ; si N no es una hoja entonces { para cada entrada ( ) en N hacer { si entonces { Calcular ; si entonces RangeSearch (*ptr( )), Q , ); } } } de lo contrario { para cada entrada ( ) en N hacer { si entonces { Calcular ; si ≤ entonces agregar al resultado; } } }}
La consulta de k -vecinos más cercanos ( k -NN) toma la cardinalidad del conjunto de entrada como parámetro de entrada. Para un objeto de consulta dado Q ∈ D y un entero k ≥ 1, la consulta k -NN NN(Q, k) selecciona los k objetos indexados que tienen la distancia más corta desde Q, de acuerdo con la función de distancia d. [2]