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>() private val client by di.instance() fun autocomplete(title: String): List { 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? = null ): List { val items = mutableListOf() 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() } }