¿Cómo funciona el cursorMark de Solr para resolver la paginación profunda mientras es apátrida?



pagination full-text-search (1)

Esta pregunta ya se hizo antes, pero no estoy satisfecho y necesito una mayor elaboración.

Estas son las premisas básicas:

  1. cursorMark no tiene estado. No almacena nada en el servidor
  2. cursorMark es un valor calculado que indica si se debe omitir un documento o no

No estoy seguro si lo entendí correctamente, pero así es como leo las explicaciones dadas.

Mis preguntas son:

  1. Si cursorMark está destinado a saber qué documentos omitir, ¿cómo no se trata de una búsqueda? Básicamente es una búsqueda al ejecutar una secuencia de documentos y hacer la pregunta "¿Es esto lo que estoy buscando o necesito omitir esto?"

  2. Aún relacionado con la primera pregunta, ¿cómo se calcula esta "secuencia de documentos"? ¿No está eso almacenado en la memoria? ¿O es cursorMark la creación de un archivo temporal almacenado en el disco?

  3. ¿Cómo calcula el próximo cursorMark si no recuerda todo el universo de resultados?

Todo lo que puedo ver es que no hay escapatoria.

O almacenas algún estado sobre tus resultados de búsqueda o realizas búsquedas para cada solicitud de página.

Referencias relacionadas

cursorMark no tiene estado y cómo resuelve la localización profunda

¿Cuánto tiempo tiene el cursorMark disponible en el servidor Solr?

http://yonik.com/solr/paging-and-deep-paging/


cursorMark no afecta la búsqueda: la búsqueda se realiza como siempre. cursorMark no es un índice o relevante para la forma en que se realiza la búsqueda real, pero es una estrategia para permitir la paginación eficiente a través de grandes conjuntos de datos. Esto también significa que su segunda pregunta se vuelve irrelevante, ya que no cambia nada acerca de cómo se realiza la búsqueda real.

La razón por la cual cursorMark soluciona la paginación profunda se vuelve aparente cuando se considera el caso de un clúster de servidores Solr, como cuando se ejecuta en modo SolrCloud.

Supongamos que tiene cuatro servidores, A , B , C y D , y desea recuperar 10 documentos a partir de la fila número 400 (asumiremos que un servidor == un fragmento de una colección más grande para facilitar esto).

En el caso normal, tendrá que comenzar por recuperar (en orden ordenado, ya que cada nodo clasificará su conjunto de resultados de acuerdo con su consulta; esto no es diferente de cualquier consulta normal, ya que deberá ordenarse localmente de todos modos ), y luego fusionar:

  • 410 documentos del servidor A
  • 410 documentos del servidor B
  • 410 documentos del servidor C
  • 410 documentos del servidor D

Ahora tiene que ir a través de documentos 1640 para descubrir cuál será su conjunto de resultados real , ya que podría ser que los 10 documentos que está buscando, todos se encuentren en el servidor C O tal vez 350 en el servidor B y el resto en el servidor D Es imposible decir sin recuperar 410 documentos de cada servidor. El conjunto de resultados se fusionará y ordenará hasta que se hayan omitido 400 documentos y se hayan encontrado 10 documentos.

Ahora supongamos que quiere 10 documentos a partir de la fila 1 000 000; deberá recuperar 1 000 010 documentos de cada servidor y fusionar y ordenar un conjunto de resultados de 4 000 040 documentos. Puede ver que esto se vuelve cada vez más caro a medida que aumenta el número de servidores y documentos, solo para aumentar el punto de partida en 10 documentos.

En su lugar, supongamos que sabe cuál es el orden de clasificación global (es decir, el valor de clasificación léxica del último documento devuelto). La primera consulta, sin cursorMark, será la misma que para la paginación normal: obtenga los primeros 10 documentos de cada servidor (ya que estamos comenzando al inicio del conjunto de resultados (y no desde la posición 400 como en el primer ejemplo) , solo necesitamos 10 de cada servidor).

Procesamos estos 40 documentos (un tamaño muy manejable), los ordenamos y recuperamos los 10 primeros documentos, y luego incluimos la clave de clasificación global (cursorMark) del último documento. El cliente luego incluye esta "clave de clasificación global" en la solicitud, lo que nos permite decir "OK, no estamos interesados ​​en ninguna entrada que se ordene frente a este documento, como ya hemos mostrado". La siguiente consulta entonces haría:

  • 10 documentos del servidor A, que ordenarían después de cursorMark
  • 10 documentos del servidor B, que ordenarían después de cursorMark
  • 10 documentos del servidor C, que ordenarían después de cursorMark
  • 10 documentos del servidor D, que ordenarían después de cursorMark

Ahora solo estamos devolviendo 10 documentos de cada servidor, incluso si nuestro cursorMark tiene un millón de filas de profundidad en la paginación. Donde previamente tuvimos que recuperar, ordenar (bueno, podemos suponer que se devuelven ordenados del conjunto de resultados, entonces tenemos que revisar los conjuntos de resultados y encontrar el primer millón de entradas, luego elegir los siguientes diez de los conjuntos, después de recuperándolos) y manejar 4 000 040 documentos, ahora solo tenemos que recuperar 40 documentos y ordenarlos localmente para obtener los 10 documentos reales para regresar.

Para explicar mejor cómo un cursorMark podría funcionar, supongamos que este enfoque solo funcionó en columnas únicas con un valor entero (ya que eso hace que sea más fácil mostrar lo que el cursorMark representa internamente, y por qué la clave única tiene que estar presente en el género ) ( si la clave única no estaba presente, podríamos terminar al azar con los documentos faltantes si el cursorMark terminara en un documento con múltiples valores idénticos para el campo de clasificación):

A    B    C    D
1    2    3    4
8    7    6    5
9    10   11   12
13   14   15   16
17   20   21   22
18   23   25   27
19   24   26   28

Hacemos una solicitud de 4 valores (filas = 4), comenzando desde cursorMark 7. Cada servidor puede ver su conjunto de resultados (que está ordenado internamente, como todos los conjuntos de resultados), y recuperar 4 valores a partir del valor que viene después de 7 en el orden ordenado: (<significa que aquí es donde el primer valor después de cursorMark es, + significa que este documento está incluido en el conjunto de resultados devuelto por el nodo)

A    B    C    D
1    2    3    4
8  < 7    6    5
9  + 10 < 11 < 12 <
13 + 14 + 15 + 16 +
17 + 20 + 21 + 22 +
18   23 + 25 + 27 +
19   24   26   28

Luego iteramos a través de cada conjunto de resultados devuelto, hasta que hayamos elegido cuatro documentos de la parte superior:

8 (from A)
9 (from A)
10 (from B)
11 (from C)

E incluimos el cursorMark del último documento: 11. La siguiente solicitud se realiza con 11 como cursorMark, lo que significa que cada servidor puede devolver 4 documentos a partir de la entrada después del 11 en su lugar:

A    B    C    D
1    2    3    4
8    7    6    5
9    10   11   12 <
13 < 14 < 15 < 16 +
17 + 20 + 21 + 22 +
18 + 23 + 25 + 27 +
19 + 24 + 26 + 28

Y luego realizamos la fusión nuevamente, seleccionando las primeras 4 entradas en orden ordenado, e incluimos el siguiente cursorMark.

.. y eso responde a la tercera pregunta: no necesita conocer el estado global, solo cuál es el próximo resultado que necesita para regresar del gigantesco conjunto de datos.