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

Uma introdução aos índices para MongoDB Atlas Search

Nic Raboy7 min read • Published Jan 17, 2022 • Updated Feb 03, 2023
Atlas
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Imagine ler um livro longo como "As Crônicas de Gelo e Fogo", "O Senhor dos Anéis" ou "Harry Potter". Agora imagine que havia um detalhe específico em um desses livros que você precisava reler. Não seria uma boa opção pesquisar todas as páginas desses livros longos para encontrar o que estava procurando. Em vez disso, você gostaria de usar algum tipo de índice de livros para ajudar a localizar rapidamente o que estava procurando. Esse mesmo conceito de indexação de conteúdo em um livro pode ser carregado para o MongoDB Atlas Search com índices de pesquisa.
O Atlas Search facilita a criação de uma busca rápida, relevante e de texto completo sobre seus dados na nuvem. Ele é totalmente integrado, gerenciado e disponível em todos os clusters do MongoDB Atlas que executam a versão 4.2 ou superior do MongoDB.
Definir corretamente seus índices é importante porque eles são responsáveis por garantir que você receba resultados relevantes ao usar o Atlas Search. Não existe uma solução única para todos os casos e diferentes índices trazem benefícios diferentes.
Neste tutorial, veremos uma leve introdução à criação de índices que serão valiosos para vários casos de uso de pesquisa de texto completo.
Antes de investirmos muito nesta introdução, é importante observar que o Atlas Search usa Apache Lucene. Isso significa que os índices de pesquisa não são exclusivos do Atlas Search e se você já estiver familiarizado com o Apache Lucene, seu conhecimento existente sobre indexação será transferido. No entanto, o tutorial pode funcionar como uma atualização sólida de qualquer maneira.

Noções básicas sobre o modelo de dados para os documentos no exemplo

Antes de começarmos a criar índices, provavelmente devemos definir qual será nosso modelo de dados para o exemplo. Em um esforço para cobrir vários cenários de indexação, o modelo de dados será complexo.
Veja o exemplo a seguir:
1{
2 "_id": "cea29beb0b6f7b9187666cbed2f070b3",
3 "name": "Pikachu",
4 "pokedex_entry": {
5 "red": "When several of these Pokemon gather, their electricity could build and cause lightning storms.",
6 "yellow": "It keeps its tail raised to monitor its surroundings. If you yank its tail, it will try to bite you."
7 },
8 "moves": [
9 {
10 "name": "Thunder Shock",
11 "description": "A move that may cause paralysis."
12 },
13 {
14 "name": "Thunder Wave",
15 "description": "An electrical attack that may paralyze the foe."
16 }
17 ],
18 "location": {
19 "type": "Point",
20 "coordinates": [-127, 37]
21 }
22}
O exemplo de documento acima é sobre Pokemon, mas o Atlas Search pode ser usado em qualquer documento que faça parte do seu aplicativo.
Documentos de exemplo como o acima nos permitem usar pesquisa de texto, pesquisa geográfica e potencialmente outras. Para cada um desses diferentes cenários de pesquisa, o índice pode mudar.
Quando criamos um índice para o Atlas Search, ele é criado no nível da coleção.

Mapeando campos estaticamente em um documento ou mapeando dinamicamente campos à medida que o esquema evolui

Há duas maneiras de mapear campos em um documento ao criar um índice:
  • Mapeamentos dinâmicos
  • Mapeamentos estáticos
