Acerca de la demo

Tres formas de buscar una película

Elastiflix-Movies Java busca en un catálogo de películas guardado en un índice de Elasticsearch Serverless. Con la misma consulta puedes probar tres modos de búsqueda y ver cómo cambia lo que encuentra cada uno: por palabras, por significado o combinando ambos. Además puedes acotar los resultados con filtros y cargar nuevas películas al catálogo.

Full-text (léxica) Encuentra películas cuyo título contiene las palabras de tu consulta. BM25 · title, original_title Vectorial Encuentra películas cuya sinopsis se parece en significado a lo que describes. k-NN · plot_256, plot_512, plot_1024 Híbrida Ejecuta las dos búsquedas anteriores y combina sus resultados en una sola lista. BM25 + k-NN · fusión RRF

Full-text (léxica)

Busca coincidencias de términos en los campos title y original_title, ambos de tipo text. Elasticsearch analiza el texto de la consulta en tokens y los compara con los tokens indexados de cada título.

Cómo se calcula la relevancia: BM25

BM25 es el algoritmo de puntuación por defecto de Elasticsearch para campos text. Favorece los términos de la consulta que aparecen en el campo y que son poco comunes en el catálogo. Dos parámetros controlan su comportamiento: k1 (por defecto 1.2) limita cuánto suma que un término se repita, y b (por defecto 0.75) ajusta la puntuación según la longitud del campo.

Ajustes disponibles

Tipo de consulta: match
Busca en un solo campo, que eliges entre title y original_title.
Tipo de consulta: multi-match
Busca en los dos campos a la vez con el tipo best_fields: cada campo se evalúa por separado y la película recibe la puntuación del campo que mejor coincide.
Operador: OR
Basta con que aparezca una de las palabras de la consulta. Es el comportamiento por defecto de Elasticsearch.
Operador: AND
Deben aparecer todas las palabras. Con multi-match y best_fields, todas deben estar en un mismo campo: no se pueden repartir entre title y original_title.

Documentación Match query Multi-match query Similarity (BM25)

Vectorial

Busca por significado en la sinopsis de cada película (campo plot). El texto de tu consulta se convierte en un vector con el modelo jina-embeddings-v5-omni-small y Elasticsearch devuelve las películas cuyos vectores de sinopsis están más cerca, usando el retriever knn.

Cómo funciona k-NN

k-NN (k vecinos más cercanos) busca los vectores más próximos al vector de la consulta. Elasticsearch lo hace de forma aproximada sobre un grafo HNSW: recorre el grafo en lugar de comparar contra todo el catálogo, lo que la hace rápida aunque no siempre exacta.

Las tres representaciones de la sinopsis

El objetivo de este modo es comprobar cómo el número de dimensiones del vector influye en la precisión de los resultados. Los tres campos vienen del mismo modelo: su dimensión nativa es 1024 y admite recorte Matryoshka a 256 y 512.

CampoTipoDimensionesOrigen
plot_256dense_vector256Primeros valores del vector de 1024, renormalizados (Matryoshka)
plot_512dense_vector512Primeros valores del vector de 1024, renormalizados (Matryoshka)
plot_1024dense_vector1024Vector completo del modelo

Una comparación justa. Los tres campos usan la misma configuración de índice: index_options de tipo hnsw con vectores float sin cuantización, los mismos m (16) y ef_construction (100), los valores por defecto de Elasticsearch, y similitud cosine. Así, la única diferencia entre ellos es el número de dimensiones.

Precisión medida por dimensión

Medido en el catálogo original de 4 322 películas. Se midió con 32 descripciones de trama (26 en español y 6 en inglés), cada una con una sola película correcta del catálogo y sin palabras de su título. Las posiciones se obtuvieron en Elasticsearch y se confirmaron con una búsqueda exacta por fuerza bruta: coinciden en todos los casos.

CampoCorrecta en 1.er lugarEntre las 5 primerasEntre las 10 primerasMRR@10
plot_25622 de 32 (69 %)29300.774
plot_51225 de 32 (78 %)31320.853
plot_102426 de 32 (81 %)31310.880

El MRR premia que la película correcta quede arriba: vale 1 si siempre sale 1.ª y 0.5 si siempre sale 2.ª. En 24 de las 32 consultas la posición es la misma en los tres campos; las diferencias se concentran en las descripciones más difíciles:

