Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Junte-se a nós no Amazon Web Services re:Invent 2024! Saiba como usar o MongoDB para casos de uso de AI .
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
Atlaschevron-right

A relevância do Atlas Search explicada

Erik Hatcher13 min read • Published Aug 14, 2024 • Updated Aug 14, 2024
AtlasPesquisa
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Artigo
star-empty
star-empty
star-empty
star-empty
star-empty
Atlas Search impulsiona todas as nossas vidas digitais: pesquisar isso e aquilo no Google; perguntar à Siri onde encontrar um jantar saboroso nas proximidades; fazer compras na Amazon; e assim por diante. Recebemos resultados relevantes, muitas vezes, mesmo apesar de nossos erros de digitação, erros de transcrição de voz ou consultas mal formadas. Nós nos acostumamos a esperar os melhores resultados para nossas intenções de busca, ali mesmo, no topo.
Mas agora é sua vez, caro desenvolvedor, de criar a mesma experiência de usuário satisfatória em seu aplicativo com tecnologia Atlas.
Se você ainda não criou um índice do Atlas Search, seria útil fazê-lo antes de analisar o restante deste artigo. Temos um tutorial útil para começar a usar o Atlas Search. Iremos aguardar com todo o afinco que você comece e retornar aqui quando tiver alguns resultados de pesquisa.
Bem-vindo de volta! Observamos que você tem dados e eles estão no MongoDB Atlas. Você ativou o Atlas Search e executou algumas queries, e agora deseja entender por que os resultados estão na ordem em que aparecem e obter algumas dicas sobre como ajustar a ordem de classificação de relevância.

Enigma de relevância

No artigo Usando Atlas Search do Java, deixamos o leitor com um pouco de segredo de relevância de pesquisa, usando uma query do campo de conversão para a frase "keanu reeves " (em letra minúscula; um $match falha mesmo essa query inexata) restringindo os resultados a filmes que são ao mesmo tempo dramativos (genres:Drama) E alternativos (genres:Romance). Usaremos a mesma query aqui. Os resultados desta query correspondem a vários documentos, mas com pontuações diferentes. O único fator de pontuação é uma cláusulamust do phrase “keanu reeves”. Por que "Sweet November " e "A Walk in the Clouds " não pontuam de forma idêntica?
Enigma de relevância
Você consegue ver a diferença? Continue lendo enquanto fornecemos a você as ferramentas e dicas para descobrir e resolver esses tipos de desafios apresentados pelos resultados do Atlas Search de texto completo, inexato/fuzzy/close-mas-not-exact.

Detalhes da pontuação

