Paginación de resultados de 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 accede a la página siguiente, se recupera y se muestra el siguiente lote de resultados. En esta página se describe cómo añadir paginación a los resultados de búsqueda al realizar una búsqueda de texto completo en Spanner.

Opciones de paginación

Hay dos formas de implementar consultas paginadas en Spanner: paginación basada en claves (recomendada) y paginación basada en desplazamientos.

La paginación basada en claves es un método para obtener resultados de búsqueda en fragmentos más pequeños y fáciles de gestionar, al tiempo que se asegura la coherencia de los resultados en las solicitudes. Se usa un identificador único (la "clave") del último resultado de una página como punto de referencia para obtener el siguiente conjunto de resultados.

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

  1. Mayor coste de las consultas: la paginación basada en el desplazamiento recupera y descarta repetidamente los mismos resultados, lo que aumenta los costes y reduce el rendimiento.
  2. Resultados incoherentes: en las consultas paginadas, cada página se suele recuperar con una marca de tiempo de lectura diferente. Por ejemplo, la primera página puede proceder de una consulta a las 13:00 y la siguiente, de una consulta a las 13:10. Esto significa que los resultados de búsqueda pueden cambiar entre consultas, lo que provoca resultados incoherentes 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 obtener el siguiente conjunto de resultados. De esta forma, se garantiza tanto una recuperación eficiente como resultados coherentes, incluso si cambian los datos subyacentes.

Para ofrecer estabilidad en los resultados de las páginas, la aplicación podría emitir todas las consultas de diferentes páginas en la misma marca de tiempo. Sin embargo, esto podría fallar si la consulta supera el periodo de conservación de versiones (el valor predeterminado es 1 hora). Por ejemplo, este error se produce si version_gc es de una hora y el usuario final ha obtenido los primeros resultados a las 13:00 y ha hecho clic en Siguiente a las 15:00.

Usar 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 consulta de la página siguiente. Para ello, la consulta debe devolver las columnas especificadas en la cláusula ORDER BY y limitar el número de filas mediante LIMIT.

Para que la paginación basada en claves funcione, la consulta debe ordenar los resultados según un orden total estricto. La forma más sencilla de obtener una es elegir cualquier total de pedidos y, a continuación, añadir 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 principal de la tabla base.

Si usamos nuestro esquema de ejemplo Albums, la consulta de la primera página sería la siguiente:

GoogleSQL

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

PostgreSQL

SELECT albumid, releasetimestamp
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY releasetimestamp DESC, albumid
LIMIT 10;

El AlbumId es el factor de desempate, ya que ReleaseTimestamp no es una clave. Puede que haya dos álbumes diferentes con el mismo valor de ReleaseTimestamp.

Para reanudar la consulta, 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 criterios de desempate y el orden de los valores NULL de las columnas que admiten valores NULL.

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

GoogleSQL

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;

PostgreSQL

En este ejemplo se usan los parámetros de consulta $1, $2, $3 y $4, que están vinculados a los valores especificados para last_page_release_timestamp, last_page_album_id, query y page_size, respectivamente.

SELECT albumid, releasetimestamp
FROM albums
WHERE (releasetimestamp < $1
    OR (releasetimestamp = $1
        AND albumid > $2))
    AND spanner.search(albumtitle_tokens, $3)
ORDER BY releasetimestamp DESC, albumid ASC
LIMIT $4;

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 desplazamientos.

Usar la paginación basada en el desplazamiento

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

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

GoogleSQL

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

PostgreSQL

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY releasetimestamp DESC, albumid
LIMIT 50 OFFSET 100;

Notas de uso:

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

Siguientes pasos