Skip to content

Commit

Permalink
Merge pull request #830 from wellcomecollection/rk/subject-contributo…
Browse files Browse the repository at this point in the history
…r-concept-filter

Implement contributor & subject concept filters
  • Loading branch information
kenoir authored Nov 22, 2024
2 parents 14fd273 + 4e66dac commit a6b8dd0
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 125 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,19 @@ case class SubjectLabelFilter(labels: Seq[String])
with ImageFilter
with Pairable

case class SubjectConceptFilter(conceptIds: Seq[String])
extends WorkFilter
with ImageFilter

case class ContributorsFilter(contributorQueries: Seq[String])
extends WorkFilter
with ImageFilter
with Pairable

case class ContributorsConceptFilter(conceptIds: Seq[String])
extends WorkFilter
with ImageFilter

case class LicenseFilter(licenseIds: Seq[String])
extends WorkFilter
with ImageFilter
Expand Down
6 changes: 6 additions & 0 deletions search/src/main/scala/weco/api/search/rest/ImagesParams.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ case class MultipleImagesParams(
query: Option[String],
license: Option[LicenseFilter],
`source.contributors.agent.label`: Option[ContributorsFilter],
`source.contributors.concepts`: Option[ContributorsConceptFilter],
`source.genres.label`: Option[GenreFilter],
`source.genres.concepts`: Option[GenreConceptFilter],
`source.subjects.label`: Option[SubjectLabelFilter],
`source.subjects.concepts`: Option[SubjectConceptFilter],
`source.production.dates.from`: Option[LocalDate],
`source.production.dates.to`: Option[LocalDate],
color: Option[RgbColor],
Expand All @@ -73,9 +75,11 @@ case class MultipleImagesParams(
List(
license,
`source.contributors.agent.label`,
`source.contributors.concepts`,
`source.genres.label`,
`source.genres.concepts`,
`source.subjects.label`,
`source.subjects.concepts`,
dateFilter
).flatten

Expand All @@ -98,9 +102,11 @@ object MultipleImagesParams extends QueryParamsUtils {
"query".as[String].?,
"locations.license".as[LicenseFilter].?,
"source.contributors.agent.label".as[ContributorsFilter].?,
"source.contributors.concepts".as[ContributorsConceptFilter].?,
"source.genres.label".as[GenreFilter].?,
"source.genres.concepts".as[GenreConceptFilter].?,
"source.subjects.label".as[SubjectLabelFilter].?,
"source.subjects.concepts".as[SubjectConceptFilter].?,
"source.production.dates.from".as[LocalDate].?,
"source.production.dates.to".as[LocalDate].?,
"color".as[RgbColor].?,
Expand Down
9 changes: 9 additions & 0 deletions search/src/main/scala/weco/api/search/rest/QueryParams.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ import weco.api.search.rest.MultipleWorksParams.{
stringListFilter
}
import weco.api.search.models.{
ContributorsConceptFilter,
ContributorsFilter,
GenreConceptFilter,
GenreFilter,
LicenseFilter,
SubjectConceptFilter,
SubjectLabelFilter
}

Expand All @@ -38,6 +40,13 @@ object CommonDecoders {

implicit val subjectsFilter: Decoder[SubjectLabelFilter] =
stringListFilter(SubjectLabelFilter)

implicit val subjectsConceptFilter: Decoder[SubjectConceptFilter] =
stringListFilter(SubjectConceptFilter)

implicit val contributorsConceptFilter: Decoder[ContributorsConceptFilter] =
stringListFilter(ContributorsConceptFilter)

}

trait QueryParamsUtils extends Directives {
Expand Down
10 changes: 10 additions & 0 deletions search/src/main/scala/weco/api/search/rest/WorksParams.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ case class WorkFilterParams(
`genres.label`: Option[GenreFilter],
`genres.concepts`: Option[GenreConceptFilter],
`subjects.label`: Option[SubjectLabelFilter],
`subjects.concepts`: Option[SubjectConceptFilter],
`contributors.agent.label`: Option[ContributorsFilter],
`contributors.concepts`: Option[ContributorsConceptFilter],
identifiers: Option[IdentifiersFilter],
partOf: Option[PartOfFilter],
`partOf.title`: Option[PartOfTitleFilter],
Expand Down Expand Up @@ -120,7 +122,9 @@ case class MultipleWorksParams(
filterParams.`genres.label`,
filterParams.`genres.concepts`,
filterParams.`subjects.label`,
filterParams.`subjects.concepts`,
filterParams.`contributors.agent.label`,
filterParams.`contributors.concepts`,
filterParams.identifiers,
itemsParams.`items`,
itemsParams.`items.identifiers`,
Expand Down Expand Up @@ -202,7 +206,9 @@ object MultipleWorksParams extends QueryParamsUtils {
"genres.label".as[GenreFilter].?,
"genres.concepts".as[GenreConceptFilter].?,
"subjects.label".as[SubjectLabelFilter].?,
"subjects.concepts".as[SubjectConceptFilter].?,
"contributors.agent.label".as[ContributorsFilter].?,
"contributors.concepts".as[ContributorsConceptFilter].?,
"identifiers".as[IdentifiersFilter].?,
"partOf".as[PartOfFilter].?,
"partOf.title".as[PartOfTitleFilter].?,
Expand All @@ -217,7 +223,9 @@ object MultipleWorksParams extends QueryParamsUtils {
genres,
genreConcepts,
subjectLabels,
subjectConcepts,
contributors,
contributorsConcepts,
identifiers,
partOf,
partOfTitle,
Expand All @@ -232,7 +240,9 @@ object MultipleWorksParams extends QueryParamsUtils {
genres,
genreConcepts,
subjectLabels,
subjectConcepts,
contributors,
contributorsConcepts,
identifiers,
partOf,
partOfTitle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import com.sksamuel.elastic4s.ElasticDsl._
import com.sksamuel.elastic4s._
import com.sksamuel.elastic4s.requests.searches._
import com.sksamuel.elastic4s.requests.searches.aggs.TermsAggregation
import com.sksamuel.elastic4s.requests.searches.queries.{
NoopQuery,
Query,
RangeQuery
}
import com.sksamuel.elastic4s.requests.searches.queries.{Query, RangeQuery}
import com.sksamuel.elastic4s.requests.searches.sort._
import io.circe.{Json, JsonObject}
import weco.api.search.models.index.IndexedImage
Expand Down Expand Up @@ -54,10 +50,10 @@ class ImagesRequestBuilder()
searchOptions.searchQuery.isDefined || searchOptions.color.isDefined,
includes = Seq("display", "vectorValues.reducedFeatures"),
aggs = filteredAggregationBuilder(pairables).filteredAggregations,
preFilter = buildImageFilterQuery(unpairables),
preFilter = unpairables.collect(buildImageFilterQuery),
postFilter = Some(
must(
buildImageFilterQuery(searchOptions.filters)
searchOptions.filters.collect(buildImageFilterQuery)
)
),
knn = searchOptions.color.map(ColorQuery(_))
Expand Down Expand Up @@ -112,38 +108,52 @@ class ImagesRequestBuilder()
searchOptions.sortOrder
}

private def buildImageFilterQuery(filter: ImageFilter): Query =
filter match {
case LicenseFilter(licenseIds) =>
termsQuery(
field = "filterableValues.locations.license.id",
values = licenseIds
)
case ContributorsFilter(contributorQueries) =>
termsQuery(
"filterableValues.source.contributors.agent.label",
contributorQueries
)
case GenreFilter(genreLabels) =>
termsQuery("filterableValues.source.genres.label", genreLabels)
case GenreConceptFilter(conceptIds) =>
if (conceptIds.isEmpty) NoopQuery
else
termsQuery("filterableValues.source.genres.concepts.id", conceptIds)
case SubjectLabelFilter(subjectLabels) =>
termsQuery("filterableValues.source.subjects.label", subjectLabels)
case DateRangeFilter(fromDate, toDate) =>
val (gte, lte) =
(fromDate map ElasticDate.apply, toDate map ElasticDate.apply)
RangeQuery(
"filterableValues.source.production.dates.range.from",
lte = lte,
gte = gte
)
}
private val buildImageFilterQuery: PartialFunction[ImageFilter, Query] = {
case LicenseFilter(licenseIds) =>
termsQuery(
field = "filterableValues.locations.license.id",
values = licenseIds
)
case ContributorsFilter(contributorQueries) =>
termsQuery(
"filterableValues.source.contributors.agent.label",
contributorQueries
)
case ContributorsConceptFilter(conceptIds) =>
termsQuery(
"filterableValues.source.contributors.agent.id",
conceptIds
)
case GenreFilter(genreLabels) =>
termsQuery(
"filterableValues.source.genres.label",
genreLabels
)
case GenreConceptFilter(conceptIds) if conceptIds.nonEmpty =>
termsQuery(
"filterableValues.source.genres.concepts.id",
conceptIds
)
case SubjectLabelFilter(subjectLabels) =>
termsQuery(
"filterableValues.source.subjects.label",
subjectLabels
)
case SubjectConceptFilter(conceptIds) if conceptIds.nonEmpty =>
termsQuery(
"filterableValues.source.subjects.concepts.id",
conceptIds
)
case DateRangeFilter(fromDate, toDate) =>
val (gte, lte) =
(fromDate map ElasticDate.apply, toDate map ElasticDate.apply)

private def buildImageFilterQuery(filters: Seq[ImageFilter]): Seq[Query] =
filters.map(buildImageFilterQuery) filter (_ != NoopQuery)
RangeQuery(
"filterableValues.source.production.dates.range.from",
lte = lte,
gte = gte
)
}

def requestWithSimilarFeatures
: (Index, String, IndexedImage, Int, Double) => SearchRequest =
Expand Down
Loading

0 comments on commit a6b8dd0

Please sign in to comment.