From 43f2723213ed403a9f58d813d391ef26c961d909 Mon Sep 17 00:00:00 2001 From: Mikhail Khludnev Date: Sun, 27 Jan 2019 15:05:40 +0300 Subject: [PATCH] SOLR-13156: support facet.sort for facet.field={!terms=foo,bar}field --- solr/CHANGES.txt | 2 + .../org/apache/solr/request/SimpleFacets.java | 39 ++++++++++++++----- .../org/apache/solr/request/TestFaceting.java | 31 +++++++++++++++ solr/solr-ref-guide/src/faceting.adoc | 4 +- 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 4464c4c2b091..169081d25f3e 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -336,6 +336,8 @@ Improvements * SOLR-13029: solr.hdfs.buffer.size can be configured for HdfsBackupRepository for better performance (Tim Owen via Mikhail Khludnev) +* SOLR-13156: support facet.sort for facet.field={!terms=foo,bar}field. (Konstantin Perikov via Mikhail Khludnev) + Other Changes ---------------------- diff --git a/solr/core/src/java/org/apache/solr/request/SimpleFacets.java b/solr/core/src/java/org/apache/solr/request/SimpleFacets.java index 4608e2de8ab6..1bea80af07dd 100644 --- a/solr/core/src/java/org/apache/solr/request/SimpleFacets.java +++ b/solr/core/src/java/org/apache/solr/request/SimpleFacets.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -35,6 +36,7 @@ import java.util.concurrent.RunnableFuture; import java.util.concurrent.Semaphore; import java.util.function.Predicate; +import java.util.stream.Stream; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; @@ -861,22 +863,39 @@ public NamedList getFacetFieldCounts() } /** - * Computes the term->count counts for the specified term values relative to the + * Computes the term->count counts for the specified term values relative to the + * * @param field the name of the field to compute term counts against * @param parsed contains the docset to compute term counts relative to - * @param terms a list of term values (in the specified field) to compute the counts for + * @param terms a list of term values (in the specified field) to compute the counts for */ - protected NamedList getListedTermCounts(String field, final ParsedParams parsed, List terms) throws IOException { - SchemaField sf = searcher.getSchema().getField(field); - FieldType ft = sf.getType(); - NamedList res = new NamedList<>(); - for (String term : terms) { - int count = searcher.numDocs(ft.getFieldQuery(null, sf, term), parsed.docs); - res.add(term, count); + protected NamedList getListedTermCounts(String field, final ParsedParams parsed, List terms) + throws IOException { + final String sort = parsed.params.getFieldParam(field, FacetParams.FACET_SORT, "empty"); + final SchemaField sf = searcher.getSchema().getField(field); + final FieldType ft = sf.getType(); + final DocSet baseDocset = parsed.docs; + final NamedList res = new NamedList<>(); + Stream inputStream = terms.stream(); + if (sort.equals(FacetParams.FACET_SORT_INDEX)) { // it might always make sense + inputStream = inputStream.sorted(); + } + Stream> termCountEntries = inputStream + .map((term) -> new SimpleImmutableEntry<>(term, numDocs(term, sf, ft, baseDocset))); + if (sort.equals(FacetParams.FACET_SORT_COUNT)) { + termCountEntries = termCountEntries.sorted(Collections.reverseOrder(Map.Entry.comparingByValue())); } - return res; + termCountEntries.forEach(e -> res.add(e.getKey(), e.getValue())); + return res; } + private int numDocs(String term, final SchemaField sf, final FieldType ft, final DocSet baseDocset) { + try { + return searcher.numDocs(ft.getFieldQuery(null, sf, term), baseDocset); + } catch (IOException e1) { + throw new RuntimeException(e1); + } + } /** * Returns a count of the documents in the set which do not have any diff --git a/solr/core/src/test/org/apache/solr/request/TestFaceting.java b/solr/core/src/test/org/apache/solr/request/TestFaceting.java index 88de349d47d0..59b3a41c52c6 100644 --- a/solr/core/src/test/org/apache/solr/request/TestFaceting.java +++ b/solr/core/src/test/org/apache/solr/request/TestFaceting.java @@ -900,5 +900,36 @@ public void testMultiThreadedFacets() throws Exception { return null; }); } + + @Test + public void testListedTermCounts() throws Exception { + assertU(adoc("id", "1", "title_ws", "Book1")); + assertU(adoc("id", "2", "title_ws", "Book2")); + assertU(adoc("id", "3", "title_ws", "Book3")); + assertU(adoc("id", "4", "title_ws", "Book2")); + assertU(adoc("id", "5", "title_ws", "Book1")); + assertU(adoc("id", "6", "title_ws", "Book2")); + assertU(commit()); + + // order is the same as in facet.field, when no facet.sort specified + assertQ(req("q", "*:*", FacetParams.FACET, "true", FacetParams.FACET_FIELD, "{!terms=Book3,Book2,Book1}title_ws"), + "//lst[@name='facet_fields']/lst[@name='title_ws']/int[1][@name='Book3']", + "//lst[@name='facet_fields']/lst[@name='title_ws']/int[2][@name='Book2']", + "//lst[@name='facet_fields']/lst[@name='title_ws']/int[3][@name='Book1']"); + + // order is by counts, when facet.sort by count specified + assertQ(req("q", "*:*", FacetParams.FACET, "true", FacetParams.FACET_FIELD, "{!terms=Book3,Book2,Book1}title_ws", + "facet.sort", FacetParams.FACET_SORT_COUNT), + "//lst[@name='facet_fields']/lst[@name='title_ws']/int[1][@name='Book2']", + "//lst[@name='facet_fields']/lst[@name='title_ws']/int[2][@name='Book1']", + "//lst[@name='facet_fields']/lst[@name='title_ws']/int[3][@name='Book3']"); + + // order is by index, when facet.sort by index specified + assertQ(req("q", "*:*", FacetParams.FACET, "true", FacetParams.FACET_FIELD, "{!terms=Book3,Book2,Book1}title_ws", + "facet.sort", FacetParams.FACET_SORT_INDEX), + "//lst[@name='facet_fields']/lst[@name='title_ws']/int[1][@name='Book1']", + "//lst[@name='facet_fields']/lst[@name='title_ws']/int[2][@name='Book2']", + "//lst[@name='facet_fields']/lst[@name='title_ws']/int[3][@name='Book3']"); + } } diff --git a/solr/solr-ref-guide/src/faceting.adoc b/solr/solr-ref-guide/src/faceting.adoc index 4827db071b11..efbb0331c60a 100644 --- a/solr/solr-ref-guide/src/faceting.adoc +++ b/solr/solr-ref-guide/src/faceting.adoc @@ -79,7 +79,7 @@ There are two options for this parameter. `index`::: Return the constraints sorted in their index order (lexicographic by indexed term). For terms in the ASCII range, this will be alphabetically sorted. -- + -The default is `count` if `facet.limit` is greater than 0, otherwise, the default is `index`. +The default is `count` if `facet.limit` is greater than 0, otherwise, the default is `index`. Note that the default logic is changed when <<#limiting-facet-with-certain-terms>> `facet.limit`:: This parameter specifies the maximum number of constraint counts (essentially, the number of facets for a field that are returned) that should be returned for the facet fields. A negative value means that Solr will return unlimited number of constraint counts. @@ -616,7 +616,7 @@ To limit field facet with certain terms specify them comma separated with `terms `facet.field={!terms='alfa,betta,with\,with\',with space'}symbol` -This parameter disables sorting, facet values are returned in the given order. +This local parameter overrides default logic for `facet.sort`. if `facet.sort` is omitted, facets are returned in the given terms order that might be changed with `index` and `count` values. Note: other parameters might not be fully supported when this parameter is supplied. == Related Topics