Paginar los resultados de la búsqueda

Las aplicaciones web suelen paginar los datos a medida que se presentan a los usuarios. El usuario final recibe una página de resultados y, cuando navega a la siguiente, se recupera y presenta el siguiente lote de resultados. En esta página, se describe cómo agregar paginación a los resultados de la búsqueda cuando se realiza una búsqueda de texto completo en Spanner.

Opciones de paginación

Existen dos maneras de implementar consultas paginadas en Spanner: paginación basada en claves (recomendado) y paginación basada en offsets.

La paginación basada en claves es un método para recuperar resultados de la búsqueda en fragmentos más pequeños y fáciles de administrar, a la vez que se garantizan resultados coherentes en todas las solicitudes. Se usa un identificador único (la "clave") del último resultado de una página como punto de referencia para recuperar el siguiente conjunto de resultados.

Por lo general, Spanner recomienda usar la paginación basada en claves. Si bien la paginación basada en offsets es más fácil de implementar, tiene dos inconvenientes importantes:

  1. Mayor costo de consulta:La paginación basada en offsets recupera y descarta de forma reiterada los mismos resultados, lo que genera un aumento de los costos y una disminución del rendimiento.
  2. Resultados incoherentes: En las consultas paginadas, por lo general, cada página se recupera en una marca de tiempo de lectura diferente. Por ejemplo, la primera página podría provenir de una búsqueda a la 1 p.m. y la siguiente de una búsqueda a la 1:10 p.m. Esto significa que los resultados de la búsqueda pueden cambiar entre las consultas, lo que genera resultados inconsistentes en las páginas.

Por otro lado, la paginación basada en claves usa un identificador único (clave) del último resultado de una página para recuperar el siguiente conjunto de resultados. Esto garantiza una recuperación eficiente y resultados coherentes, incluso si cambian los datos subyacentes.

Para proporcionar estabilidad en los resultados de la página, la aplicación podría emitir todas las consultas para diferentes páginas en la misma marca de tiempo. Sin embargo, esto podría fallar si la consulta supera el período de retención de versiones (el valor predeterminado es de 1 hora). Por ejemplo, esta falla ocurre si version_gc es una hora y el usuario final recuperó los primeros resultados a la 1 p.m. y hizo clic en Siguiente a las 3 p.m.

Usa la paginación basada en claves

La paginación basada en claves recuerda el último elemento de la página anterior y lo usa como punto de partida para la siguiente consulta de página. Para lograrlo, la consulta debe mostrar las columnas especificadas en la cláusula ORDER BY y limitar la cantidad de filas con LIMIT.

Para que funcione la paginación basada en claves, la consulta debe ordenar los resultados según un orden total estricto. La forma más sencilla de obtener uno es elegir cualquier orden total y, luego, agregar columnas de desempate, si es necesario. En la mayoría de los casos, el orden total es el orden de clasificación del índice de búsqueda, y la combinación única de columnas es la clave primaria de la tabla base.

Con nuestro esquema de muestra de Albums, para la primera página, la consulta se ve de la siguiente manera:

SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 10;

AlbumId es el desempate, ya que ReleaseTimestamp no es una clave. Puede haber dos álbumes diferentes con el mismo valor para ReleaseTimestamp.

Para reanudar, la aplicación vuelve a ejecutar la misma consulta, pero con una cláusula WHERE que restringe los resultados de la página anterior. La condición adicional debe tener en cuenta la dirección de la clave (ascendente o descendente), los desempates y el orden de los valores NULL para las columnas con valores nulos.

En nuestro ejemplo, AlbumId es la única columna clave (en orden ascendente) y no puede ser NULL, por lo que la condición es la siguiente:

SELECT AlbumId, ReleaseTimestamp
FROM Albums
WHERE (ReleaseTimestamp < @last_page_release_timestamp
       OR (ReleaseTimestamp = @last_page_release_timestamp
           AND AlbumId > @last_page_album_id))
      AND SEARCH(AlbumTitle_Tokens, @p)
ORDER BY ReleaseTimestamp DESC, AlbumId ASC
LIMIT @page_size;

Spanner interpreta este tipo de condición como buscable. Esto significa que Spanner no lee el índice de los documentos que estás filtrando. Esta optimización es lo que hace que la paginación basada en claves sea mucho más eficiente que la paginación basada en offsets.

Usa la paginación basada en desplazamientos

La paginación basada en el desplazamiento aprovecha las cláusulas LIMIT y OFFSET de la consulta en SQL para simular páginas. El valor de LIMIT indica la cantidad de resultados por página. El valor OFFSET se establece en cero para la primera página, en el tamaño de la página para la segunda página y en el doble del tamaño de la página para la tercera página.

Por ejemplo, la siguiente consulta recupera la tercera página, con un tamaño de página de 50:

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY ReleaseTimestamp DESC, AlbumId
LIMIT 50 OFFSET 100;

Notas de uso:

  • Se recomienda usar la cláusula ORDER BY para garantizar un orden coherente entre las páginas.
  • En las consultas de producción, usa parámetros de consulta en lugar de constantes para especificar LIMIT y OFFSET para que el almacenamiento en caché de consultas sea más eficiente. Para obtener más información, consulta Parámetros de consulta.

¿Qué sigue?