diff --git a/rest/src/main/groovy/whelk/rest/api/SearchUtils.groovy b/rest/src/main/groovy/whelk/rest/api/SearchUtils.groovy index 3e8654c063..56f0dbbb0b 100644 --- a/rest/src/main/groovy/whelk/rest/api/SearchUtils.groovy +++ b/rest/src/main/groovy/whelk/rest/api/SearchUtils.groovy @@ -8,7 +8,6 @@ import groovy.util.logging.Log4j2 as Log import whelk.Document import whelk.JsonLd import whelk.Whelk -import whelk.component.DocumentNormalizer import whelk.exception.InvalidQueryException import whelk.exception.WhelkRuntimeException import whelk.search.ESQuery @@ -831,6 +830,9 @@ class SearchUtils { int limit = slice['itemLimit'] def connective = slice['connective']?.equals(OR.toString()) ? OR : AND statsfind[key] = ['sort': 'value', 'sortOrder': 'desc', 'size': limit, 'connective': connective] + if (slice['_matchMissing']) { // FIXME: what should it be called? + statsfind[key]['_matchMissing'] = slice['_matchMissing'] + } } return statsfind } diff --git a/whelk-core/src/main/groovy/whelk/search/ESQuery.groovy b/whelk-core/src/main/groovy/whelk/search/ESQuery.groovy index f3cfd8dfcd..cbd2878e44 100644 --- a/whelk-core/src/main/groovy/whelk/search/ESQuery.groovy +++ b/whelk-core/src/main/groovy/whelk/search/ESQuery.groovy @@ -559,14 +559,14 @@ class ESQuery { } Set multiSelectable = multiSelectFacets(queryParameters) + Map matchMissing = matchMissing(queryParameters) getOrGroups(notNested).each { Map m -> if (m.size() == 1 && m.keySet().first() in multiSelectable) { - multiSelectFilters[m.keySet().first()] = createBoolFilter(m) + multiSelectFilters[m.keySet().first()] = createBoolFilter(addMissingMatch(m, matchMissing)) } else { - filters << createBoolFilter(m) + filters << createBoolFilter(addMissingMatch(m, matchMissing)) } - } notNestedGroupsForNot.each { m -> filtersForNot << createBoolFilter(m) @@ -583,6 +583,14 @@ class ESQuery { return new Tuple2(allFilters ? [['bool': allFilters]] : null, multiSelectFilters) } + private static Map addMissingMatch(Map m, Map matchMissing) { + if (m.size() == 1 && m.keySet().first() in matchMissing) { + String field = matchMissing[m.keySet().first()] + m.put(EXISTS_PREFIX + field, ['false']) + } + return m + } + private getPrefixIfExists(String key) { if (key.contains('.')) { return key.substring(0, key.indexOf('.')) @@ -642,6 +650,7 @@ class ESQuery { if (p.size() > 0) { result.add(p) } + return result } @@ -836,6 +845,13 @@ class ESQuery { } as Set } + @CompileStatic(TypeCheckingMode.SKIP) + static Map matchMissing(Map queryParameters) { + getStatsRepr(queryParameters) + .findAll { key, value -> value['_matchMissing'] } + .collectEntries { key, value -> [key, value['_matchMissing'] as String]} + } + @CompileStatic(TypeCheckingMode.SKIP) private static Map getStatsRepr(Map queryParameters) { mapper.readValue(queryParameters.get('_statsrepr')?[0] ?: '{}', Map)