You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

101 lines
3.1 KiB
Kotlin

package moe.odango.index.http.graphql
import io.inbot.eskotlinwrapper.IndexRepository
import io.inbot.eskotlinwrapper.dsl.*
import moe.odango.index.di
import moe.odango.index.entity.Title
import moe.odango.index.es.dto.AnimeDTO
import moe.odango.index.http.graphql.dto.AnimeItem
import moe.odango.index.http.graphql.dto.AnimeTitleItem
import moe.odango.index.http.graphql.dto.AutoCompleteItem
import moe.odango.index.utils.ScoreMode
import moe.odango.index.utils.nested
import org.elasticsearch.action.search.dsl
import org.elasticsearch.action.search.source
import org.elasticsearch.client.RestHighLevelClient
import org.elasticsearch.common.unit.Fuzziness
import org.elasticsearch.search.suggest.SuggestBuilder
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder
import org.kodein.di.instance
class AnimeService {
private val es by di.instance<IndexRepository<AnimeDTO>>()
private val client by di.instance<RestHighLevelClient>()
fun autocomplete(title: String): List<AutoCompleteItem> {
return es.search {
source {
suggest(
SuggestBuilder().addSuggestion(
"title",
CompletionSuggestionBuilder("title.name").prefix(title, Fuzziness.AUTO)
)
)
}
}
.hits
.mapNotNull { (s, item) ->
AutoCompleteItem(
s.innerHits["title"]?.hits?.get(0)?.sourceAsMap?.get("name")?.toString() ?: return@mapNotNull null,
item?.id.toString() ?: return@mapNotNull null
)
}
.toList()
}
fun search(
title: String? = null,
description: String? = null,
genre: List<String>? = null
): List<AnimeItem> {
val items = mutableListOf<ESQuery>()
title?.let {
items.add(
nested("title") {
query = MatchQuery("title.name", it)
scoreMode = ScoreMode.max
}
)
}
genre?.let {
items.add(
bool {
must(*it.toSet().map { genre -> TermQuery("genre", genre) }.toTypedArray())
}
)
}
description?.let {
items.add(
nested("description") {
query = MatchQuery("description.name", it)
scoreMode = ScoreMode.max
}
)
}
return es.search {
dsl {
query = disMax {
queries(*items.toTypedArray())
}
}
}
.hits
.mapNotNull { (_, dto) ->
dto?.let {
AnimeItem(
it.id.toString(),
it.title.map { dto ->
AnimeTitleItem(dto.name, dto.language, dto.type.let(Title.TitleType::valueOf), dto.source)
},
it.genre.toSet().toList()
)
}
}
.toList()
}
}