Se o esquema do documento ainda estiver mudando ou o caso de uso não permitir que ele seja rigidamente definido, convém optar por mapear dinamicamente os campos do documento. Um mapeamento dinâmico atribuirá campos automaticamente quando novos dados forem inseridos.
Veja o exemplo a seguir:
1{
2 "mappings": {
3 "dynamic": true
4 }
5}
O JSON acima representa um índice válido. Quando você o adiciona a uma coleção, está mapeando essencialmente todos os campos existentes nos documentos e qualquer campo que possa existir no futuro.
Podemos fazer uma pesquisa simples usando este índice, como da seguinte forma:
1db.pokemon.aggregate([
2 {
3 "$search": {
4 "text": {
5 "query": "thunder",
6 "path": ["moves.name"]
7 }
8 }
9 }
10]);
Não definimos explicitamente os campos para esse índice, mas a tentativa de pesquisar "thunder" dentro da array moves nos dará resultados correspondentes com base em nossos dados de exemplo.
Para ser claro, mapeamentos dinâmicos podem ser aplicados no nível do documento ou do campo. No nível do documento, um mapeamento dinâmico indexa automaticamente todos os tipos de dados comuns. Em ambos os níveis, ele indexa automaticamente todos os dados novos e existentes.
Embora seja conveniente, ter um índice de mapeamento dinâmico em todos os campos de um documento tem um custo. Esses índices ocuparão mais espaço em disco e podem ter menor desempenho.
A alternativa é usar um mapeamento estático; nesse caso, você especifica os campos a serem mapeados e que tipo de campos são. Veja o exemplo a seguir:
1{
2 "mappings": {
3 "dynamic": false,
4 "fields": {
5 "name": {
6 "type": "string"
7 }
8 }
9 }
10}
No exemplo acima, o único campo do nosso documento que está sendo indexado é o camponame.
A seguinte query de pesquisa retornaria resultados:
1db.pokemon.aggregate([
2 {
3 "$search": {
4 "text": {
5 "query": "pikachu",
6 "path": ["name"]
7 }
8 }
9 }
10]);
Se tentarmos pesquisar em qualquer outro campo em nosso documento, não obteremos resultados porque esses campos não estão mapeados estaticamente nem o esquema do documento está mapeado dinamicamente.
No entanto, existe uma maneira de obter o melhor dos dois mundos, se precisarmos.
Considere o seguinte que usa mapeamentos estáticos e dinâmicos:
1{
2 "mappings": {
3 "dynamic": false,
4 "fields": {
5 "name": {
6 "type": "string"
7 },
8 "pokedex_entry": {
9 "type": "document",
10 "dynamic": true
11 }
12 }
13 }
14}
No exemplo acima, ainda estamos usando um mapeamento estático para o campo name. No entanto, estamos usando um mapeamento dinâmico no campopokedex_entry. O campo pokedex_entry é um objeto, portanto, qualquer campo dentro desse objeto receberá o tratamento de mapeamento dinâmico. Isso significa que todos os subcampos são mapeados automaticamente, bem como quaisquer novos campos que possam existir no futuro. Isso pode ser útil se você quiser especificar os campos de nível superior a serem mapeados, mas também mapear todos os campos de um determinado objeto.
Tome a seguinte query de pesquisa como exemplo:
1db.pokemon.aggregate([
2 {
3 "$search": {
4 "text": {
5 "query": "pokemon",
6 "path": ["name", "pokedex_entry.red"]
7 }
8 }
9 }
10]);
A pesquisa acima retornará resultados se "pokemon" aparecer no campo name ou no campo red dentro do objeto pokedex_entry.
Ao usar um mapeamento estático, você precisa especificar um tipo para o campo ou ter dynamic definido como verdadeiro no campo. Se você especificar apenas um tipo, dynamic terá como padrão falso. Se você especificar apenas dynamic como verdadeiro, o Atlas Search poderá definir automaticamente como padrão determinados tipos de campo (por exemplo, string, data, número).

O Atlas Search indexa campos complexos dentro de um documento.