Películaplot_256plot_512plot_1024
Inception21.º4.º3.º
Life of Pi10.º3.º2.º
Spirited Away4.º1.º1.º
Titanic4.º3.º1.º
E.T. the Extra-Terrestrial3.º1.º1.º
Coco2.º1.º1.º
  • 256 dimensiones pierde precisión de forma clara; 512 queda muy cerca de 1024 con la mitad del tamaño.
  • Más dimensiones no siempre es mejor en cada caso: Forrest Gump queda 21.º, 8.º y 18.º.
  • Con 32 consultas es una tendencia clara, no una conclusión estadística firme.

Ajustes disponibles

Vector k-NN
El campo sobre el que se busca: plot_256, plot_512 o plot_1024. Más dimensiones suelen capturar más matices del significado, a cambio de más memoria y de comparaciones más costosas.
k
Número máximo de resultados que devuelve la búsqueda vectorial, después de combinar los candidatos de todos los shards; se reparten en páginas de 25, 50 o 100. Debe ser menor o igual que num_candidates. Valor inicial: 100.
num_candidates
Candidatos que se evalúan en cada shard antes de quedarse con los k mejores. Subirlo tiende a mejorar la precisión, a cambio de más tiempo de respuesta. Máximo 10 000. Valor inicial: 200.

Nota de implementación: para recuperación, el modelo espera el prefijo Query: en las consultas. Las sinopsis se vectorizan con input_type ingest y sin prefijo.

Documentación kNN retriever Approximate kNN Dense vector jina-embeddings-v5-omni-small

Híbrida

Combina los dos modos anteriores con los mismos ajustes. El retriever rrf agrupa un retriever standard, con la consulta match o multi_match del componente full-text, y un retriever knn del componente vectorial.

  1. 1 · Componente full-text Lista ordenada por BM25 sobre title y/o original_title.
  2. 2 · Componente vectorial Lista ordenada por cercanía k-NN sobre el vector de sinopsis elegido.
  3. 3 · Fusión RRF Una sola lista final, ordenada por la posición de cada película en las dos listas.

Cómo funciona Reciprocal Rank Fusion

RRF combina las dos listas según la posición de cada película en ellas, no según su puntuación, porque las escalas de BM25 y de la similitud vectorial no son comparables. Una película que aparece arriba en ambas listas sube en el resultado final.

Parámetros de la fusión

La demo no los expone en la interfaz: rank_constant usa el valor por defecto de Elasticsearch y rank_window_size lo fija la aplicación.

rank_constant = 60
Cuanto más alto, más influencia tienen las películas que están más abajo en cada lista.
rank_window_size = k
Cuántos resultados de cada componente entran a la fusión y cuántos resultados combinados se pueden recorrer. La aplicación lo iguala a k (100 por defecto), así que ambos componentes aportan la misma cantidad y las páginas de 25, 50 o 100 nunca salen vacías.

Documentación RRF retriever

Resultados y filtros

Los resultados se muestran por páginas, con la puntuación que corresponde a cada modo, y se pueden acotar con filtros que se calculan a partir de los propios resultados.

Paginación

25 · 50 · 100 por página
El usuario elige el tamaño de página y se mueve con Anterior, Siguiente o el número de página. Al cambiar el tamaño o aplicar filtros se vuelve a la página 1.
Full-text
Se pueden recorrer todas las coincidencias con from y size, hasta el límite de 10 000 que fija index.max_result_window.
Vectorial
Hay como máximo k resultados (100 por defecto), repartidos en páginas.
Híbrida
Hay como máximo rank_window_size resultados combinados. La aplicación lo iguala a k, así que from + size nunca supera la ventana y ninguna página sale vacía.

Puntuación de cada resultado

Full-text
Puntuación BM25. No tiene una escala fija: solo sirve para comparar resultados de una misma búsqueda.
Vectorial
Similitud k-NN. Con cosine, Elasticsearch devuelve (1 + coseno) / 2, un valor entre 0 y 1.
Híbrida
La puntuación BM25 y la similitud k-NN, cada una con la posición de la película en su lista, más la puntuación RRF que define el orden final.

Filtros

