Descubra seu Airbnb ideal: implementando um Spring Boot e Atlas Search com o driver Kotlin Sync
Avalie esse Tutorial
Uma das minhas atividades favoritas é viajar e explorar o mundo. Você conhece essa impressão de descobrir um novo lugar e pensar: "Como não estava aqui antes?" É com essa impressão que sempre me motivo a procurar novos lugares para descobrir. Muitas vezes, ao procurar um lugar para ficar, não temos certeza do que procuramos ou quais experiências queremos ter. Por exemplo, podemos querer alugar um quarto em uma cidade com vista para um reino. Encontrar algo assim pode parecer difícil, não é mesmo? No entanto, há uma maneira de o Atlas Search obter informações com precisão usando o Atlas Search.
Neste tutorial, aprenderemos a criar um aplicativo em Kotlin que utiliza o Atlas Search de texto completo em um banco de dados contendo milhares de anúncios do Airbnb. Veremos como podemos encontrar a hospedagem perfeita que atenda às nossas necessidades específicas.
Aqui está uma versão em vídeo deste artigo, se você preferir assistir.
Para atingir nosso objetivo, criaremos um aplicativoKotlin Spring Boot que se comunica com o MongoDB Atlas usando o driver Kotlin Sync.
O aplicativo usará um banco de dados pré-importado no Atlas chamado
sample_airbnb
, utilizando a collectionlistingsAndReviews
, que contém informações sobre vários Airbnbs.Para identificar os melhores anúncios do Airbnb, criaremos um endpoint que retornará informações sobre esses anúncios. Esse endpoint usará o campo
summary
da collection para executar uma Atlas Search de texto completo com o parâmetro fuzzy no operador de texto. Além disso, filtraremos os documentos com base em um número mínimo de revisões, utilizando as funcionalidades do Atlas Search fornecidas pelo Atlas Search.- Comece a usar o MongoDB Atlas gratuitamente! Se você ainda não tiver uma conta, o MongoDB oferece um cluster Atlas gratuito para sempre.
- IDE de sua escolha
Atlas Search é um recurso no MongoDB Atlas que fornece recursos poderosos e flexíveis do Atlas Search para seus dados. Ele se integra ao Apache Lucene, permitindo análise avançada de texto, pontuação personalizada e realce de resultados. Isso permite que você crie a funcionalidade sofisticada do Atlas Search diretamente nos seus aplicativos MongoDB .
Para utilizar o Atlas Search de forma eficaz, vamos nos concentrar em três operadores principais:
text
, range
e compound
. Embora haja vários operadores disponíveis, nossa análise se concentrará neles para ilustrar suas aplicações práticas.- Texto: esse operador será usado para realizar pesquisas de texto em nosso endpoint, permitindo uma correspondência aproximada e variações de manuseio nos termos do Atlas Search.
- Faixa: exploraremos o operador
range
especificamente com a condiçãogte
(maior ou iguala) para o camponumber_of_reviews
. Isso nos permitirá fazer query e filtrar com base nas contagens de avaliações de forma eficaz. - Composto: O operador
compound
será utilizado para combinar as queriestext fuzzy
erange
em uma Pesquisa Atlas mais complexa e refinada. Isso demonstrará como mesclar múltiplos critérios para uma funcionalidade mais sofisticada do Atlas Search.
Embora este artigo não se aprofunde em todos os operadores disponíveis, os interessados em uma análise mais abrangente podem consultar a documentação do MongoDB Atlas Atlas Search para obter mais detalhes.
Antes de iniciar, você precisará importar o conjunto de dados de exemplo, que inclui vários bancos de dados e coleções, como a lista doAirbnb. Após configurar seu cluster, basta clicar em "Banco de Dados" no menu esquerdo e escolher "Carregar conjunto de dados de amostra", como mostrado na imagem:
Se tudo correr bem, após a importação, você verá nossos databases e collections exibidos conforme a imagem.
Após importar as collections, a próxima etapa é criar um índice para a collection do Airbnb. Para fazer isso, selecione "Banco de dados" no menu lateral em "Deployment," Go para a guia "Atlas Search" e clique em " Editor JSON ," conforme mostrado na imagem:
Na próxima etapa, selecione o banco de dados
sample_airbnb
e a coleçãolistingsAndReviews
(a coleção do Airbnb). Em seguida, nomeie seu índice de "searchPlaces":Observe que estamos usando Mapeamentos dinâmicos por simplificação, o que permite que o Atlas Search indexe automaticamente os campos dos tipos suportados em cada documento. Para obter mais detalhes, sugere-se verificar Definir Mapeamentos de Campo
Se tudo correr bem, oíndice " searchPlaces" será criado com sucesso e você poderá visualizá-lo conforme mostrado na imagem abaixo:
Para testar nosso índice, precisamos criar um aggregation pipeline. Embora existam vários métodos para testar isso, usaremos o MongoDB Compass por conveniência. O MongoDB Compass é uma poderosa ferramenta de GUI que facilita o gerenciamento e a análise de dados do MongoDB. Ele fornece recursos para visualizar esquemas, criar queries e gerenciar dados por meio de uma interface intuitiva.
Precisamos configurar um pipeline de agregação para atender aos seguintes requisitos:
- Filtrar o campo
summary
por texto - Garanta um mínimo
number_of_reviews
Aqui está o pipeline de agregação que usaremos para testes:
1 [ 2 { 3 $search: { 4 index: "searchPlaces", 5 compound: { 6 filter: [ 7 { 8 range: { 9 path: "number_of_reviews", 10 gte: 50 11 } 12 }, 13 { 14 text: { 15 path: "summary", 16 query: "Istambun", 17 fuzzy: { 18 maxEdits: 2 19 } 20 } 21 } 22 ] 23 } 24 } 25 }, 26 { 27 $limit: 5 28 }, 29 { 30 $project: { 31 _id: 0, 32 name: 1, 33 summary: 1, 34 number_of_reviews: 1, 35 price: 1, 36 street: "$address.street", 37 } 38 } 39 ]
Vamos detalhar cada etapa:
- $Atlas Search: o estágio
$search
usa os recursos do MongoDB Atlas Atlas Search para executar uma Atlas Search de texto completo com filtragem adicional.- índice:
"searchPlaces"
especifica o índice do Atlas Search a ser usado. Se o nome do índice fosse "padrão", não precisariamos especificá-lo aqui. - composto: Permite combinar vários critérios do Atlas Search. A query composta aqui é usada para filtrar os resultados do Atlas Search com base em critérios de texto e intervalo.
- filtro: contém uma array de critérios de filtro aplicados aos resultados do Atlas Search.
- faixa: filtra documentos em que o campo
number_of_reviews
é maior ou igual a 50. - texto: o texto executa uma Pesquisa do Atlas de texto completo no campo
summary
com a consulta"Istambun".
A opção difusa com maxEdits: 2 permite a correspondência difusa, o que significa que ele pode corresponder termos semelhantes a "Istambun" com até a duas edições de caracteres (inserções, exclusões ou substituições).
- $limit: Limita o número de documentos retornados pela query para 5. Usar um limite é essencial para manter o desempenho.
- $project: especifica quais campos incluir ou excluir no resultado final.
Basta executar este pipeline para obter os resultados. Veja:
Nosso aplicativo será desenvolvido em Kotlin com o Spring. Éimportante observar que não usaremos dados da Spring. Em vez disso, usaremos o Kotlin Sync Driver, especializado para comunicação entre o aplicativo e o MongoDB. O objetivo do nosso aplicativo é simples:
- Forneça um endpoint que nos permita fazer solicitações e nos comunicar com o MongoDB Atlas.
Como você pode ver, adicionei apenas a dependênciado Spring Web .
A primeira coisa que vamos fazer é abrir o arquivo
build.gradle.kts
e adicionar a dependênciamongodb-driver-kotlin-sync
.1 dependencies { 2 implementation("org.mongodb:mongodb-driver-kotlin-sync:5.1.1") 3 }
Para estabelecer nossa conexão, precisamos seguir estas etapas. Primeiro, atualize o arquivo
application.properties
com os valores exigidos.1 spring.application.name=Airbnb Searcher 2 spring.data.mongodb.uri=mongodb+srv://user:pass@cluster0.cluster.mongodb.net/ 3 spring.data.mongodb.database=sample_airbnb
Aviso: não se lembre de atualizar o URI para corresponder à sua conexão do MongoDB.
Em seguida, criaremos uma classe
MongoConfig
dentro do diretórioapplication.config
para configurar a conexão quando nosso aplicativo iniciar.1 package com.mongodb.searcher.application.config 2 3 import com.mongodb.kotlin.client.MongoClient 4 import com.mongodb.kotlin.client.MongoDatabase 5 import org.springframework.beans.factory.annotation.Value 6 import org.springframework.context.annotation.Bean 7 import org.springframework.context.annotation.Configuration 8 9 10 class MongoConfig { 11 12 13 lateinit var uri: String 14 15 16 lateinit var databaseName: String 17 18 19 fun getMongoClient(): MongoClient { 20 return MongoClient.create(uri) 21 } 22 23 24 fun mongoDatabase(mongoClient: MongoClient): MongoDatabase { 25 return mongoClient.getDatabase(databaseName) 26 } 27 }
Ideal, definimos nossa classe
MongoConfig
, que usará os valores de application.properties
. Agora, crie a classe AirbnbEntity
dentro do pacoteresources
:1 package com.mongodb.searcher.resources 2 3 import com.mongodb.searcher.domain.Airbnb 4 import org.bson.codecs.pojo.annotations.BsonId 5 import org.bson.codecs.pojo.annotations.BsonProperty 6 import org.bson.types.Decimal128 7 8 data class AirbnbEntity( 9 val id: String, 10 val name: String, 11 val summary: String, 12 val price: Decimal128, 13 14 val numbersOfReviews: Int, 15 val address: Address 16 ) { 17 data class Address( 18 val street: String, 19 val country: String, 20 21 val countryCode: String 22 ) 23 24 fun toDomain(): Airbnb { 25 return Airbnb( 26 id = id, 27 name = name, 28 summary = summary, 29 price = price, 30 numbersOfReviews = numbersOfReviews, 31 street = address.street 32 ) 33 } 34 }
Agora, vamos criar nossa classe que utilizará o índice do Atlas Search. Para fazer isso, crie a classe
AirbnbRepository
dentro do pacoteresources
.1 package com.mongodb.searcher.resources 2 3 import com.mongodb.client.model.Aggregates 4 import com.mongodb.client.model.Projections 5 import com.mongodb.client.model.search.FuzzySearchOptions 6 import com.mongodb.client.model.search.SearchOperator 7 import com.mongodb.client.model.search.SearchOptions 8 import com.mongodb.client.model.search.SearchPath 9 import com.mongodb.kotlin.client.MongoDatabase 10 import org.slf4j.LoggerFactory 11 import org.springframework.stereotype.Repository 12 13 14 class AirbnbRepository( 15 private val mongoDatabase: MongoDatabase 16 ) { 17 companion object { 18 private val logger = LoggerFactory.getLogger(AirbnbRepository::class.java) 19 private const val COLLECTION = "listingsAndReviews" 20 } 21 fun find(query: String, minNumberReviews: Int): List<AirbnbEntity> { 22 val collection = mongoDatabase.getCollection<AirbnbEntity>(COLLECTION) 23 24 return try { 25 collection.aggregate( 26 listOf( 27 createSearchStage(query, minNumberReviews), 28 createLimitStage(), 29 createProjectionStage() 30 ) 31 ).toList() 32 } catch (e: Exception) { 33 logger.error("An exception occurred when trying to aggregate the collection: ${e.message}") 34 emptyList() 35 } 36 } 37 38 private fun createSearchStage(query: String, minNumberReviews: Int) = 39 Aggregates.search( 40 SearchOperator.compound().filter( 41 listOf( 42 SearchOperator.numberRange(SearchPath.fieldPath("number_of_reviews")) 43 .gte(minNumberReviews), 44 SearchOperator.text(SearchPath.fieldPath(AirbnbEntity::summary.name), query) 45 .fuzzy(FuzzySearchOptions.fuzzySearchOptions().maxEdits(2)) 46 ) 47 ), 48 SearchOptions.searchOptions().index("searchPlaces") 49 ) 50 private fun createLimitStage() = 51 Aggregates.limit(5) 52 53 54 private fun createProjectionStage() = 55 Aggregates.project( 56 Projections.fields( 57 Projections.include( 58 listOf( 59 AirbnbEntity::name.name, 60 AirbnbEntity::id.name, 61 AirbnbEntity::summary.name, 62 AirbnbEntity::price.name, 63 "number_of_reviews", 64 AirbnbEntity::address.name 65 ) 66 ) 67 ) 68 ) 69 }
Vamos analisar o método find.
Como você pode ver, o método espera uma string de query e um
minNumberReviews
int e retorna uma lista de AirbnbEntity
. Essa lista é gerada por meio de um pipeline de agregação, que consiste em três estágios:- Estágio Atlas Search: Utiliza o operador
$search
para filtrar documentos com base na query e no número mínimo de revisões. - Estágio limite: restringe o resultado definido a um número máximo de documentos.
- Estágio de projeção: Especifica quais campos incluir nos documentos devolvidos (esse estágio é opcional e incluído aqui apenas para ilustrar como usá-lo).
Aviso: dependendo do cenário, adicionar estágios após o estágio
$search
pode afetar drasticamente o desempenho do aplicativo. Para obter mais detalhes, consulte nossos Docs sobre considerações de desempenho.Para continuar com nosso projeto, vamos criar um pacote
domain
com duas classes. O primeiro será o nossoAirbnb
.1 package com.mongodb.searcher.domain 2 3 import org.bson.codecs.pojo.annotations.BsonId 4 import org.bson.codecs.pojo.annotations.BsonProperty 5 import org.bson.types.Decimal128 6 7 data class Airbnb( 8 val id: String, 9 val name: String, 10 val summary: String, 11 val price: Decimal128, 12 13 val numbersOfReviews: Int, 14 val street: String 15 )
Em seguida, nosso
AirbnbService
:1 package com.mongodb.searcher.domain 2 3 import com.mongodb.searcher.resources.AirbnbRepository 4 import org.springframework.stereotype.Service 5 6 7 class AirbnbService( 8 private val airbnbRepository: AirbnbRepository 9 ) { 10 11 fun find(query: String, minNumberReviews: Int): List<Airbnb> { 12 require(query.isNotEmpty()) { "Query must not be empty" } 13 require(minNumberReviews > 0) { "Minimum number of reviews must not be negative" } 14 15 return airbnbRepository.find(query, minNumberReviews).map { it.toDomain() } 16 } 17 }
Essa classe é responsável por validar nossas entradas e acessar o repositório.
Para habilitar a comunicação REST, crie a classe
AirbnbController
dentro do pacoteapplication.web
:1 package com.mongodb.searcher.application.web 2 3 import com.mongodb.searcher.domain.Airbnb 4 import com.mongodb.searcher.domain.AirbnbService 5 import org.springframework.web.bind.annotation.GetMapping 6 import org.springframework.web.bind.annotation.RequestParam 7 import org.springframework.web.bind.annotation.RestController 8 9 10 class AirbnbController( 11 private val airbnbService: AirbnbService 12 ) { 13 14 15 fun find( 16 query: String, 17 minNumberReviews: Int 18 ): List<Airbnb> { 19 return airbnbService.find(query, minNumberReviews) 20 } 21 }
A estrutura final da pasta deve ser semelhante à da imagem:
Basta navegar até o diretório do projeto e executar:
1 ./gradlew bootRun
Em seguida, basta acessar o endpoint fornecendo os argumentos necessários. Abaixo está um exemplo:
1 curl --location 'http://localhost:8080/airbnb/search?query=Istambun&minNumberReviews=50'
Neste tutorial, criamos um aplicativo Spring Boot baseado em Kotlin que usa o MongoDB Atlas Atlas Search para encontrar listagens do Airbnb de forma eficiente. Demonstramos como criar um índice do Atlas Search e implementar um aggregation pipeline para filtrar e pesquisar dados.
Enquanto nos concentramos na correspondência difusa e na filtragem de contagem de avaliações, o MongoDB Atlas Atlas Search oferece muitos outros recursos avançados, como pontuação personalizada e análise avançada de texto.
Explorar estes recursos adicionais pode melhorar ainda mais a funcionalidade do Atlas Search e fornecer resultados ainda mais refinados. O exemplo de código-fonte usado nesta série está disponível em Github.
Para mais informações sobre o Atlas Search, veja o artigoExplorando os recursos do Atlas Search com o Atlas Search.
Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.