Atlas Search possibilita a criação de aplicativos de pesquisa de texto completo e, com alguns cliques, aceitando as configurações padrão, você tem recursos incrivelmente poderosos ao seu alcance. Você tem um sistema de piloto automático muito bom, mas está no cockpit de um 747 com botões e mostradores ao redor. O avião decolará e pousará com segurança sozinho - na maioria das vezes. Dependendo das condições e objetivos, subir manualmente até 11.0 no botão de volume, e talvez um pouco mais na alavanca de empuxo, é necessário para voar até lá com estilo. O ajuste de relevância também pode ser descrito assim e, antes de assumir o controle dos parâmetros, você precisa entender o que as configurações fazem e o que é possível com os ajustes.
Os detalhes de pontuação de cada documento para uma determinada consulta podem ser solicitados e retornados. Há duas etapas necessárias para obter os detalhes da pontuação: primeiro solicitá-los na solicitação$searche, em seguida, projetar os metadados dos detalhes da pontuação em cada documento retornado. Solicitar detalhes de pontuação é um impacto no desempenho do mecanismo de pesquisa subjacente, portanto, faça isso apenas para fins de diagnóstico ou aprendizado. Para solicitar detalhes de pontuação da solicitação de pesquisa, defina scoreDetails como true. Esses detalhes da pontuação estão disponíveis nos resultados $metadados de cada documento.
Veja o que é necessário para obter os detalhes da pontuação:
1[{
2 "$search": {
3 ...
4 "scoreDetails": true
5 }
6},
7{
8 "$project": {
9 ...
10 "scoreDetails": {"$meta": "searchScoreDetails"}
11 }
12}]
Vamos pesquisar a coleção de filmes criada no tutorial em busca de filmes dramáticos e românticos estrelados por "keanu reeves" (tl; dr: adicione coleções de amostra, crie um índice de pesquisa default na coleção de filmes com dynamic=”true”), trazendo a pontuação e os detalhes da pontuação:
1[
2 {
3 "$search": {
4 "compound": {
5 "filter": [
6 {
7 "compound": {
8 "must": [
9 {
10 "text": {
11 "query": "Drama",
12 "path": "genres"
13 }
14 },
15 {
16 "text": {
17 "query": "Romance",
18 "path": "genres"
19 }
20 }
21 ]
22 }
23 }
24 ],
25 "must": [
26 {
27 "phrase": {
28 "query": "keanu reeves",
29 "path": "cast"
30 }
31 }
32 ]
33 },
34 "scoreDetails": true
35 }
36 },
37 {
38 "$project": {
39 "_id": 0,
40 "title": 1,
41 "cast": 1,
42 "genres": 1,
43 "score": {
44 "$meta": "searchScore"
45 },
46 "scoreDetails": {
47 "$meta": "searchScoreDetails"
48 }
49 }
50 },
51 {
52 "$limit": 10
53 }
54 ]
Aviso de conteúdo! A seguinte saída não é para os sensíveis. No entanto, é a razão pela qual estamos aqui, então, por favor, persista enquanto esses detalhes são explicados abaixo. O valor do scoreDetailsprojetado terá a seguinte aparência para o primeiro resultado:
1"scoreDetails": {
2 "value": 6.011996746063232,
3 "description": "sum of:",
4 "details": [
5 {
6 "value": 0,
7 "description": "match on required clause, product of:",
8 "details": [
9 {
10 "value": 0,
11 "description": "# clause",
12 "details": []
13 },
14 {
15 "value": 1,
16 "description": "+ScoreDetailsWrapped ($type:string/genres:drama) +ScoreDetailsWrapped ($type:string/genres:romance)",
17 "details": []
18 }
19 ]
20 },
21 {
22 "value": 6.011996746063232,
23 "description": "$type:string/cast:\"keanu reeves\" [BM25Similarity], result of:",
24 "details": [
25 {
26 "value": 6.011996746063232,
27 "description": "score(freq=1.0), computed as boost * idf * tf from:",
28 "details": [
29 {
30 "value": 13.083234786987305,
31 "description": "idf, sum of:",
32 "details": [
33 {
34 "value": 6.735175132751465,
35 "description": "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
36 "details": [
37 {
38 "value": 27,
39 "description": "n, number of documents containing term",
40 "details": []
41 },
42 {
43 "value": 23140,
44 "description": "N, total number of documents with field",
45 "details": []
46 }
47 ]
48 },
49 {
50 "value": 6.348059177398682,
51 "description": "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
52 "details": [
53 {
54 "value": 40,
55 "description": "n, number of documents containing term",
56 "details": []
57 },
58 {
59 "value": 23140,
60 "description": "N, total number of documents with field",
61 "details": []
62 }
63 ]
64 }
65 ]
66 },
67 {
68 "value": 0.4595191478729248,
69 "description": "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
70 "details": [
71 {
72 "value": 1,
73 "description": "phraseFreq=1.0",
74 "details": []
75 },
76 {
77 "value": 1.2000000476837158,
78 "description": "k1, term saturation parameter",
79 "details": []
80 },
81 {
82 "value": 0.75,
83 "description": "b, length normalization parameter",
84 "details": []
85 },
86 {
87 "value": 8,
88 "description": "dl, length of field",
89 "details": []
90 },
91 {
92 "value": 8.217415809631348,
93 "description": "avgdl, average length of field",
94 "details": []
95 }
96 ]
97 }
98 ]
99 }
100 ]
101 }
102 ]
103}
Escreveremos um pequeno código, abaixo, que apresenta essa estrutura aninhada em um formato mais conciso e legível, e detalharemos os detalhes lá. Antes de analisarmos a pontuação, precisamos entender de onde vêm esses vários fatores. Eles vêm de Lucene.

