BM25 práctico - Parte 1: cómo afectan los shards a la relevancia en Elasticsearch
Esta es la primera publicación de la serie de tres partes Practical BM25 sobre la clasificación por similitud (relevancia). La siguiente publicación está enlazada al final.
Antecedentes
En Elasticsearch 5.0, cambiamos a Okapi BM25 como nuestro algoritmo de similitud predeterminado, que es el que se utiliza para puntuar los resultados en relación con una búsqueda. No entraré demasiado en BM25 frente a otras medidas en este blog, pero si quieres una introducción a la justificación teórica de BM25, puedes ir a ver la presentación BM25 Demystified de Elastic{ON} 2016. En su lugar, voy a cubrir (y espero desmitificar) el uso práctico de BM25 para ti, incluyendo los parámetros disponibles y lo que afecta a la puntuación.
Ten en cuenta que este blog se referirá en gran medida a quienes realizan la puntuación de documentos de texto. Es decir, está realmente enfocado en ayudar a nuestros usuarios de búsqueda. Si estás indexando logs o métricas y devolviendo resultados ordenados por algún metadato explícito u orden numérico como la marca de tiempo, este blog puede servir principalmente para satisfacer tu curiosidad.
Cómo entender cómo los shards afectan la puntuación
Como espero que sigas los pasos desde casa, una de las primeras cosas que debemos aclarar es entender cómo tener más de 1 shard afecta la puntuación, ya que Elasticsearch usa 5 shards primarios por índice de forma predeterminada. Comencemos creando un índice llamado “people”. Los ajustes que proporciono aquí serían los predeterminados (y, por lo tanto, innecesarios de definir), pero lo haré de todos modos para ser explícito con fines de demostración. Usaré variantes de mi nombre (“Shane Connelly”) aquí, pero siéntete libre de reemplazarlo con un nombre de tu elección si estás siguiendo los pasos desde casa.
PUT people
{
"settings": {
"number_of_shards": 5,
"índice" : {
"similitud" : {
"default" : {
"type" : "BM25"
}
}
}
}
}
Y ahora agreguemos un documento y hagamos una búsqueda de él. Primero, solo agregaremos mi nombre:
PUT /people/_doc/1
{
"title": "Shane"
}
GET /people/_doc/_search
{
"query": {
"match": {
"title": "Shane"
}
}
}
Obtienes 1 resultado en este punto, con una puntuación de 0.2876821. Profundizaremos en cómo se deriva esta puntuación en un momento, pero primero veamos qué sucede cuando agregamos algunos documentos más con diferentes variantes de mi nombre completo.
PUT /people/_doc/2
{
"title": "Shane C"
}
PUT /people/_doc/3
{
"title": "Shane Connelly"
}
PUT /people/_doc/4
{
"title": "Shane P Connelly"
}
Y ahora haz la misma búsqueda de nuevo:
GET /people/_doc/_search
{
"query": {
"match": {
"title": "Shane"
}
}
}
En este punto, deberías tener 4 resultados, pero si miras las puntuaciones, es posible que te rasques la cabeza. Los documentos 1 y 3 tienen una puntuación de 0.2876821, pero el documento 2 tiene una puntuación de 0.19856805 y el documento 4 tiene una puntuación de 0.16853254. Esto es algo que a menudo confunde a los nuevos usuarios. Los documentos 2 y 3 son muy similares —ambos tienen 2 términos y ambos coinciden con “shane”—, pero el documento 2 tiene una puntuación mucho más baja. Puedes empezar a asumir que hay algo diferente en la puntuación de “C” frente a la puntuación de “Connelly”, pero, de hecho, esto tiene que ver con cómo los documentos aterrizaron en los shards.
Como recordatorio, Elasticsearch divide los documentos en shards, y cada shard contiene un subconjunto de los datos. Si echamos un vistazo a:
GET /_cat/shards/people?v
Si ejecutas esto, verás que el shard 2 tiene 2 documentos, mientras que los shards 3 y 4 solo tienen 1 documento (los shards 0 y 1 aún no tienen documentos). Esto significa que la cantidad total de apariciones del término “shane” es diferente en estos distintos shards y eso es lo que, en última instancia, provoca la diferencia en las puntuaciones en este caso. De forma predeterminada, Elasticsearch calcula las puntuaciones por cada shard.
Las personas comienzan a cargar solo unos pocos documentos en su índice y preguntan “¿por qué el documento A tiene una puntuación más alta/baja que el documento B?” y, a veces, la respuesta es que el usuario tiene una proporción relativamente alta de shards por documento, por lo que las puntuaciones están sesgadas entre los diferentes shards. Hay algunas formas de obtener puntuaciones más consistentes entre los shards:
- Cuantos más documentos cargues en tu índice, más normalizadas estarán las estadísticas de términos de tus shards. Con suficientes documentos, es posible que no notes las ligeras diferencias en las estadísticas de términos y, por lo tanto, en la puntuación de cada shard.
- Podrías usar una cantidad menor de shards para reducir las desviaciones estadísticas en las frecuencias de los términos. Por ejemplo, si hubiéramos configurado
number_of_shardsen1en los ajustes del índice, tendríamos puntuaciones muy diferentes. Veríamos el documento 1 con una puntuación de 0.13245322, los documentos 2 y 3 con puntuaciones de 0.105360515 cada uno, y el documento 4 con una puntuación de 0.0874691. Existen algunas compensaciones al tener varias cantidades de shards primarios, lo cual se analiza en nuestro webinar sobre dimensionamiento cuantitativo de clústeres. - Puedes añadir
?search_type=dfs_query_then_fetcha la solicitud, lo cual primero recopila las frecuencias de términos distribuidas (DFS = Distributed Frequency búsqueda) y luego calcula las puntuaciones usándolas. De hecho, esto devuelve la misma puntuación que tener solo 1 shard. Echa un vistazo a cómo difieren los resultados con y sin el parámetro “search_type”:GET /people/_doc/_search?search_type=dfs_query_then_fetch { "query": { "match": { "title": "Shane" } } }Esto proporciona lo mismo que haber configuradonumber_of_shards=1. Entonces, te preguntarás: “Bueno, si esto produce puntuaciones más precisas, ¿por qué no está activado de forma predeterminada?” La respuesta es que añade un viaje de ida y vuelta adicional durante el procesamiento para ir a recopilar todas las estadísticas y, para algunos casos de uso (donde la precisión de la puntuación no es tan importante como la velocidad), este viaje de ida y vuelta es innecesario. Además, con suficientes datos en los shards, las estadísticas pueden volverse muy similares entre sí, lo que también hace innecesarios los viajes de ida y vuelta. Si tienes suficientes datos,search_type=dfs_query_then_fetchsolo es necesario principalmente cuando los datos entre shards siguen estando distribuidos de forma desigual, como es el caso con algo de enrutamiento personalizado.
Bien, ahora tenemos una idea de cómo el sharding puede afectar nuestra puntuación (y cómo ajustarla). A continuación, veremos el algoritmo BM25 y cómo entran en juego diferentes variables.
Continúa esta serie con: Parte 2: El algoritmo BM25 y sus variables