Quando fazemos uma busca full-text sobre vários campos, o comportamento padrão do bool com should pode devolver documentos que combinam com muitos campos, mas com poucas palavras-chave em cada um, à frente de documentos onde um único campo concentra a maior parte dos termos. Para priorizar o docuemnto em que um campo específico acumula mais termos, usamos a estratégia best fields.
Preparando os documentos
O exemplo a seguir adiciona um campo de conteúdo a posts já existentes em um índice chamado blog:
POST /blog/posts/_bulk
{ "update": { "_id": "1" } }
{ "doc": { "conteudo": "i like to write best elasticsearch article" } }
{ "update": { "_id": "2" } }
{ "doc": { "conteudo": "i think java is the best programming language" } }
{ "update": { "_id": "3" } }
{ "doc": { "conteudo": "i am only an elasticsearch beginner" } }
{ "update": { "_id": "4" } }
{ "doc": { "conteudo": "elasticsearch and hadoop are all very good solution, i am a beginner" } }
{ "update": { "_id": "5" } }
{ "doc": { "conteudo": "spark is best big data solution based on scala, a programming language similar to java" } }
Problema do bool/should
Imagine buscar posts cujo titulo ou conteudo contenham java ou solution:
GET /blog/posts/_search
{
"query": {
"bool": {
"should": [
{ "match": { "titulo": "java solution" } },
{ "match": { "conteudo": "java solution" } }
]
}
}
}
Como o bool should soma os scores e aplica um fator de coordenação, um documento que casa nos dois campos pode superar outro que casa de forma mais concentrada em apenas um campo. O cálculo é:
score = (soma dos scores) × (queries que casaram / total de queries)
Suponha que o doc4 tenha score 1,1 no título e 1,2 no conteúdo: (1,1 + 1,2) × 2/2 = 2,3. O doc5, com score 0 no título e 2,3 no conteúdo, ficaria com 2,3 × 1/2 = 1,15. Assim, o doc4 aparece antes do doc5, mesmo não sendo o resultado mais relevante.
Usando dis_max para best_fields
A consulta dis_max retorna o maior score entre as cláusulas, sem somá-las:
GET /blog/posts/_search
{
"query": {
"dis_max": {
"queries": [
{ "match": { "titulo": "java solution" } },
{ "match": { "conteudo": "java solution" } }
]
}
}
}
Agora, o score do doc4 é max(1,1; 1,2) = 1,2, e o do doc5 é max(0; 2,3) = 2,3. O doc5 sobe no ranking, o que corresponde ao objetivo de best fields.
Limitação: campos ignorados
Com a consulta java beginner, o dis_max pode deixar de considerar a contribuição dos demais campos. Um documento com java apenas no título e outro com beginner apenas no conteúdo podem superar um documento com java no título e beginner no conteúdo, porque o maior score individual de cada um pode ser semelhante.
tie_breaker
Para não ignorar totalmente as outras cláusulas, usamos tie_breaker:
GET /blog/posts/_search
{
"query": {
"dis_max": {
"queries": [
{ "match": { "titulo": "java beginner" } },
{ "match": { "conteudo": "java beginner" } }
],
"tie_breaker": 0.3
}
}
}
O valor, geralmente entre 0 e 1, multiplica os scores das demais cláusulas e adiciona ao maior score. Dessa forma, o documento que casa em mais de um campo recebe um reforço adicional.
minimum_should_match
Esse parâmetro ajuda a eliminar a cauda longa de resultados, exigindo que um percentual mínimo dos termos seja atendido:
GET /blog/posts/_search
{
"query": {
"dis_max": {
"queries": [
{
"match": {
"titulo": {
"query": "java beginner",
"minimum_should_match": "50%",
"boost": 2
}
}
},
{
"match": {
"conteudo": {
"query": "java beginner",
"minimum_should_match": "30%"
}
}
}
],
"tie_breaker": 0.3
}
}
}
best_fields versus most_fields
As duas estratégias resolvem problemas diferentes.
best_fields seleciona o campo com maior score e, com tie_breaker, considera levemente os demais. É ideal quando queremos que um campo concentre a maior parte dos termos. A vantagem é a precisão dos primeiros resultados; a desvantagem é que o restante do ranking pode ficar pouco diferenciado, como acontece em mecanismos de busca gerais.
most_fields, por outro lado, premia documentos em que muitos campos casam com pelo menos um termo. A vantagem é um ranking mais uniforme, mas a desvantagem é que resultados altamente precisos podem não ficar no topo, situação comum em wikis, onde precisamos navegar por várias páginas para encontrar o melhor resultado.