Lucene por dentro

O Apache Lucene alimenta uma grande porcentagem das experiências de busca do mundo, da maioria dos sites de e-commerce a sistemas de saúde e seguros, intranets, inteligência ultrassecreta e muito mais. E não é nenhum segredo que o Apache Lucene alimenta o Atlas Search. O Lucene comprovou ser robusto e escalável, e é implantado de forma difusa. Muitos de nós consideraria o Lucene o projeto de código aberto mais importante de todos os tempos, onde uma comunidade diversificada de especialistas em pesquisa de todo o mundo e de vários setores colaborará de forma construtiva para melhorar e renovar continuamente esse projeto potente.
Então, o que é essa coisa surpreendente chamada Lucene? Lucene é uma biblioteca de mecanismos de busca open source escrita em Java que indexa conteúdo e lida com queries sofisticadas, retornando rapidamente resultados relevantes. Além disso, o Lucene oferece facet, realce, pesquisa vetorial e muito mais.

Indexação do Lucene

Não podemos discutir a relevância da pesquisa sem abordar o lado da indexação da equação, pois eles estão inter-relacionados. Quando os documentos são adicionados a uma coleção do Atlas com um Atlas Search ativado, os campos dos documentos são indexados no Lucene de acordo com os mapeamentos de índice configurados.
Quando os campos textuais são indexados, uma estrutura de dados conhecida como índice invertido é construída por meio de um processo chamado análise. O índice invertido, assim como um dicionário físico, é uma lista de termos/palavras ordenada lexicograficamente/alfabeticamente, com referência cruzada aos documentos que os contêm. O processo de análise é alimentado inicialmente com todo o valor do texto do campo durante a indexação e, de acordo com o analisador definido no mapeamento, o divide em termos/palavras individuais.
Por exemplo, a frase tola "The quick brown fox jumps over the lazy dog " é analisada pelo analisador padrão do Atlas Search (lucene.standard) nos seguintes termos: o,quick,brown,fox,jumps,over,the,lazy,dog. Agora, se colocarmos em ordem alfabética (e deduplicarmos, observando a frequência) esses termos, fica assim:
termoFrequência
marrom1
cachorro1
rasteja1
saltos1
preguiçoso1
terminado1
rápido1
O2
Além de quais documentos contêm um termo, as posições de cada instância desse termo são registradas na estrutura do índice invertido. O registro de posições de termo permite queries de frase (como nosso exemplo "keanu reeves "), em que os termos da query devem ser adjacentes uns aos outros no campo indexado.
Suponha que temos uma coleção de Sentenças Tolas onde esse foi o nosso primeiro documento ( ID documento 1) e adicionamos outro documento (ID 2) com o texto "My dogs play with the red fox". Nosso índice invertido, mostrando IDs de documentos e posições de termo. torna-se:
termodocument idsFrequência de termoPosições de termo
marrom11Documento 1: 3
cachorro11Documento 1: 9
cães21Documento 2: 2
rasteja1,22Document 1: 4; Document 2: 7
saltos11Documento 1: 5
preguiçoso11Documento 1: 8
meu21Documento 2: 1
terminado11Documento 1: 6
jogar21Documento 2: 3
rápido11Documento 1: 2
vermelho21Documento 2: 6
O1,23Document 1: 1, 7; Document 2: 5
com21Documento 2: 4
Com essa estrutura de dados, a Lucene pode navegar rapidamente até um termo consultado e retornar os documentos que o contêm.
Existem algumas características notáveis neste exemplo de índice invertido. As palavras "dog" e "dogs" são termos separados. Os termos emitidos do processo de análise, que são indexados exatamente como são emitidos, são as unidades atômicas pesquisáveis, em que "dog" não é o mesmo que "dogs". Seu aplicativo precisa encontrar ambos os documentos para uma Atlas Search de qualquer um desses termos? Ou deve ser mais exato? Observe também que, de dois documentos, "the" apareceu três vezes - mais vezes do que documentos. Talvez palavras como “the” sejam tão comuns em seus dados que um Atlas Search para esse termo não seja útil. Suas opções de analisador determinam o que entra no índice invertido e, portanto, o que é pesquisável ou não. O Atlas Search oferece uma variedade de opções de analisadores, sendo a escolha certa a que funciona melhor para seu domínio e dados.
Há uma série de estatísticas sobre uma collection de documentos que surgem por meio dos processos de análise e indexação, incluindo:
  • Frequência do termo: quantas vezes um termo apareceu no campo do documento?
  • Frequência do documento: Em quantos documentos esse termo aparece?
  • Comprimento do campo: Quantos termos estão neste campo?
  • Posições de termo: em qual posição, nos termos emitidos, cada instância aparece?
