Skip to content

Commit

Permalink
chore: add extra search index for current versions
Browse files Browse the repository at this point in the history
  • Loading branch information
NilsOveTen committed Oct 6, 2023
1 parent 5aa48c0 commit 9952701
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package no.fdk.concept_catalog.elastic

import no.fdk.concept_catalog.model.CurrentConcept
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository
import org.springframework.stereotype.Repository

@Repository
interface CurrentConceptRepository : ElasticsearchRepository<CurrentConcept, String>
24 changes: 20 additions & 4 deletions src/main/kotlin/no/fdk/concept_catalog/elastic/ElasticUpdater.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,45 @@ package no.fdk.concept_catalog.elastic
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import no.fdk.concept_catalog.model.BegrepDBO
import no.fdk.concept_catalog.model.CurrentConcept
import org.slf4j.LoggerFactory
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.findAll
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service

private val logger = LoggerFactory.getLogger(ElasticUpdater::class.java)

@Service
class ElasticUpdater(
private val conceptRepository: MongoTemplate,
private val conceptSearchRepository: ConceptSearchRepository
private val conceptSearchRepository: ConceptSearchRepository,
private val currentConceptRepository: CurrentConceptRepository
) {

fun reindexElastic() = runBlocking {
launch {
try { conceptSearchRepository.deleteAll() }
catch (_: Exception) { }
try {
conceptSearchRepository.deleteAll()
currentConceptRepository.deleteAll()
} catch (_: Exception) { }

conceptRepository.findAll<BegrepDBO>()
.forEach { conceptSearchRepository.save(it) }
.forEach {
conceptSearchRepository.save(it)
if (it.shouldBeCurrent(currentConceptRepository.findByIdOrNull(it.originaltBegrep))) currentConceptRepository.save(CurrentConcept(it))
}

logger.info("finished reindexing elastic")
}
}

}

fun BegrepDBO.shouldBeCurrent(current: CurrentConcept?): Boolean =
when {
current == null -> true
erPublisert && !current.erPublisert -> true
!erPublisert && current.erPublisert -> false
else -> versjonsnr > current.versjonsnr
}
78 changes: 78 additions & 0 deletions src/main/kotlin/no/fdk/concept_catalog/model/CurrentConcept.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package no.fdk.concept_catalog.model

import com.fasterxml.jackson.annotation.JsonFormat
import com.fasterxml.jackson.annotation.JsonInclude
import org.springframework.data.annotation.Id
import org.springframework.data.elasticsearch.annotations.*
import java.time.Instant
import java.time.LocalDate

@Document(indexName = "concepts-current")
@Setting(settingPath = "/elastic/settings.json")
@Mapping(mappingPath = "/elastic/mappings.json")
@JsonInclude(JsonInclude.Include.NON_NULL)
data class CurrentConcept(
val idOfThisVersion: String,
@Id val originaltBegrep: String,
val versjonsnr: SemVer,
val revisjonAv: String?,
val status: Status?,
val statusURI: String? = null,
val erPublisert: Boolean = false,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "Europe/Oslo")
@Field(type = FieldType.Date)
val publiseringsTidspunkt: Instant? = null,
val anbefaltTerm: Term?,
val tillattTerm: Map<String, List<String>>?,
val frarådetTerm: Map<String, List<String>>?,
val definisjon: Definisjon?,
val definisjonForAllmennheten: Definisjon?,
val definisjonForSpesialister: Definisjon?,
val merknad: Map<String, String>?,
val merkelapp: List<String>?,
val ansvarligVirksomhet: Virksomhet,
val eksempel: Map<String, String>?,
val fagområde: Map<String, List<String>>?,
val fagområdeKoder: List<String>?,
val omfang: URITekst?,
val kontaktpunkt: Kontaktpunkt?,
@Field(type = FieldType.Date)
val gyldigFom: LocalDate?,
@Field(type = FieldType.Date)
val gyldigTom: LocalDate?,
val endringslogelement: Endringslogelement?,
@Field(type = FieldType.Date)
val opprettet: Instant? = null,
val opprettetAv: String? = null,
val seOgså: List<String>?,
val erstattesAv: List<String>?,
val assignedUser: String?,
val abbreviatedLabel: String?,
val begrepsRelasjon: List<BegrepsRelasjon>?,
val interneFelt: Map<String, InterntFelt>?
) {
constructor(dbo: BegrepDBO) : this(
dbo.id, dbo.originaltBegrep, dbo.versjonsnr, dbo.revisjonAv,
dbo.status, dbo.statusURI, dbo.erPublisert, dbo.publiseringsTidspunkt,
dbo.anbefaltTerm, dbo.tillattTerm, dbo.frarådetTerm, dbo.definisjon,
dbo.definisjonForAllmennheten, dbo.definisjonForSpesialister,
dbo.merknad, dbo.merkelapp, dbo.ansvarligVirksomhet, dbo.eksempel,
dbo.fagområde, dbo.fagområdeKoder, dbo.omfang, dbo.kontaktpunkt,
dbo.gyldigFom, dbo.gyldigTom, dbo.endringslogelement, dbo.opprettet,
dbo.opprettetAv, dbo.seOgså, dbo.erstattesAv, dbo.assignedUser,
dbo.abbreviatedLabel, dbo.begrepsRelasjon, dbo.interneFelt
)

fun toDBO(): BegrepDBO =
BegrepDBO(
idOfThisVersion, originaltBegrep, versjonsnr, revisjonAv,
status, statusURI, erPublisert, publiseringsTidspunkt,
anbefaltTerm, tillattTerm, frarådetTerm, definisjon,
definisjonForAllmennheten, definisjonForSpesialister,
merknad, merkelapp, ansvarligVirksomhet, eksempel,
fagområde, fagområdeKoder, omfang, kontaktpunkt,
gyldigFom, gyldigTom, endringslogelement, opprettet,
opprettetAv, seOgså, erstattesAv, assignedUser,
abbreviatedLabel, begrepsRelasjon, interneFelt
)
}
13 changes: 8 additions & 5 deletions src/main/kotlin/no/fdk/concept_catalog/model/Pagination.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package no.fdk.concept_catalog.model

