Pregunta de la entrevista de JD.COM: solución de paginación profunda ElasticSearch
En el uso de bases de datos relacionales, se nos dice que tengamos cuidado e incluso se nos prohíbe explícitamente el uso de paginación profunda. Asimismo, en Elasticsearch debemos intentar evitar el uso de paginación profunda.
¡Este artículo presenta principalmente el contenido relacionado con la paginación en Elasticsearch!
En ES, de forma predeterminada, la consulta de paginación devuelve los primeros 10 resultados coincidentes.
Si se requiere paginación, se deben utilizar los parámetros from y size.
La declaración de consulta básica de ES es así:
La consulta anterior indica 10 datos a partir de 100 resultados de búsqueda.
Entonces, ¿cómo se ejecuta esta consulta en el clúster ES? 》
En ES, la búsqueda generalmente incluye dos etapas, la etapa de consulta y la etapa de recogida, que se pueden entender fácilmente. La fase de consulta determina qué documento recuperar y la fase de recuperación recupera documentos específicos.
Como se muestra en la figura anterior, se describe la fase de consulta de la solicitud de búsqueda:.
En el ejemplo anterior, el nodo de coordinación obtiene (de+tamaño) * 6 datos, luego los fusiona y clasifica, y luego selecciona los datos anteriores de+tamaño para almacenarlos en la cola de prioridad. Para uso en la fase de extracción.
Además, los datos devueltos por cada segmento al nodo coordinador se utilizan para seleccionar los primeros datos de+tamaño, por lo que solo se devuelven el _id que marca de forma única el documento y el _score utilizado para ordenar, lo que También se puede garantizar que la cantidad de datos devueltos sea lo suficientemente pequeña.
Después de que el nodo coordinador calcula su propia cola de prioridad, la fase de consulta finaliza y entra en la fase de adquisición.
La fase de consulta sabe qué datos obtener, pero no obtiene datos concretos, que es lo que debe hacer la fase de adquisición.
La figura anterior muestra el proceso de adquisición:
Hay from+size_doc_id en la cola de prioridad del nodo de coordinación, pero durante la fase de adquisición, no es necesario recuperar todos los datos. . En el ejemplo anterior, no es necesario recuperar los primeros 100 datos, solo los 101 a 110 datos de la cola de prioridad.
Los datos que se recuperarán pueden estar en diferentes sectores o en el mismo sector. El nodo coordinador utiliza "obtención múltiple" para evitar recuperar datos del mismo sector varias veces, mejorando así el rendimiento.
"Solicitar una paginación profunda de esta manera es problemático:"
Podemos asumir que estamos buscando en un índice con cinco secciones principales. Cuando solicitamos la primera página de resultados (los resultados van del 1 al 10), cada segmento genera los 10 resultados principales y los devuelve al nodo coordinador, que ordena los 50 resultados para obtener los 10 resultados principales de los 10 resultados.
Ahora supongamos que solicitamos la página 1000; el resultado es de 10001 a 10010. Todos funcionan de la misma manera excepto que cada segmento debe producir los primeros 10010 resultados. Luego, el nodo coordinador clasifica los 50050 resultados y, finalmente, descarta 50040 de estos resultados.
"El costo de ordenar los resultados aumenta exponencialmente con la profundidad de la paginación".
"Nota 1:"
El tamaño del tamaño no puede exceder el parámetro configuración index.max_result_window, el valor predeterminado es 10000.
Si el tamaño de la búsqueda es mayor que 10000, debe configurar el parámetro index.max_result_window.
"Nota 2:"
_doc se eliminará en versiones futuras. Ver:
El modo Desde/Tamaño de Elasticsearch proporciona funcionalidad de paginación, pero también tiene las restricciones correspondientes.
Por ejemplo, un índice tiene 100 millones de datos, divididos en 10 fragmentos, y luego una solicitud de búsqueda, desde=100000, tamaño=100, provocará graves problemas de rendimiento: CPU, memoria, IO, ancho de banda de red. .
En la fase de consulta, cada fragmento debe devolver 1000100 datos al nodo de coordinación, y el nodo de coordinación debe recibir 10 * 1000, 100 datos incluso si cada dato solo tiene. _doc _id y _score, la cantidad de datos es muy grande.
"Por otro lado, nos damos cuenta de que las solicitudes de paginación tan profundas no son razonables porque rara vez revisamos manualmente las solicitudes muy tardías. En muchos escenarios comerciales, la paginación está directamente limitada, por ejemplo, solo podemos leer la página 100. "
Por ejemplo, un influencer de WeChat con 100.000 fans necesita enviar un mensaje a todos los fans, o a los fans de una determinada provincia. En este momento, es necesario obtener todos los ventiladores calificados. Lo más fácil de pensar es usar from+size para lograrlo. Sin embargo, esto no es realista. En este momento, puede utilizar otros métodos proporcionados por Elasticsearch para implementar el recorrido.
Los problemas de paginación profunda se pueden dividir aproximadamente en dos categorías:
"Los siguientes son algunos métodos oficiales de paginación profunda".
Podemos entender el desplazamiento como una relación cursor de base de datos en . Por lo tanto, el desplazamiento no es adecuado para búsquedas en tiempo real, pero es más adecuado para tareas de procesamiento por lotes en segundo plano, como la entrega por lotes.
El uso de este tipo de paginación "no es para consultar datos en tiempo real", sino para consultar una gran cantidad de datos (o incluso todos los datos) a la vez.
Debido a que esta consulta continua es equivalente a mantener una instantánea del segmento de índice actual, cuando ejecuta esta consulta continua, esta información de la instantánea es la instantánea. Los datos recién indexados después de esta consulta no se encontrarán en esta instantánea.
Pero en comparación con desde y tamaño, no consulta todos los datos ni elimina partes innecesarias, sino que registra una posición de lectura para garantizar una lectura rápida la próxima vez.
Cuando no se considera la clasificación, se puede utilizar en combinación con SearchType.SCAN.
El desplazamiento se puede dividir en dos partes: inicialización y recorrido. Durante la inicialización, "todos los resultados de búsqueda que cumplen con las condiciones de búsqueda se almacenan en caché (tenga en cuenta que este es solo el doc_id almacenado en caché, no todos los datos del documento se almacenan en caché, la recuperación de datos se completa en la fase de recuperación)", lo que se puede imaginar como una instantánea. .
Durante el recorrido, los datos se extraen de esta instantánea, es decir, después de la inicialización, insertar, eliminar y actualizar datos en el índice no afectará los resultados del recorrido.
"Propósito básico"
La inicialización indica el índice y el tipo, y luego agrega el parámetro de desplazamiento para indicar el tiempo para almacenar temporalmente los resultados de la búsqueda, y el resto es como un Solicitud de búsqueda normal.
_scroll_id, _scroll_id se devolverá para la siguiente recuperación de datos.
"Traversabilidad"
El scroll_id aquí es el _scroll_id recuperado del recorrido anterior o el _scroll_id devuelto por la inicialización. Asimismo, se requiere el parámetro de desplazamiento.
Repita este paso hasta que los datos devueltos estén vacíos, es decir, se complete el recorrido.
Tenga en cuenta que el parámetro de desplazamiento debe pasarse cada vez que se actualiza el tiempo de caché de los resultados de la búsqueda. Además, "no es necesario especificar índices y tipos".
Al configurar el desplazamiento, los resultados de la búsqueda deben almacenarse en caché hasta que se complete el siguiente recorrido. "Al mismo tiempo, no debería llevar mucho tiempo. Después de todo, el espacio es limitado".
"Ventajas y desventajas"
Desventajas:
"Ventajas:"
Adecuado para el procesamiento no en tiempo real de grandes cantidades de datos, como migración de datos o cambios de índice.
ES proporciona un método de escaneo continuo para mejorar aún más el rendimiento transversal, pero el escaneo continuo no admite la clasificación, por lo que el escaneo continuo es adecuado para escenarios que no requieren clasificación.
"Uso básico"
El recorrido del escaneo de desplazamiento es el mismo que el del desplazamiento normal, pero la inicialización es ligeramente diferente.
Necesita especificar parámetros:
"La diferencia entre escaneo de desplazamiento y desplazamiento"
Si tiene una gran cantidad de datos, use Scroll para recorrer los datos Es realmente inaceptable. Las interfaces de desplazamiento ahora atraviesan datos al mismo tiempo.
Cada solicitud de desplazamiento se puede dividir en múltiples solicitudes de corte, que pueden entenderse como cortes. Cada corte es independiente y paralelo, lo que es muchas veces más rápido que el desplazamiento.
El ejemplo anterior puede solicitar dos datos por separado y el resultado final de fusionar cinco datos es el mismo que el escaneo de desplazamiento directo.
Entre ellos, max es el número de bloques e id es el número de bloques.
Search_after es un nuevo mecanismo de consulta de paginación introducido en ES 5. Su principio es similar al desplazamiento, por lo que el código es similar.
"Propósito básico:"
Paso uno:
Información del resultado devuelto:
La solicitud anterior devolverá una matriz, en la que Contiene el valor de clasificación para cada documento.
Estos valores de clasificación se pueden utilizar en el parámetro search_after para capturar la siguiente página de datos.
Por ejemplo, podemos usar el valor de clasificación del último documento y pasarlo al parámetro search_after:
Si queremos leer la página siguiente después de los datos del último resultado leído, la segunda consulta agrega search_after a la oración de la primera consulta e indica desde qué datos comenzar a leer.
"Principios Básicos"
Es mantiene un cursor en tiempo real. El último registro de la consulta anterior es un cursor para facilitar la consulta de la página siguiente. Es una consulta sin estado, por lo que consulta los datos más recientes cada vez.
Debido a que utiliza registros como cursores, "SearchAfter requiere al menos una variable globalmente única en el documento (los campos con valores únicos por documento deben usarse como especificaciones de clasificación)".
"Ventajas y Desventajas"
"Ventajas:"
"Desventajas:"
SEARCH_AFTER no es una solución para saltar libremente a cualquier esquema de página, pero una solución para realizar múltiples consultas en paralelo.
Las ventajas y desventajas de rendimiento del modo de paginación son que el escenario desde+tamaño es bajo y flexible, la cantidad de datos necesarios para implementar problemas simples de paginación profunda es pequeña y los problemas de paginación profunda se pueden tolerar. Scroll resuelve el problema de la paginación profunda y no puede reflejar el rendimiento de los datos en tiempo real (versión instantánea). Los costos de mantenimiento son altos. Para la exportación de datos masivos, es necesario mantener un scroll_id. Necesidad de consultar datos de conjuntos de resultados masivos. search_after es muy eficaz. Es mejor no tener problemas de paginación profundos. Puede reflejar la complejidad de los cambios de datos en tiempo real. Es más complicado realizar una paginación continua con un campo globalmente único, porque cada consulta requiere los resultados de la consulta anterior, lo que no es adecuado para paginar datos masivos con grandes saltos de página.
Referencia:/elastic/elastic search/issues/29449), el problema del reenvío de páginas en es se puede resolver invirtiendo la clasificación, es decir:
Los principios de Scroll y search_after son básicos Lo mismo, ambos usan cursores para paginación profunda.
Aunque este método puede resolver el problema de la paginación profunda hasta cierto punto. Sin embargo, no son la solución definitiva al problema de paginación profunda, que debe evitarse. ! ”.
Para Scroll, mantener scroll_id y las instantáneas históricas es inevitable, y es necesario garantizar el tiempo de supervivencia de scroll_id, lo cual supone una carga enorme para el servidor.
Para Search_After, si a los usuarios se les permite saltar a la página de manera significativa, se generarán acciones de búsqueda frecuentes en un corto período de tiempo, lo cual es muy ineficiente y también aumentará la carga en el servidor. Al mismo tiempo, durante el proceso de consulta, la adición, eliminación y modificación de índices provocará inconsistencias en los datos de la consulta o cambios en las clasificaciones, lo que dará como resultado resultados inexactos.
Search_After en sí es un compromiso comercial. No le permite especificar un salto a una página y solo proporciona la función de la página siguiente.
Scroll eliminará todos los datos calificados de forma predeterminada, por lo que solo buscará todos los doc_ids calificados (es por eso que se recomienda oficialmente usar Doc_ID para ordenar, porque almacena en caché el propio Doc_ID) y ordenar con otros campos. aumentará el volumen de consulta) y luego guárdelo en el nodo de coordenadas. Sin embargo, en lugar de obtener todos los datos, nos desplazamos por los documentos grandes y pequeños a la vez y devolvemos el último documento leído esta vez y el estado de contexto para indicar qué fragmento de documento debe leerse la próxima vez.
Esta es también la razón por la que el gobierno no recomienda el desplazamiento para que los usuarios realicen consultas de paginación en tiempo real, pero es adecuado para extraer datos en lotes grandes, porque no está diseñado para lectura en tiempo real. de datos.