Essas estatísticas estão ocultas nas profundezas da estrutura do índice Lucene e aparecem visivelmente na saída de detalhes da pontuação que vimos acima e que aprofundaremos a seguir.

Pontuação Lucene

As estatísticas capturadas durante o fator de indexação em como os documentos são pontuados no momento da consulta. A pontuação Lucene, em seu núcleo, é baseada em TF/IDF - frequência de termo/frequência de documento inversa. De um modo geral, o TF/IDF classifica documentos com frequências de termos mais altos maiores do que os com frequências de termos mais baixos e pontua documentos com frequências de termos mais comuns abaixo dos termos mais raros — a ideia é que um termo raro na coleção transmite mais informações do que um termo frequentemente ocorrendo e que o peso de um termo é proporcional à sua frequência.
Há um pouco mais de matemática nos backstage da implementação de TF/IDF do Lucene, para abafa o efeito (por exemplo, tirar a raiz quadrada) de TF e escalar IDF (usando uma função de logaritmo).
A fórmula clássica TF/IDF funciona bem em geral, quando os campos do documento geralmente têm o mesmo tamanho e não há coisas obsoletas ou bizarras ocorrendo com os dados em que a mesma palavra é repetida várias vezes — o que acontece nas descrições de produtos , comentários de postagens de blogs, avaliações de restaurantes e onde impulsionar um documento para o topo dos resultados tem algum apoio. Como nem todos os documentos são criados da mesma forma (alguns títulos são longos, outros são curtos e alguns têm descrições que repetem muitas palavras ou são muito sucintas), é necessário um ajuste fino para levar em conta essas situações.

Melhores partidas

À medida que os mecanismos de pesquisa evoluíram, foram feitos refinamentos no cálculo clássico de relevância do TF/IDF para levar em conta a saturação de termos (um número excessivamente grande do mesmo termo em um campo) e reduzir a contribuição de longos valores de campo que contêm muito mais termos do que campos mais curtos, fatorando na proporção do comprimento do campo do documento para o comprimento médio do campo da collection. O agora popular métodoBM25 se tornou a fórmula de pontuação padrão no Lucene e é a fórmula de pontuação usada pelo Atlas Search. BM25 significa "Best Match 25 " (a 25ª iteração deste algoritmo de pontuação). Um ótimo artigo comparando o TF/IDF clássico ao BM25, incluindo gráficos ilustrativos, pode ser encontrado em Conexões OpenSource.
Existem valores embutidos para os fatores adicionais do BM25 , k1 e b. O fatork1 afeta o quanto a pontuação aumenta com cada recorrência do termo e b controla o efeito do comprimento do campo. Ambos os fatores estão atualmente definidos internamente para os padrões do Lucene e não são configurações que um desenvolvedor possa ajustar no momento, mas tudo bem, pois os valores incorporados foram ajustados para fornecer grande relevância como estão.