Campos
adult, genres, release_date (rango desde–hasta), spoken_languages y rating.
Combinación
Entre filtros distintos se cumplen todos; dentro de un mismo filtro basta con uno de los valores marcados. Los cambios se aplican al pulsar APLICAR; la fecha «Desde» no puede ser posterior a «Hasta».
Valores dinámicos
Cada filtro muestra solo los valores presentes en los resultados actuales, con cuántos resultados tienen cada uno, y se recalculan cada vez que cambian los resultados. Los valores ya marcados siguen visibles para poder desmarcarlos.
En Elasticsearch
Full-text: los filtros van en el contexto filter de la consulta, que no altera la puntuación BM25, y los valores salen de agregaciones terms. Vectorial: los filtros van en el filter del retriever knn, que se aplica durante la búsqueda, así que se devuelven k películas que los cumplen. Híbrida: van en el filter del retriever rrf, que se aplica a las dos búsquedas.
Valores en Vectorial e Híbrida
La aplicación los calcula sobre los resultados devueltos (hasta k). En RRF las agregaciones incluirían todas las coincidencias de cada búsqueda, incluso películas que no aparecen en la lista combinada.

Cuando no hay resultados

Si la búsqueda no encuentra nada, la página lo dice y sugiere ajustes según el modo (por ejemplo, OR en lugar de AND). Si la búsqueda sí encontró películas pero ninguna cumple los filtros, lo explica y ofrece quitarlos.

Documentación Paginación Terms aggregation Filtrar kNN RRF retriever

Carga de datos

Se pueden agregar películas una por una o importar un archivo. Un archivo se puede cargar en dos modos: append, que agrega las películas al catálogo, o bulk, que lo reemplaza. En los dos se valida todo el archivo antes de escribir.

Formas de carga

Registro individual
Formulario con los campos del mapping. id, title y plot son obligatorios.
Archivo .json
La exportación del índice (objeto con documents y, opcionalmente, mapping y document_count), un arreglo de películas o NDJSON.
Archivo .csv
Texto UTF-8 con o sin BOM, separado por comas y con encabezado. Un CSV sin encabezado se rechaza. Las listas y los objetos anidados van como JSON dentro de la celda.

Validaciones

Antes de subir
Solo .json o .csv, sin dobles extensiones, de máximo 25 MB y con contenido de texto UTF-8. El servidor repite estas comprobaciones.
Contra el mapping
Se revisa el archivo completo: cada campo debe existir en el mapping y tener su tipo (release_date en yyyy-MM-dd, adult booleano, keywords y belongs_to_collection como objetos anidados). id no se puede repetir.
Si algo no coincide
La carga se detiene y no se importa ningún registro. La página muestra cada error con su registro, id, campo, valor recibido y lo que espera el mapping, y permite descargar el informe completo.
Advertencias
Lo que no rompe el mapping no detiene la carga: por ejemplo, los valores vacíos dentro de una lista se omiten y los textos vacíos se guardan sin valor.

Importación

Vectores
Los tres vectores se generan siempre desde plot con el servicio de inferencia de Elasticsearch (jina-embeddings-v5-omni-small, input_type ingest y sin prefijo). Si el archivo trae plot_256, plot_512 o plot_1024, se ignoran.
Modo append (por defecto)
Las películas del archivo se agregan al índice vigente a través del alias, en lotes de 100 y sin índice temporal. Si un id ya existe, la película se reemplaza. Si un lote falla o se cancela la carga, lo ya escrito se queda y la página dice cuántas películas se agregaron.
Modo bulk
Las películas del archivo se escriben en lotes de 100 en un índice temporal nuevo, que contiene solo las películas del archivo: el catálogo actual no se copia.
Publicación (bulk)
Al terminar se comprueba el conteo y el alias elastiflix-reloaded pasa al índice nuevo en una sola operación atómica. El índice anterior se borra.
Si falla (bulk)
Si Elasticsearch rechaza un lote o la comprobación no cuadra, se borra el índice temporal y el catálogo queda exactamente como estaba.

Documentación Alias de índices Dense vector

Créditos y aviso de uso

Fines académicos y demostrativos

Elastiflix-Movies Java es un proyecto académico que demuestra técnicas de búsqueda full-text, vectorial e híbrida. No es un producto comercial: no se vende, no muestra publicidad y de ninguna manera pretende obtener un lucro comercial con él ni con la información que usa.

Los créditos de la información de las películas corresponden a TMDB y a Wikipedia.

Los datos de las películas y las imágenes de pósters vienen de TMDB (The Movie Database).

This product uses the TMDB API but is not endorsed or certified by TMDB.

Este producto usa la API de TMDB, pero no está avalado ni certificado por TMDB.

Los textos de las películas vienen de Wikipedia, cuyo contenido se publica bajo la licencia Creative Commons Atribución-CompartirIgual 4.0.

Los nombres, marcas, pósters y textos pertenecen a sus respectivos titulares. Esta demo no está afiliada a TMDB ni a Wikipedia, ni avalada por ellos.