data class Pagination (
val page: Int = 0,
val size: Int = 10
)
private val page: Int = 0,
private val size: Int = 10
) {
fun getPage(): Int = page.let { if (it < 0) 0 else it }
fun getSize(): Int = size.let { if (it < 1) 10 else it }
}

data class Paginated (
val hits: List<Begrep>,
Expand All @@ -13,6 +16,6 @@ data class Paginated (
data class PageMeta (
val currentPage: Int,
val size: Int,
val totalElements: Int,
val totalPages: Int
val totalElements: Long,
val totalPages: Long
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package no.fdk.concept_catalog.service

import com.fasterxml.jackson.databind.ObjectMapper
import no.fdk.concept_catalog.elastic.ConceptSearchRepository
import no.fdk.concept_catalog.elastic.CurrentConceptRepository
import no.fdk.concept_catalog.model.*
import java.util.UUID
import no.fdk.concept_catalog.repository.ChangeRequestRepository
Expand All @@ -22,8 +22,8 @@ class ChangeRequestService(
private val changeRequestRepository: ChangeRequestRepository,
private val conceptRepository: ConceptRepository,
private val conceptSearchRepository: ConceptSearchRepository,
private val conceptService: ConceptService,
private val mapper: ObjectMapper
private val currentConceptRepository: CurrentConceptRepository,
private val conceptService: ConceptService
) {
fun getCatalogRequests(catalogId: String, status: String?, conceptId: String?): List<ChangeRequest> {
val parsedStatus = changeRequestStatusFromString(status)
Expand Down Expand Up @@ -83,6 +83,7 @@ class ChangeRequestService(
dbConcept == null -> createNewConcept(Virksomhet(id=catalogId), user)
.updateLastChangedAndByWhom(user)
.also { conceptSearchRepository.save(it) }
.also { currentConceptRepository.save(CurrentConcept(it)) }
.let { conceptRepository.save(it) }
dbConcept.erPublisert -> dbConcept.createNewRevision(user)
.updateLastChangedAndByWhom(user)
Expand All @@ -98,6 +99,9 @@ class ChangeRequestService(
changeRequest.copy(status = ChangeRequestStatus.OPEN).run { changeRequestRepository.save(this) }
if (conceptToUpdate.id != dbConcept?.id) {
conceptSearchRepository.delete(conceptToUpdate)
if (conceptToUpdate.id == conceptToUpdate.originaltBegrep) {
currentConceptRepository.delete(CurrentConcept(conceptToUpdate))
}
conceptRepository.delete(conceptToUpdate)
}
throw ex
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package no.fdk.concept_catalog.service

import co.elastic.clients.elasticsearch._types.query_dsl.TextQueryType
import no.fdk.concept_catalog.model.*
import org.springframework.data.domain.Pageable
import org.springframework.data.elasticsearch.client.elc.NativeQuery
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder
import org.springframework.data.elasticsearch.core.ElasticsearchOperations
import org.springframework.data.elasticsearch.core.SearchHits
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates
import org.springframework.data.elasticsearch.core.query.Query
import org.springframework.stereotype.Service
Expand All @@ -14,17 +16,25 @@ class ConceptSearchService(
private val elasticsearchOperations: ElasticsearchOperations
) {

fun searchConcepts(orgNumber: String, search: SearchOperation): List<BegrepDBO> =
fun searchConcepts(orgNumber: String, search: SearchOperation): SearchHits<BegrepDBO> =
elasticsearchOperations.search(
search.toElasticQuery(orgNumber),
BegrepDBO::class.java,
IndexCoordinates.of("concepts")
).map { it.content }.toList()
)

fun searchCurrentConcepts(orgNumber: String, search: SearchOperation): SearchHits<CurrentConcept> =
elasticsearchOperations.search(
search.toElasticQuery(orgNumber),
CurrentConcept::class.java,
IndexCoordinates.of("concepts-current")
)

private fun SearchOperation.toElasticQuery(orgNumber: String): Query {
val qb = NativeQuery.builder()
qb.withFilter { q -> q.match { m -> m.field("ansvarligVirksomhet.id").query(orgNumber) } }
if (!query.isNullOrBlank()) qb.addFieldsQuery(fields, query)
qb.withPageable(Pageable.ofSize(pagination.getSize()).withPage(pagination.getPage()))
return qb.build()
}

Expand Down
58 changes: 32 additions & 26 deletions src/main/kotlin/no/fdk/concept_catalog/service/ConceptService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package no.fdk.concept_catalog.service
import com.fasterxml.jackson.databind.ObjectMapper
import no.fdk.concept_catalog.configuration.ApplicationProperties
import no.fdk.concept_catalog.elastic.ConceptSearchRepository
import no.fdk.concept_catalog.elastic.CurrentConceptRepository
import no.fdk.concept_catalog.model.*
import no.fdk.concept_catalog.repository.ConceptRepository
import no.fdk.concept_catalog.validation.isValid
Expand All @@ -18,7 +19,7 @@ import org.springframework.web.server.ResponseStatusException
import org.springframework.web.util.UriComponentsBuilder
import java.time.Instant
import kotlin.math.ceil
import kotlin.math.roundToInt
import kotlin.math.roundToLong

private val logger = LoggerFactory.getLogger(ConceptService::class.java)

Expand All @@ -27,6 +28,7 @@ class ConceptService(
private val conceptRepository: ConceptRepository,
private val conceptSearchService: ConceptSearchService,
private val conceptSearchRepository: ConceptSearchRepository,
private val currentConceptRepository: CurrentConceptRepository,
private val mongoOperations: MongoOperations,
private val applicationProperties: ApplicationProperties,
private val conceptPublisher: ConceptPublisher,
Expand All @@ -36,6 +38,9 @@ class ConceptService(

fun deleteConcept(concept: BegrepDBO) {
conceptSearchRepository.delete(concept)
if (concept.id == concept.originaltBegrep) {
currentConceptRepository.delete(CurrentConcept(concept))
}
conceptRepository.delete(concept)
}

Expand Down Expand Up @@ -164,6 +169,10 @@ class ConceptService(
val locations = conceptsAndOperations.map { historyService.updateHistory(it.key, it.value, user, jwt) }
try {
conceptSearchRepository.saveAll(conceptsAndOperations.keys)
conceptsAndOperations.keys
.filter { it.id == it.originaltBegrep }
.map { CurrentConcept(it) }
.run { currentConceptRepository.saveAll(this) }
return conceptRepository.saveAll(conceptsAndOperations.keys).map { it.withHighestVersionDTO() }
} catch (ex: Exception) {
locations.filterNotNull().forEach { historyService.removeHistoryUpdate(it, jwt) }
Expand Down Expand Up @@ -211,35 +220,31 @@ class ConceptService(
.map { it.toDTO(it.versjonsnr, it.id, findIdOfUnpublishedRevision(it)) }

fun searchConcepts(orgNumber: String, search: SearchOperation): Paginated =
conceptSearchService.searchConcepts(orgNumber, search)
.map { it.withHighestVersionDTO() }
.filter { if(search.filters.onlyCurrentVersions) it.isCurrentVersion() else true }
.toList()
.paginate(search.pagination)

private fun List<Begrep>.paginate(pagination: Pagination): Paginated {
val currentPage = if (pagination.page > 0) pagination.page else 0
val pageSize = if (pagination.size > 0) pagination.size else 10
val totalElements = size
val totalPages = ceil(totalElements.toDouble() / pageSize).roundToInt()
val nextPage = currentPage.inc()

val fromIndex = currentPage.times(pageSize)
val toIndex = nextPage.times(pageSize)

val hits = when {
currentPage >= totalPages -> emptyList()
nextPage == totalPages -> subList(fromIndex, totalElements)
else -> subList(fromIndex, toIndex)
if (search.filters.onlyCurrentVersions) {
val hits = conceptSearchService.searchCurrentConcepts(orgNumber, search)

hits.map { it.content }
.map { it.toDBO() }
.map { it.withHighestVersionDTO() }
.toList()
.paginate(hits.totalHits, search.pagination)
} else {
val hits = conceptSearchService.searchConcepts(orgNumber, search)

hits.map { it.content }
.map { it.withHighestVersionDTO() }
.toList()
.paginate(hits.totalHits, search.pagination)
}

private fun List<Begrep>.paginate(totalHits: Long, pagination: Pagination): Paginated {
return Paginated(
hits = hits,
hits = this,
page = PageMeta(
currentPage = currentPage,
size = pageSize,
totalElements = totalElements,
totalPages = totalPages
currentPage = pagination.getPage(),
size = size,
totalElements = totalHits,
totalPages = ceil(totalHits.toDouble() / pagination.getSize()).roundToLong()
)
)
}
Expand Down Expand Up @@ -293,6 +298,7 @@ class ConceptService(
conceptPublisher.send(concept.ansvarligVirksomhet.id)

conceptSearchRepository.save(published)
currentConceptRepository.save(CurrentConcept(published))
return conceptRepository.save(published)
.withHighestVersionDTO()
}
Expand Down
Loading

0 comments on commit 9952701

Please sign in to comment.