Quebrando os detalhes da pontuação

Vejamos os mesmos detalhes da pontuação de uma forma mais resumida e fácil de ler:
detalhes de pontuação, bem impressos
É mais fácil ver nesse formato que a pontuação de aproximadamente 6.011 vem da soma de dois números: 0.0 (os filtros rotulados# clausesem pontuação ) e aproximadamente 6.011. E esse fator ~6.011 vem da fórmula de pontuação BM25 que multiplica o fator "idf" (frequência inversa do documento) de ~13.083 com o fator "tf" (frequência do termo) de ~0.459. O fator "idf" é o "sum of" de dois componentes, um para cada um dos termos em nossa cláusula do operador phrase. Cada um dos fatoresidf para nossos dois termos de consulta, "keanu" e "reeves", é calculado usando a fórmula na saída, que é:
1log(1 + (N - n + 0.5) / (n + 0.5))
O fator "tf " para a frase completa é "computed as " esta fórmula:
1freq / (freq + k1 * (1 - b + b * dl / avgdl))
Isso usa os fatores recuados abaixo, como o tamanho médio (em número de termos) do campo “cast” em todos os documentos da collection.
Na frente de cada nome de campo nesta saída ("genres " e "cast "") há um prefixo usado internamente para observar o tipo de campo (o prefixo "$type/ ").

Formatação em pretty-print dos detalhes da pontuação

A saída mais amigável para humanos dos detalhes de pontuação acima foi gerada usando o MongoDB VS Code Playgrounds. Este código JavaScript imprimirá uma versão mais concisa e com recuo do scoreDetails, chamando: print_score_details(doc.scoreDetails);:
1function print_score_details(details, indent_level) {
2 if (!indent_level) { indent_level = 0; }
3 spaces = " ".padStart(indent_level);
4 console.log(spaces + details.value + ", " + details.description);
5 details.details.forEach (d => {
6 print_score_details(d, indent_level + 2);
7 });
8}
Da mesma forma, a impressão bonita em Java pode ser feita como o código desenvolvido no artigo Usando Atlas Search do Java,disponível no GitHub.

Mistério resolvido!

Voltando ao nosso enigma de relevância, vamos ver os detalhes da pontuação:
diferenças de pontuação relevantes
Usando as informações detalhadas fornecidas sobre as estatísticas capturadas no índice invertido Lucene, verifica-se que os camposcast desses dois documentos têm uma diferença interessante. Ambos têm quatro membros do elenco, mas lembre-se do processo de análise que extrai termos pesquisáveis do texto. Na pontuação inferior dos dois documentos, um dos membros do elenco tem um sobrenome hifenizado: Aitana Sencez-Gijén. O caractere traço/hífen é um caractere separador de termos para o analisador lucene.standard , criando um termo adicional para esse documento que, por sua vez, aumenta o comprimento (em número de termos) do campocast. Um comprimento de campo maior faz com que as correspondências de termos pesem menos do que se estivessem em um campo de comprimento mais curto.

Composto é rei

Mesmo neste exemplo de consulta de frase simples, a pontuação é composta por muitos fatores que são os "sum of ", "product of ", "result of " ou "from " outros fatores e fórmulas. O ajuste de relevância envolve a criação de cláusulas aninhadas em um operador compoundusandoshould e must. Observe novamente que as cláusulasfilter não contribuem para a pontuação, mas são valiosas para restringir os documentos considerados para pontuação pelas cláusulasshould e must. E, é claro, as cláusulasmustNot não contribuem para a pontuação, pois os documentos correspondentes a essas cláusulas são omitidos dos resultados.
Use vários compound.should e compound.must para ponderar correspondências em campos diferentes de maneiras diferentes. É uma prática comum, por exemplo, ponderar as correspondências em um campotitle maior que as correspondências em um campo description (ou campoplot na collection de filmes), usando reforços em diferentes cláusulas do operador de consulta.

Cláusulas de reforço

Com uma consulta composta por diversas cláusulas, você tem controle sobre a modificação da pontuação de diversas maneiras usando a configuração opcional score disponível em todos os operadores de pesquisa. Os fatores de pontuação para uma cláusula podem ser controlados destas quatro maneiras:
  • constant: o fator de pontuação da cláusula é definido como um valor explícito.
  • boost: multiplique o fator de pontuação normal calculado para a cláusula por um valor especificado ou pelo valor de um campo no documento que está sendo pontuado.
  • functionCalcule o fator de pontuação usando a expressão de fórmula especificada.
  • embedded: trabalhe com o operador de pesquisaembeddedDocument para controlar como os documentos incorporados correspondentes contribuem para a pontuação do documento pai de nível superior.
Isso é um controle com muitas nuances! Esses são controles importantes para ter quando você estiver a fim de ajustar as classificações dos resultados de busca.

Ajuste de relevância: um equilíbrio delicada

Com as ferramentas e mecanismos ilustradas aqui, você obtém os fundamentos dos insights de pontuação do Atlas Search. Quando apresentado aos inevitáveis desafios de classificação de resultados, você poderá avaliar a situação e entender por que e como as pontuações são calculadas como são. Ajustar esses resultados é complicado. Mover os resultados de uma query para a ordem desejada é bastante simples, mas essa é apenas uma query.
O ajuste dos fatores de aumento, a utilização de cláusulas compostas com mais nuances e o ajuste da análise afetarão outros resultados da consulta. Para garantir que seus usuários obtenham resultados relevantes:
  • Teste, teste e teste novamente, em muitas queries — especialmente as queries do mundo real extraídas de seus registros, não apenas as queries de seus filhos.
  • Teste com uma coleção completa de dados (tão representativa ou tão real quanto possível), não apenas um subconjunto de dados para fins de desenvolvimento.
  • Lembre-se de que as estatísticas do índice são importantes para as pontuações, como o comprimento médio em número de termos de cada campo. Se você testar com dados de qualidade e escala que não sejam de produção, as medidas de relevância não corresponderão às estatísticas de um ambiente de produção.
As preocupações de relevância variam drasticamente de acordo com o domínio, a escala, a sensibilidade e o valor monetário da ordenação dos resultados de pesquisa. Garantir que os documentos "best " (por quaisquer métricas que sejam importantes para você) apareçam nas principais posições apresentados é uma arte e uma ciência. Os grandes nomes do e-commerce testam constantemente query results, executando testes de regressão e experimentos A/B nos backs, manipulando todos os parâmetros disponíveis. No entanto, para a pesquisa de sites, definir um impulso para title pode ser tudo o que você precisa.
Você tem as ferramentas, e é apenas matemática, mas seja criterioso ao ajustar as coisas e faça isso com dados reais completos, consultas reais e algum tempo e paciência para configurar testes e experimentos.
A compreensão e o ajuste da relevância são um processo e uma discussão contínuos. Perguntas? comentários? Vamos continuar a conversa em nosso fórum da comunidade do Atlas Search.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Artigo
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Como construir um gráfico animado da linha do tempo com MongoDB Charts Embedding SDK


Dec 13, 2023 | 6 min read
Artigo

Automatize a automação no MongoDB Atlas


Sep 11, 2024 | 4 min read
Artigo

Descubra a estrutura semântica latente com o cluster vetorial


Oct 11, 2024 | 10 min read
exemplo de código

EHRS-Peru


Sep 11, 2024 | 3 min read
Sumário