Skip to content

Commit

Permalink
feat(api): search series by completeness
Browse files Browse the repository at this point in the history
  • Loading branch information
gotson committed Dec 31, 2021
1 parent e4b912e commit 494bdf2
Show file tree
Hide file tree
Showing 10 changed files with 35 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.gotson.komga.application.tasks

import org.gotson.komga.domain.model.BookMetadataPatchCapability
import org.gotson.komga.domain.model.CopyMode
import org.gotson.komga.infrastructure.search.LuceneEntity
import java.io.Serializable

const val HIGHEST_PRIORITY = 8
Expand Down Expand Up @@ -79,9 +80,9 @@ sealed class Task(priority: Int = DEFAULT_PRIORITY) : Serializable {
override fun toString(): String = "RepairExtension(bookId='$bookId', priority='$priority')"
}

class RebuildIndex(priority: Int = DEFAULT_PRIORITY) : Task(priority) {
class RebuildIndex(val entities: Set<LuceneEntity>?, priority: Int = DEFAULT_PRIORITY) : Task(priority) {
override fun uniqueId() = "REBUILD_INDEX"
override fun toString(): String = "RebuildIndex(priority='$priority')"
override fun toString(): String = "RebuildIndex(priority='$priority',entities='${entities?.map { it.type }}')"
}

class DeleteBook(val bookId: String, priority: Int = DEFAULT_PRIORITY) : Task(priority) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class TaskHandler(
bookLifecycle.hashAndPersist(book)
} ?: logger.warn { "Cannot execute task $task: Book does not exist" }

is Task.RebuildIndex -> searchIndexLifecycle.rebuildIndex()
is Task.RebuildIndex -> searchIndexLifecycle.rebuildIndex(task.entities)

is Task.DeleteBook -> {
bookRepository.findByIdOrNull(task.bookId)?.let { book ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import org.gotson.komga.infrastructure.jms.QUEUE_TASKS
import org.gotson.komga.infrastructure.jms.QUEUE_TASKS_TYPE
import org.gotson.komga.infrastructure.jms.QUEUE_TYPE
import org.gotson.komga.infrastructure.jms.QUEUE_UNIQUE_ID
import org.gotson.komga.infrastructure.search.LuceneEntity
import org.springframework.data.domain.Sort
import org.springframework.jms.core.JmsTemplate
import org.springframework.stereotype.Service
Expand Down Expand Up @@ -117,8 +118,8 @@ class TaskReceiver(
submitTask(Task.ImportBook(sourceFile, seriesId, copyMode, destinationName, upgradeBookId, priority))
}

fun rebuildIndex(priority: Int = DEFAULT_PRIORITY) {
submitTask(Task.RebuildIndex(priority))
fun rebuildIndex(priority: Int = DEFAULT_PRIORITY, entities: Set<LuceneEntity>? = null) {
submitTask(Task.RebuildIndex(entities, priority))
}

fun deleteBook(bookId: String, priority: Int = DEFAULT_PRIORITY) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ open class SeriesSearch(
val metadataStatus: Collection<SeriesMetadata.Status>? = null,
val publishers: Collection<String>? = null,
val deleted: Boolean? = null,
val complete: Boolean? = null,
) {
enum class SearchField {
NAME, TITLE, TITLE_SORT
Expand All @@ -22,6 +23,7 @@ class SeriesSearchWithReadProgress(
metadataStatus: Collection<SeriesMetadata.Status>? = null,
publishers: Collection<String>? = null,
deleted: Boolean? = null,
complete: Boolean? = null,
val languages: Collection<String>? = null,
val genres: Collection<String>? = null,
val tags: Collection<String>? = null,
Expand All @@ -37,4 +39,5 @@ class SeriesSearchWithReadProgress(
metadataStatus = metadataStatus,
publishers = publishers,
deleted = deleted,
complete = complete,
)
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class SeriesDtoDao(
collectionId: String,
search: SeriesSearchWithReadProgress,
userId: String,
pageable: Pageable
pageable: Pageable,
): Page<SeriesDto> {
val conditions = search.toCondition().and(cs.COLLECTION_ID.eq(collectionId))
val joinConditions = search.toJoinConditions().copy(selectCollectionNumber = true, collection = true)
Expand All @@ -98,7 +98,7 @@ class SeriesDtoDao(
override fun findAllRecentlyUpdated(
search: SeriesSearchWithReadProgress,
userId: String,
pageable: Pageable
pageable: Pageable,
): Page<SeriesDto> {
val conditions = search.toCondition()
.and(s.CREATED_DATE.ne(s.LAST_MODIFIED_DATE))
Expand Down Expand Up @@ -143,7 +143,7 @@ class SeriesDtoDao(

private fun selectBase(
userId: String,
joinConditions: JoinConditions = JoinConditions()
joinConditions: JoinConditions = JoinConditions(),
): SelectOnConditionStep<Record> =
dsl.selectDistinct(*groupFields)
.apply { if (joinConditions.selectCollectionNumber) select(cs.NUMBER) }
Expand Down Expand Up @@ -205,7 +205,7 @@ class SeriesDtoDao(
dtos,
if (pageable.isPaged) PageRequest.of(pageable.pageNumber, pageable.pageSize, pageSort)
else PageRequest.of(0, maxOf(count, 20), pageSort),
count.toLong()
count.toLong(),
)
}

Expand Down Expand Up @@ -248,7 +248,7 @@ class SeriesDtoDao(
booksUnreadCount,
booksInProgressCount,
dr.toDto(genres, tags),
bmar.toDto(aggregatedAuthors, aggregatedTags)
bmar.toDto(aggregatedAuthors, aggregatedTags),
)
}

Expand All @@ -262,6 +262,8 @@ class SeriesDtoDao(
if (!publishers.isNullOrEmpty()) c = c.and(lower(d.PUBLISHER).`in`(publishers.map { it.lowercase() }))
if (deleted == true) c = c.and(s.DELETED_DATE.isNotNull)
if (deleted == false) c = c.and(s.DELETED_DATE.isNull)
if (complete == false) c = c.and(d.TOTAL_BOOK_COUNT.isNotNull.and(d.TOTAL_BOOK_COUNT.ne(s.BOOK_COUNT)))
if (complete == true) c = c.and(d.TOTAL_BOOK_COUNT.isNotNull.and(d.TOTAL_BOOK_COUNT.eq(s.BOOK_COUNT)))
if (!languages.isNullOrEmpty()) c = c.and(lower(d.LANGUAGE).`in`(languages.map { it.lowercase() }))
if (!genres.isNullOrEmpty()) c = c.and(lower(g.GENRE).`in`(genres.map { it.lowercase() }))
if (!tags.isNullOrEmpty()) c = c.and(lower(st.TAG).`in`(tags.map { it.lowercase() }).or(lower(bmat.TAG).`in`(tags.map { it.lowercase() })))
Expand Down Expand Up @@ -322,7 +324,7 @@ class SeriesDtoDao(
booksUnreadCount: Int,
booksInProgressCount: Int,
metadata: SeriesMetadataDto,
booksMetadata: BookMetadataAggregationDto
booksMetadata: BookMetadataAggregationDto,
) =
SeriesDto(
id = id,
Expand Down Expand Up @@ -378,6 +380,6 @@ class SeriesDtoDao(
summaryNumber = summaryNumber,

created = createdDate.toCurrentTimeZone(),
lastModified = lastModifiedDate.toCurrentTimeZone()
lastModified = lastModifiedDate.toCurrentTimeZone(),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ fun SeriesDto.toDocument() =
}
if (booksMetadata.releaseDate != null) add(TextField("release_date", DateTools.dateToString(booksMetadata.releaseDate.toDate(), DateTools.Resolution.YEAR), Field.Store.NO))
add(TextField("deleted", deleted.toString(), Field.Store.NO))
if (metadata.totalBookCount != null) add(TextField("complete", (metadata.totalBookCount == booksCount).toString(), Field.Store.NO))

add(StringField(LuceneEntity.TYPE, LuceneEntity.Series.type, Field.Store.NO))
add(StringField(LuceneEntity.Series.id, id, Field.Store.YES))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import kotlin.math.ceil
import kotlin.time.measureTime

private val logger = KotlinLogging.logger {}
private const val INDEX_VERSION = 3
private const val INDEX_VERSION = 4

@Component
class SearchIndexLifecycle(
Expand All @@ -37,10 +37,12 @@ class SearchIndexLifecycle(
private val luceneHelper: LuceneHelper,
) {

fun rebuildIndex() {
logger.info { "Rebuild all indexes" }
fun rebuildIndex(entities: Set<LuceneEntity>?) {
val targetEntities = entities ?: LuceneEntity.values().toSet()

LuceneEntity.values().forEach {
logger.info { "Rebuild index for: ${targetEntities.map { it.type }}" }

targetEntities.forEach {
when (it) {
LuceneEntity.Book -> rebuildIndex(it, { p: Pageable -> bookDtoRepository.findAll(BookSearchWithReadProgress(), "unused", p) }, { e: BookDto -> e.toDocument() })
LuceneEntity.Series -> rebuildIndex(it, { p: Pageable -> seriesDtoRepository.findAll(SeriesSearchWithReadProgress(), "unused", p) }, { e: SeriesDto -> e.toDocument() })
Expand All @@ -63,7 +65,7 @@ class SearchIndexLifecycle(
indexWriter.deleteDocuments(Term(LuceneEntity.TYPE, entity.type))

(0 until pages).forEach { page ->
logger.info { "Processing page $page of $batchSize elements" }
logger.info { "Processing page ${page + 1} of $pages ($batchSize elements)" }
val entityDocs = provider(PageRequest.of(page, batchSize)).content
.map { toDoc(it) }
indexWriter.addDocuments(entityDocs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ class SeriesCollectionController(
@RequestParam(name = "age_rating", required = false) ageRatings: List<String>?,
@RequestParam(name = "release_year", required = false) release_years: List<String>?,
@RequestParam(name = "deleted", required = false) deleted: Boolean?,
@RequestParam(name = "complete", required = false) complete: Boolean?,
@RequestParam(name = "unpaged", required = false) unpaged: Boolean = false,
@Parameter(hidden = true) @Authors authors: List<Author>?,
@Parameter(hidden = true) page: Pageable
Expand All @@ -286,6 +287,7 @@ class SeriesCollectionController(
readStatus = readStatus,
publishers = publishers,
deleted = deleted,
complete = complete,
languages = languages,
genres = genres,
tags = tags,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class SeriesController(
@RequestParam(name = "age_rating", required = false) ageRatings: List<String>?,
@RequestParam(name = "release_year", required = false) release_years: List<String>?,
@RequestParam(name = "deleted", required = false) deleted: Boolean?,
@RequestParam(name = "complete", required = false) complete: Boolean?,
@RequestParam(name = "unpaged", required = false) unpaged: Boolean = false,
@Parameter(hidden = true) @Authors authors: List<Author>?,
@Parameter(hidden = true) page: Pageable
Expand Down Expand Up @@ -165,6 +166,7 @@ class SeriesController(
readStatus = readStatus,
publishers = publishers,
deleted = deleted,
complete = complete,
languages = languages,
genres = genres,
tags = tags,
Expand Down Expand Up @@ -200,6 +202,7 @@ class SeriesController(
@RequestParam(name = "age_rating", required = false) ageRatings: List<String>?,
@RequestParam(name = "release_year", required = false) release_years: List<String>?,
@RequestParam(name = "deleted", required = false) deleted: Boolean?,
@RequestParam(name = "complete", required = false) complete: Boolean?,
@Parameter(hidden = true) @Authors authors: List<Author>?,
@Parameter(hidden = true) page: Pageable
): List<GroupCountDto> {
Expand All @@ -218,6 +221,7 @@ class SeriesController(
readStatus = readStatus,
publishers = publishers,
deleted = deleted,
complete = complete,
languages = languages,
genres = genres,
tags = tags,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.gotson.komga.interfaces.scheduler
import mu.KotlinLogging
import org.gotson.komga.application.tasks.HIGHEST_PRIORITY
import org.gotson.komga.application.tasks.TaskReceiver
import org.gotson.komga.infrastructure.search.LuceneEntity
import org.gotson.komga.infrastructure.search.LuceneHelper
import org.springframework.boot.context.event.ApplicationReadyEvent
import org.springframework.context.annotation.Profile
Expand All @@ -27,6 +28,7 @@ class SearchIndexController(
logger.info { "Lucene index version: ${luceneHelper.getIndexVersion()}" }
when (luceneHelper.getIndexVersion()) {
1, 2 -> taskReceiver.rebuildIndex(HIGHEST_PRIORITY)
3 -> taskReceiver.rebuildIndex(HIGHEST_PRIORITY, setOf(LuceneEntity.Series))
}
}
}
Expand Down

0 comments on commit 494bdf2

Please sign in to comment.