From 9e89d2c2ed6de069043a70bc046710eddf8a5036 Mon Sep 17 00:00:00 2001 From: Konstantin Albatov Date: Sun, 24 Mar 2024 15:13:39 +0300 Subject: [PATCH] :memo: Elastic search engine implemented # 2 --- .../data/model/database/Tender.kt | 12 ++-- .../data/model/dto/FullTextSearchRequest.kt | 6 +- .../data/repository/TenderSearchRepository.kt | 67 ++++++++++++++++++- .../controller/TenderController.kt | 38 ++++++++--- .../presentation/schedule/Scheduler.kt | 4 +- 5 files changed, 108 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/com/albatros/springsecurity/data/model/database/Tender.kt b/src/main/kotlin/com/albatros/springsecurity/data/model/database/Tender.kt index f7a99f7..bb0bca7 100644 --- a/src/main/kotlin/com/albatros/springsecurity/data/model/database/Tender.kt +++ b/src/main/kotlin/com/albatros/springsecurity/data/model/database/Tender.kt @@ -10,9 +10,9 @@ import org.springframework.data.elasticsearch.annotations.FieldType class Tender( @Field(type = FieldType.Text, name = "api_tender_info") var apiTenderInfo: String?, - @Field(type = FieldType.Keyword, name = "category") + @Field(type = FieldType.Text, name = "category") var category: String?, - @Field(type = FieldType.Keyword, name = "customer") + @Field(type = FieldType.Text, name = "customer") var customer: String?, @Field(type = FieldType.Text, name = "date") var date: String?, @@ -35,7 +35,7 @@ class Tender( var tenderInnerLink: String?, @Field(type = FieldType.Text, name = "tender_name") var tenderName: String?, - @Field(type = FieldType.Keyword, name = "tender_num_outer") + @Field(type = FieldType.Text, name = "tender_num_outer") var tenderNumOuter: String?, @Field(type = FieldType.Text, name = "user_id") var userId: String?, @@ -60,5 +60,9 @@ fun TenderDto.toDomainObject() = tenderName = this.TenderName, tenderNumOuter = this.TenderNumOuter, userId = this.User_id, - metaData = this.searchFragmentXML?.fragment?.joinToString() ?: "" + metaData = ( + this.ApiTenderInfo + this.Category + this.Customer + this.Etp + this.ID + this.Price + + this.Region + this.TenderName + this.User_id + + this.searchFragmentXML?.fragment?.joinToString() + ) ) diff --git a/src/main/kotlin/com/albatros/springsecurity/data/model/dto/FullTextSearchRequest.kt b/src/main/kotlin/com/albatros/springsecurity/data/model/dto/FullTextSearchRequest.kt index 676cfd6..1d1166a 100644 --- a/src/main/kotlin/com/albatros/springsecurity/data/model/dto/FullTextSearchRequest.kt +++ b/src/main/kotlin/com/albatros/springsecurity/data/model/dto/FullTextSearchRequest.kt @@ -1,2 +1,6 @@ -package com.albatros.springsecurity.data.model.dto +package com.albatros.springsecurity.data.model.dto +class FullTextSearchRequest( + val include: String, + val exclude: String +) diff --git a/src/main/kotlin/com/albatros/springsecurity/data/repository/TenderSearchRepository.kt b/src/main/kotlin/com/albatros/springsecurity/data/repository/TenderSearchRepository.kt index 328338d..3532378 100644 --- a/src/main/kotlin/com/albatros/springsecurity/data/repository/TenderSearchRepository.kt +++ b/src/main/kotlin/com/albatros/springsecurity/data/repository/TenderSearchRepository.kt @@ -3,12 +3,77 @@ package com.albatros.springsecurity.data.repository import com.albatros.springsecurity.data.model.database.Tender import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable +import org.springframework.data.elasticsearch.annotations.Query import org.springframework.data.elasticsearch.repository.ElasticsearchRepository import org.springframework.stereotype.Repository @Repository -interface TenderRepository : ElasticsearchRepository { +interface TenderSearchRepository : ElasticsearchRepository { + @Query( + """ + { + "bool": { + "must": [ + { + "multi_match": { + "query": "?0", + "fields": ["tender_name^5", "tender_id^15", "region^5", "etp^10", "fz", "meta_data", "user_id", "category^10", "customer^15", "date"], + "operator": "AND", + "fuzziness": "2", + "minimum_should_match": "2", + "type": "best_fields" + } + } + ], + "must_not": [ + { + "multi_match": { + "query": "?1", + "fields": ["tender_name^5", "tender_id^15", "region^5", "etp^10", "fz", "meta_data", "user_id", "category^10", "customer^15", "date"], + "operator": "AND", + "fuzziness": "2", + "type": "best_fields" + } + } + ] + } + } + """ + ) + fun fullTextSearchAnd(keywords: String): List + + @Query( + """ + { + "bool": { + "must": [ + { + "multi_match": { + "query": "?0", + "fields": ["tender_name^5", "tender_id^15", "region^5", "etp^10", "fz", "meta_data", "user_id", "category^10", "customer^15", "date"], + "operator": "OR", + "fuzziness": "2", + "type": "best_fields" + } + } + ], + "must_not": [ + { + "multi_match": { + "query": "?1", + "fields": ["tender_name^5", "tender_id^15", "region^5", "etp^10", "fz", "meta_data", "user_id", "category^10", "customer^15", "date"], + "operator": "AND", + "fuzziness": "2", + "type": "best_fields" + } + } + ] + } + } + """ + ) + fun fullTextSearchOr(keywords: String, exclude: String): List fun findAllByTenderId(tenderId: String, pageable: Pageable): Page fun findAllByCustomerContainsIgnoreCase(customer: String, pageable: Pageable): Page diff --git a/src/main/kotlin/com/albatros/springsecurity/presentation/controller/TenderController.kt b/src/main/kotlin/com/albatros/springsecurity/presentation/controller/TenderController.kt index 1e52ed0..e77f598 100644 --- a/src/main/kotlin/com/albatros/springsecurity/presentation/controller/TenderController.kt +++ b/src/main/kotlin/com/albatros/springsecurity/presentation/controller/TenderController.kt @@ -1,10 +1,15 @@ package com.albatros.springsecurity.presentation.controller import com.albatros.springsecurity.data.model.database.Tender -import com.albatros.springsecurity.data.repository.TenderRepository +import com.albatros.springsecurity.data.model.dto.FullTextSearchRequest +import com.albatros.springsecurity.data.repository.TenderSearchRepository import com.albatros.springsecurity.data.service.TenderApiService +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @@ -13,9 +18,16 @@ import org.springframework.web.bind.annotation.RestController @RequestMapping("/api") class TenderController( private val apiService: TenderApiService, - private val tenderRepository: TenderRepository + private val tenderRepository: TenderSearchRepository, ) { + @PostMapping("/full-text-search") + fun getAll(@RequestBody fullTextSearchRequest: FullTextSearchRequest): List { + return tenderRepository.fullTextSearchOr( + fullTextSearchRequest.include, fullTextSearchRequest.exclude + ) + } + @GetMapping("/provider/") fun getAll() = apiService.getAllTenderProviders() @@ -23,21 +35,25 @@ class TenderController( fun getTendersByProviderId(@PathVariable id: Int) = apiService.getTendersByProviders(id) @GetMapping("/tender/customer") - fun findAllByCustomerContainsIgnoreCase(@RequestParam customer: String): List = - tenderRepository.findAllByCustomerContainsIgnoreCase(customer) + fun findAllByCustomerContainsIgnoreCase(@RequestParam customer: String, pageable: Pageable): Page = + tenderRepository.findAllByCustomerContainsIgnoreCase(customer, pageable) @GetMapping("/tender/region") - fun findAllByRegionContainsIgnoreCase(@RequestParam region: String): List = - tenderRepository.findAllByRegionContainsIgnoreCase(region) + fun findAllByRegionContainsIgnoreCase(@RequestParam region: String, pageable: Pageable): Page = + tenderRepository.findAllByRegionContainsIgnoreCase(region, pageable) @GetMapping("/tender/category") - fun findAllByCategory(@RequestParam category: String): List = tenderRepository.findAllByCategory(category) + fun findAllByCategory(@RequestParam category: String, pageable: Pageable): Page = + tenderRepository.findAllByCategory(category, pageable) @GetMapping("/tender/etp") - fun findAllByEtpEqualsIgnoreCase(@RequestParam etp: String): List = - tenderRepository.findAllByEtpEqualsIgnoreCase(etp) + fun findAllByEtpEqualsIgnoreCase(@RequestParam etp: String, pageable: Pageable): Page = + tenderRepository.findAllByEtpEqualsIgnoreCase(etp, pageable) @GetMapping("/tender/name") - fun findAllByTenderNameContainingIgnoreCase(@RequestParam(value = "query") query: String): List = - tenderRepository.findAllByTenderNameContainingIgnoreCase(query) + fun findAllByTenderNameContainingIgnoreCase( + @RequestParam(value = "query") query: String, + pageable: Pageable + ): Page = + tenderRepository.findAllByTenderNameContainingIgnoreCase(query, pageable) } diff --git a/src/main/kotlin/com/albatros/springsecurity/presentation/schedule/Scheduler.kt b/src/main/kotlin/com/albatros/springsecurity/presentation/schedule/Scheduler.kt index bd493e4..e6c1d16 100644 --- a/src/main/kotlin/com/albatros/springsecurity/presentation/schedule/Scheduler.kt +++ b/src/main/kotlin/com/albatros/springsecurity/presentation/schedule/Scheduler.kt @@ -4,7 +4,7 @@ import com.albatros.springsecurity.data.model.database.toDomainObject import com.albatros.springsecurity.data.model.dto.TenderDto import com.albatros.springsecurity.data.model.dto.TenderProviderDto import com.albatros.springsecurity.data.repository.TenderProviderRepository -import com.albatros.springsecurity.data.repository.TenderRepository +import com.albatros.springsecurity.data.repository.TenderSearchRepository import com.albatros.springsecurity.data.service.TenderApiService import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -15,7 +15,7 @@ import org.springframework.scheduling.annotation.Scheduled @Configuration class Scheduler( private val tenderProviderRepository: TenderProviderRepository, - private val tenderRepository: TenderRepository, + private val tenderRepository: TenderSearchRepository, private val apiService: TenderApiService, ) {