Indice complejo
En los índices normales, indexamos registros de la propia tabla y el resultado obtenido son registros de la misma tabla. En un índice complejo intervienen:
Una tabla primaria (tabla asociada) que se corresponde con la tabla cuyas altas y bajas generarán las altas y bajas de la clave indexada.
Una tabla secundaria (tabla para búsquedas) es la tabla de la que se obtienen los resultados. Cuando hagamos una búsqueda por un índice complejo obtendremos una lista de registros de esta tabla. La tabla secundaria puede ser la primaria o alguna de sus ascendientes (tablas apuntadas por campos de tipo puntero a maestro, indirecto real o virtual, etc.)
Una o múltiples tablas terciarias, son las que intervienen en la composición de la clave y en el cálculo de los pisos intermedios para el cálculo de la dirección. El cambio de valor de una tabla terciaria fuerza la regeneración de la dirección apuntada en el índice. Puede ser la tabla primaria o alguna de sus ascendientes (tablas apuntadas por campos de tipo puntero a maestro, indirecto real o virtual, etc.). También se consideran terciarias tablas que parecen no intervenir, por ejemplo, si indexamos el nombre de la población del cliente de la factura, todas las tablas son terciarias ya que el cliente puede cambiar de población y la factura puede cambiar de cliente y cualquiera de estos cambios produce el recálculo de la dirección a indexar. Incluso también son terciarias las tablas que intervienen en la tabla secundaria, por ejemplo, tenemos la tabla líneas de pedido que apunta al pedido que a su vez apunta al cliente, y las líneas también apuntan al artículo que a su vez apunta a la familia, si en nuestro índice hemos definido como secundaria a la familia, es decir obtenemos familias vendidas a clientes, la tabla artículos también será terciaria, ya que si un artículo cambia de familia obliga a la regeneración de las direcciones apuntadas en los índices.
Por ejemplo, podemos crear este índice para buscar facturas de una empresa por el nombre del transportista o del cliente.
Propiedades
Identificador
Etiqueta alfanumérica que identifica de forma unívoca al objeto. Este identificador será el que usemos en fórmulas y para referenciarlo en otras propiedades.
Constará de mayúsculas y números exclusivamente. Al identificar de forma unívoca un campo de una tabla no puede haber duplicidad.
Nombre
Etiqueta alfanumérica que servirá como descriptor del índice.
Podemos definir una etiqueta por cada idioma presente en el proyecto.
Estilos
Podemos definir los estilos siguientes:
Privado
Limita el acceso del usuario final al objeto desde puntos donde no se haya programado el acceso al mismo.
Comentarios
Esta propiedad nos permite documentar el uso del índice complejo.
Tabla asociada
En esta propiedad indicaremos la tabla primaria que es aquella cuyas altas y bajas generarán las altas y bajas de la clave indexada.
Tabla para búsquedas
En esta propiedad indicaremos la tabla secundaria, que es aquella que define el resultado de la búsqueda que se realiza por el índice.
Tipo de índice
Esta propiedad nos permite definir de qué forma van a ser indexados los datos. Los tipos existentes son:
Clave única
No admite más que un registro con la misma clave.
Palabras
El registro es indexado por cada palabra encontrada en las partes que forman la clave. Por razones de optimización y rendimiento, solamente se indexarán los 9 primeros caracteres de cada palabra del campo o campos a indexar.
Múltiples claves
El registro es indexado desde cero claves hasta el número que el programador declare en la propiedad número de claves. El índice deberá estar compuesto al menos por tantos componentes como número de claves hayan sido declaradas. Si el campo o la fórmula de una clave está vacío, esa clave no será indexada.
Los campos a indexar han de ser del mismo tipo y longitud.
Un ejemplo de uso es cuando en una tabla tenemos dos o más campos enlazados a una tabla maestra. Por ejemplo, en la ficha de un libro, el autor primero y el autor segundo, y nos interesa buscar libros de un autor, sin importar si es el autor primero o el segundo.
Crearemos un índice con múltiples claves cuyo primer componente será el campo enlazado al autor1 y cuyo segundo componente será el campo enlazado al autor2.
En la propiedad nº de claves del índice estableceremos un 2.
Si queremos que al buscar por dicho índice el resultado salga ordenado, por ejemplo, por el título del libro, por ejemplo, al índice le añadiremos el campo NAME de la tabla, pero el número de claves del índice seguirá siendo 2 (los enlaces a los autores).
Acepta repetidas
La ficha es indexada sólo una vez pero, al contrario que la clave única, se admiten repeticiones. El sistema le añade 4 bytes a la clave para diferenciar las repetidas.
Trozos de palabras
El registro es indexado por cada grupo de 3 ó más caracteres de cada una de las partes que forman la clave.
Los índices de palabras y de trozos de palabras hacen una conversión interna a Alfa40, si no hay correspondencia de un carácter entra la tabla de caracteres de origen y la de Alfa40, no lo indexará. Además, solamente existe la tabla Alfa40 para el alfabeto latino. Esto quiere decir que por este tipo de índices se indexarán caracteres latinos, pero no de otros alfabetos.
Condición para indexar
Lista negra
Esta propiedad aparecerá en el caso de que el índice sea de tipo palabras. Permite establecer una lista de las palabras que no serán indexadas por ese índice. Para escribir la lista pulsar el botón que aparece al editar el valor.
Número de claves
Esta propiedad aparecerá en el caso de que el índice sea de tipo múltiples claves. En ella se indicarán el número de claves que conforman el índice.
Número de partes
Indica el número de campos o fórmulas (partes) que componen la clave.
Longitud de la clave
Indica la longitud total, en bytes, del índice.
Resolución dir
Esta propiedad solamente estará disponible cuando las tablas especificadas en las propiedades tabla asociada y tabla para búsqueda sean distintas. Aquí debemos definir el campo enlazado a la tabla de búsquedas que queremos usar.
Partes índice complejo
Aquí es donde definiremos las claves que se indexarán y que se corresponden con la tabla o tablas terciarias que componen el índice.
En un mismo índice complejo, podremos indexar campos de la tabla primaria, de la secundaria y/o terciarias, componiendo todas ellas una única clave.
Un índice complejo estará compuesto por una o más partes. Para crear una parte de un índice complejo abrir el menú objetos, submenú nuevo sub-objeto, opción parte índice. Sus propiedades son:
Identificador
Etiqueta alfanumérica que identifica al componente índice complejo. Este identificador será el que usemos para referenciarlo en otras propiedades.
Nombre
Etiqueta alfanumérica que servirá como descriptor del componente.
Estilos
Podemos definir los estilos siguientes:
Privado
Limita el acceso del usuario final a cierta información sobre esa parte del índice.
Heredable
Permite que esa parte del índice complejo sea usada cuando el proyecto sea heredado.
Comentarios
Esta propiedad nos permite documentar el uso del componente del índice complejo.
Modo
Permite establecer de qué forma se indexará la parte. Los valores posibles son:
Campo completo
La parte a indexar va a ser un campo y se indexará completo.
Campo porción
La parte a indexar va a ser un campo pero va a indexarse solamente una porción del mismo.
Fórmula
La parte a indexar va a ser una fórmula definible por el programador.
Campo
Esta propiedad solamente estará disponible en el caso de que el modo sea campo completo o campo porción. Solamente podremos seleccionar campos de la tabla actual que tengan persistencia en disco; es decir, no es posible ni indexar campos de tablas enlazadas ni indexar campos de tipo fórmula.
Fórmula
Longitud
Longitud, en bytes, que tendrá la parte a indexar.
Si el modo es campo completo, este valor no podrá ser modificado.
Si el modo es campo porción, en esta propiedad indicaremos el número de caracteres a indexar del campo. Ejemplo: Si el campo es alfabético de 35 bytes y este valor lo establecemos a 12, esta parte indexará solamente los 12 primeros caracteres del mismo.
Si el modo es fórmula, en esta propiedad indicaremos 0 si queremos indexar la totalidad del resultado de la fórmula; en caso contrario indicaremos el número de caracteres a indexar del campo.
Conversión
Si el modo es campo porción y el campo es de tipo alfabético (Alfa Latin-1, alfa UTF-16, alfa 256, alfa 128 o alfa 64); en esta propiedad podremos hacer una conversión de la parte a una tabla de caracteres inferior.Ejemplo: un campo de tipo alfa256 indexarlo convertido a alfa 64.
Si en un componente realizamos una conversión tendremos que modificar también la longitud que se indexará del mismo en función de la nueva tabla de caracteres. Por ejemplo, si convertimos una parte de Alfa128 a alfa 64, dado que éste último cada cuatro caracteres que se introduzcan se comprimen en 3 grabado en disco, la longitud a indexar deberá ser un múltiplo de 3.
Si el modo es fórmula en esta propiedad podremos indicar al sistema de qué tipo será el dato resultante de la fórmula. Los tipos posibles son:
Número: la parte del índice a indexar será un número.
Fecha: la parte del índice a indexar será una fecha. En este caso la propiedad del componente longitud automáticamente será establecida a 3 y no podrá ser modificada; pues es la longitud que tiene un dato de tipo fecha.
Hora: la parte del índice a indexar será una hora. En este caso la propiedad del componente longitud automáticamente será establecida a 3 y no podrá ser modificada; pues es la longitud que tiene un dato de tipo hora.
Tiempo: la parte del índice a indexar será un dato de tipo tiempo. En este caso la propiedad del componente longitud automáticamente será establecida a 4 y no podrá ser modificada; pues es la longitud que tiene un dato de tipo tiempo.
Alfa 256: la parte del índice a indexar será una cadena de tipo alfa 256.
Alfa 128: la parte del índice a indexar será una cadena de tipo alfa 128.
Alfa 64: la parte del índice a indexar será una cadena de tipo alfa 64.
Alfa 40: la parte del índice a indexar será una cadena de tipo alfa 40.
Decimales
Esta propiedad solamente es visible cuando el modo es fórmula y el valor de la conversión es número. Permite establecer el número de decimales que tendrá el número a indexar.
Signo
Esta propiedad solamente es visible cuando el modo es fórmula y el valor de la conversión es número. Permite establecer si se va a contemplar o no el signo (positivo o negativo) del número a indexar.
A continuación vamos a revisar diferentes ejemplos que nos ayudarán en la comprensión desde el punto de vista práctico. Crear un índice complejo en vDevelop es realmente sencillo y se puede realizar en cuestión de segundos, sin embargo, detrás de esta aparente sencillez se esconden complejos algoritmos que nos harán la vida más sencilla a la hora de realizar búsquedas realmente complejas sobre información almacenada en una o múltiples tablas.
Ejemplo 1
Pedidos por trozos del nombre del artículo
Queremos crear una búsqueda en la que escribiendo trozos del nombre de un artículo podamos encontrar todos los pedidos en los que se haya vendido en alguna de sus líneas algún artículo que contenga el trozo a buscar. El esquema de tablas en el que está basado el ejemplo es el siguiente:
Crear el índice complejo nos llevará un minuto. Sólo tenemos que cubrir las propiedades que se muestran en la imagen siguiente:
Las propiedades específicas del índice complejo que vemos cubiertas en la imagen son:
La tabla primaria LINEAS que es la que se encuentra en la parte más baja del esquema ya que es la que conoce al resto de tablas del índice complejo y la declaramos como tabla asociada.
La tabla secundaria PEDIDOS que es de la que queremos obtener los resultados de la búsqueda y la declaramos como tabla para búsqueda.
El índice lo declaramos del tipo “Trozos de palabras”.
Si la tabla asociada y la tabla para búsquedas no es la misma se nos solicitará resolver la propiedad Resolución dir con el campo puntero al registro a devolver en la búsqueda. Esta resolución es necesario hacerla manualmente ya que en la senda de resolución del índice complejo pueden existir más de un puntero a la tabla de búsqueda y el programador debe concretar cuál es el campo puntero adecuado para ser utilizado por el índice complejo.
En la parte del índice, en este ejemplo se configura simplemente el campo nombre del artículo a indexar.
Tal y como está definido este índice el programa automáticamente (sin necesidad de ninguna programación por parte del desarrollador) realizarán las siguientes tareas:
Cada vez que se de un alta o baja de una línea de un pedido se regeneran las entradas en el índice complejo para dicho pedido.
Si cambiamos a una línea el artículo o la asignamos a otro pedido se regeneran las entradas del índice complejo de dicho pedido.
Cuando un artículo cambie su nombre se recalcularán las claves correspondiente del índice complejo.
Ejemplo 2
Pedidos de venta por el nombre fiscal, comercial y CIF/DNI de la entidad de los clientes
Supongo que lo queremos es buscar todos los pedidos que correspondan a una empresa o particular del que conocemos su nombre fiscal (Razón social) o su nombre comercial o su CIF/DNI. El esquema de tablas en el que está basado el ejemplo es el siguiente:
En este ejemplo vemos como la misma tabla, en este caso la de PEDIDOS es a la vez la primaria y la secundaria. También vemos como la tabla de CLIENTES es una maestra de extensión de la tabla ENTIDADES que es donde se encuentran los campos a indexar.
Crear ese índice complejo es tan sencillo como completar las propiedades del objeto que vemos en la siguiente imagen:
Las propiedades específicas del índice complejo que vemos cubiertas en la imagen son:
La tabla primaria PEDIDOS que es la que se encuentra en la parte más baja del esquema ya que es la que conoce al resto de tablas del índice complejo y la declaramos como tabla asociada.
La tabla secundaria PEDIDOS que es de la que queremos obtener los resultados de la búsqueda y la declaramos como tabla para búsqueda.
El índice lo declaramos del tipo “Trozos de palabras” aunque puede estar definido de cualquiera de los tipos de índices soportados en Velneo.
Como en este caso la tabla asociada y la tabla para búsquedas son la misma, no se solicita la propiedad “Resolución dir” pues Velneo ya deduce que será el ID de la tabla PEDIDOS.
En la parte del índice, en este ejemplo se configuran los campos nombre fiscal (Razón Social), nombre comercial y CIF/DNI de la entidad.
Tal y como está definido este índice el programa automáticamente (sin necesidad de ninguna programación por parte del desarrollador) realizarán las siguientes tareas:
Cada vez que se de un alta o baja de un pedido se regeneran las entradas en el índice complejo para dicho pedido.
Cada vez que se modifique el cliente de un pedido se regeneran las entradas del índice complejo de dicho pedido.
Cuando una entidad cambie el nombre fiscal, el nombre comercial o el CIF/DNI se recalcularán las claves correspondiente del índice complejo.
Ejemplo 3
Clientes por trozos de los contactos, nombre fiscal, comercial o CIF de la entidad
Dada la abstracción y versatilidad de los índices complejos, también nos permiten crear índices sobre tablas de proyectos heredados sin modificarlos. Supongamos que tenemos una solución llamada vBase que contiene datos de empresa y es heredada por otra solución llamada Pedidos, donde gestionamos pedidos. En este ejemplo vamos a indexar tablas de la solución vBase desde nuestro proyecto Pedidos, sin tocar la solución vBase, de tal forma que si sale una nueva versión de la solución vBase podremos actualizarla sin problemas y nuestro índice complejo seguirá funcionando perfectamente.
Con este índice complejo queremos buscar clientes por los trozos de su teléfono, móvil, email, fax, skype, etc. y también si el trozo a buscar forma parte del nombre fiscal, nombre comercial o CIF/DNI de la entidad. Para conseguirlo declaramos como tabla asociada (primaria) la tabla de contactos que es el plural de contactos de le entidad, como tabla para búsqueda configuramos la de clientes y luego declaramos las partes del índices a indexar. El esquema de tablas en el que está basado el ejemplo es el siguiente:
En un minuto tendremos declarado un índice verdaderamente complejo sobre las tablas de la solución vBase sin modificarla.
Las propiedades específicas del índice complejo que vemos cubiertas en la imagen son:
La tabla primaria CTT que es la que se encuentra en la parte más baja del esquema ya que es la que conoce al resto de tablas del índice complejo y la declaramos como tabla asociada.
La tabla secundaria CLIENTES que es de la que queremos obtener los resultados de la búsqueda y la declaramos como tabla para búsqueda.
El índice lo declaramos del tipo “Trozos de palabras” aunque puede estar definido de cualquiera de los tipos de índices soportados en Velneo.
Nuevamente como la tabla asociada y la tabla para búsquedas no son la misma se nos solicita resolver la propiedad “Resolución dir” con el campo puntero al registro a devolver en la búsqueda que en este caso es el campo #ENT.EXTENSION_CLIENTES que es el campo de ENTIDADES que apunta al registro de extensión.
En la parte del índice se configuran los campos a indexar que en este caso son el campo #VAL de la tabla de contactos que es la que contiene el dato de contacto y como ya hemos visto añadimos también los nombre fiscal (Razón Social), nombre comercial y CIF/DNI de la entidad.
Tal y como está definido este índice el programa automáticamente (sin necesidad de ninguna programación por parte del desarrollador) realizarán las siguientes tareas:
Cada vez que se de un alta o baja de un contacto de una entidad se regeneran las entradas en el índice complejo para dicho cliente.
Cada vez que se modifique en un contacto la entidad a la que pertenece se regeneran las entradas del índice complejo localizar el cliente.
Cuando modifiques el valor de un dato de contacto o cuando una entidad cambie el nombre fiscal, el nombre comercial o el CIF/DNI se recalcularán las claves correspondiente del índice complejo.
Rendimiento
El rendimiento en ejecución de los índices complejos es similar al de los índices de tablas. Debemos tener en cuenta que el tiempo necesario para la generación del índice en su creación o en la regeneración del mismo variará en función de la complejidad de la clave. Si lo campos a indexar pertenecen a la tabla primaria, los tiempos serán similares a los actuales, sin embargo, en casos complejos donde existen muchas tablas terciarias este tiempo puede llegar a ser elevado si indexamos un número grande de registros, ya que debemos tener en cuenta que por ejemplo si indexamos los pedidos por el nombre del país de la entidad del cliente, cada clave de almacenar toda la senda de tablas que intervienen #PEDIDO.CLIENTE.ENT.PAIS.NOMBRE ya que si una entidad cambia de país, por ejemplo, será necesario regenerar las entradas del índice complejo para los pedidos afectados por ese cambio.
Regeneración
Cuando creamos un índice complejo, éste no es regenerado automáticamente al reconstruir las tablas, será necesario forzar su regeneración.
La regeneración de estos índices puede hacerse desde el menú utilidades del vDataClient mediante la opción “Regenerar índices” del índice complejo seleccionado. También es posible regenerar los índices complejos desde las función JavaScript regenComplexIndex( String szIdRefIdxComplejo, Boolean bProgressDialog ) que se ha añadido a la clase VApp.
Búsquedas
Existen 2 alternativas para realizar búsquedas en índices complejos:
El comando de instrucción de procesos Cargar lista de índice complejo que nos devolverá la lista de registros resueltos.
Los componentes del objeto búsqueda ahora tienen un nuevo parámetro “Grupo índices” que permite seleccionar si deseamos utilizar un índice normal o un índice complejo, en función de la selección la siguiente propiedad nos solicitará un índice normal o un índice complejo según corresponda. Una vez definida la búsqueda podrá ser usada como cualquier otra búsqueda de nuestra aplicación. En la siguiente imagen podemos ver la definición del componente.
Reducción automática de claves
Una importante optimización que contemplan los índices complejos es la reducción automática de claves. Cuando se da la circunstancia de que existen muchas claves duplicadas en el índice complejo apuntando al mismo registro de la tabla secundaria, Velneo evita que se generen esas claves duplicadas consiguiendo una notable reducción del tamaño del índice y almacenando información sobre el número de veces que se repite cada clave. Esta información podría llegar a ser utilizada en futuras versiones para la creación de índices estadísticos.
En los índices complejos en los que indexemos un campo de un maestro, debe existir un índice del campo puntero a maestro declarado en la tabla que se indexa. Si no existe este índice Velneo es incapaz de saber que registros se verán afectados por el cambio y no podrá reindexarlos.
El índice del campo puntero a maestro no debe estar condicionado ya que si el índice está condicionado no podemos garantizar que seremos capaces de apuntar a todos los registros plurales de la tabla. Este criterio es el que aplica la base de datos de Velneo a la hora de reindexar registros de índices complejos de tal forma que, si no encuentra ningún indice al campo maestro sin condicionar, no realizará el refresco de los cambios del maestro en el índice complejo.
Los índices complejos son funcionales solamente en tablas con persistencia en disco.