Com a discussão de mapeamento dinâmico versus estático resolvida para os índices do MongoDB Atlas Search, agora podemos nos concentrar em cenários mais complicados ou específicos.
Vejamos primeiro como seria o índice totalmente mapeado para o documento do nosso exemplo:
1{
2 "mappings": {
3 "dynamic": false,
4 "fields": {
5 "name": {
6 "type": "string"
7 },
8 "moves": {
9 "type": "document",
10 "fields": {
11 "name": {
12 "type": "string"
13 },
14 "description": {
15 "type": "string"
16 }
17 }
18 },
19 "pokedex_entry": {
20 "type": "document",
21 "fields": {
22 "red": {
23 "type": "string"
24 },
25 "yellow": {
26 "type": "string"
27 }
28 }
29 },
30 "location": {
31 "type": "geo"
32 }
33 }
34 }
35}
No exemplo acima, estamos usando um mapeamento estático para cada campo de nossos documentos. Uma coisa interessante a se notar é o array moves e o objetopokedex_entry no documento de exemplo. Mesmo que um seja um array e o outro um objeto, o índice é um document para ambos. Embora escrever pesquisas não seja o foco deste tutorial, pesquisar um array e um objeto seria semelhante usando a notação de ponto.
Se algum dos campos estivesse aninhado mais profundamente no documento, a mesma abordagem seria aplicada. Por exemplo, poderíamos ter algo assim:
1{
2 "mappings": {
3 "dynamic": false,
4 "fields": {
5 "pokedex_entry": {
6 "type": "document",
7 "fields": {
8 "gameboy": {
9 "type": "document",
10 "fields": {
11 "red": {
12 "type": "string"
13 },
14 "yellow": {
15 "type": "string"
16 }
17 }
18 }
19 }
20 }
21 }
22 }
23}
No exemplo acima, o campo pokedex_entry foi ligeiramente alterado para ter outro nível de objetos. Provavelmente não é uma maneira realista de modelar os dados para esse conjunto de dados, mas deve servir para mostrar o ponto sobre o mapeamento de campos aninhados mais profundos.

Alterando as opções para campos mapeados específicos

Até agora, cada um dos índices tinha apenas seus tipos definidos no mapeamento. As opções padrão estão sendo aplicadas a todos os campos. As opções são uma maneira de refinar ainda mais o índice com base em seus dados para, em última análise, obter resultados de pesquisa mais relevantes. Vamos experimentar algumas das opções dentro dos mapeamentos do nosso índice.
A maioria dos campos em nosso exemplo usa o tipo de dados de string, então há muito mais que podemos fazer usando opções. Vamos ver quais são algumas delas.
1{
2 "mappings": {
3 "dynamic": false,
4 "fields": {
5 "name": {
6 "type": "string",
7 "searchAnalyzer": "lucene.spanish",
8 "ignoreAbove": 3000
9 }
10 }
11 }
12}
No exemplo acima, estamos especificando que queremos usar um analisador de linguagem no campo name em vez do analisador padrão. Também estamos dizendo que o campo name não deve ser indexado se o valor do campo for maior que 3000 caracteres.
Os 3000 caracteres são apenas um número aleatório neste exemplo, mas adicionar um limite, dependendo do seu caso de uso, pode melhorar o desempenho ou o tamanho do índice.
Em um próximo tutorial, vamos explorar em detalhes o que são os analisadores de pesquisa e o que podem fazer.
Essas são apenas algumas das opções disponíveis para o tipo de dados de string. Cada tipo de dados terá seu próprio conjunto de opções. Se você quiser usar o padrão para qualquer opção específica, ela não precisará ser explicitamente adicionada ao campo mapeado.
Você pode aprender mais sobre os tipos de dados e suas opções de indexação na documentação oficial.

Conclusão

Você acabou de receber o que, espero, tenha sido uma introdução suave à criação de índices a serem usados no Atlas Search. Para usar o Atlas Search, você precisará de pelo menos um índice em sua coleção, mesmo que seja um índice dinâmico padrão. No entanto, se você conhece seu esquema e consegue criar mapeamentos estáticos, geralmente é a melhor maneira de ajustar a relevância e o desempenho.
Para saber mais sobre os índices do Atlas Search e os vários tipos de dados, opções e analisadores disponíveis, consulte a documentação oficial.
Tem alguma dúvida ou feedback sobre este tutorial? Acesse os Fóruns da MongoDB Community e vamos conversar!

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

Crie um mecanismo de pesquisa de imagens com Python e MongoDB


Sep 18, 2024 | 8 min read
Tutorial

Como escrever testes de unidade para MongoDB Atlas Functions


Sep 09, 2024 | 10 min read
Tutorial

Criação de um agente de AI aprimorado para memória com o laudo do Aconnection no Amazon Cama do MongoDB Atlas


Oct 29, 2024 | 8 min read
Tutorial

Pesquisa semântica com Jina Embeddings v2 e MongoDB Atlas


Dec 05, 2023 | 12 min read
Sumário