Skip to content

Commit

Permalink
SOLR-17477: prototyping custom faceting via FacetModule extending
Browse files Browse the repository at this point in the history
  • Loading branch information
mkhludnev committed Nov 15, 2024
1 parent 0502e60 commit 64913d3
Show file tree
Hide file tree
Showing 16 changed files with 259 additions and 144 deletions.
43 changes: 18 additions & 25 deletions solr/core/src/java/org/apache/solr/handler/MoreLikeThisHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,6 @@
*/
package org.apache.solr.handler;

import java.io.IOException;
import java.io.Reader;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import net.jcip.annotations.NotThreadSafe;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.ExitableDirectoryReader;
Expand Down Expand Up @@ -58,25 +48,21 @@
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.search.DocIterator;
import org.apache.solr.search.DocList;
import org.apache.solr.search.DocListAndSet;
import org.apache.solr.search.QParser;
import org.apache.solr.search.QParserPlugin;
import org.apache.solr.search.QueryCommand;
import org.apache.solr.search.QueryLimits;
import org.apache.solr.search.QueryParsing;
import org.apache.solr.search.QueryUtils;
import org.apache.solr.search.ReturnFields;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.SolrReturnFields;
import org.apache.solr.search.SortSpec;
import org.apache.solr.search.SyntaxError;
import org.apache.solr.search.*;
import org.apache.solr.search.facet.FacetParserFactory;
import org.apache.solr.search.facet.FacetRequest;
import org.apache.solr.search.facet.OneFacetParser;
import org.apache.solr.security.AuthorizationContext;
import org.apache.solr.util.SolrPluginUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.Reader;
import java.lang.invoke.MethodHandles;
import java.util.*;
import java.util.regex.Pattern;

/**
* Solr MoreLikeThis --
*
Expand Down Expand Up @@ -224,7 +210,13 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw
final ResponseBuilder responseBuilder =
new ResponseBuilder(req, rsp, Collections.emptyList());
responseBuilder.setQuery(mlt.getRealMLTQuery());
SimpleFacets f = new SimpleFacets(req, mltDocs.docSet, params, responseBuilder);
SimpleFacets f = new SimpleFacets(req, mltDocs.docSet, params, responseBuilder){
@Override
public FacetRequest parseOneFacetReq(SolrQueryRequest req, Map<String, Object> jsonFacet) {
OneFacetParser facetRequestFactory = new FacetParserFactory();
return facetRequestFactory.parseOneFacetReq(req, jsonFacet);
}
};
FacetComponent.FacetContext.initContext(responseBuilder);
rsp.add("facet_counts", FacetComponent.getFacetCounts(f));
}
Expand Down Expand Up @@ -275,6 +267,7 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw
}
}


@Override
public Name getPermissionName(AuthorizationContext request) {
return Name.READ_PERM;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@
import org.apache.solr.search.QueryLimits;
import org.apache.solr.search.QueryParsing;
import org.apache.solr.search.SyntaxError;
import org.apache.solr.search.facet.AbstractFacetComponent;
import org.apache.solr.search.facet.FacetDebugInfo;
import org.apache.solr.search.facet.FacetRequest;
import org.apache.solr.search.facet.OneFacetParser;
import org.apache.solr.util.RTimer;
import org.apache.solr.util.SolrResponseUtil;
import org.slf4j.Logger;
Expand All @@ -62,7 +65,7 @@
*
* @since solr 1.3
*/
public class FacetComponent extends SearchComponent {
public class FacetComponent extends AbstractFacetComponent {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

public static final String COMPONENT_NAME = "facet";
Expand Down Expand Up @@ -107,7 +110,13 @@ public void prepare(ResponseBuilder rb) throws IOException {
/* Custom facet components can return a custom SimpleFacets object */
protected SimpleFacets newSimpleFacets(
SolrQueryRequest req, DocSet docSet, SolrParams params, ResponseBuilder rb) {
return new SimpleFacets(req, docSet, params, rb);
return new SimpleFacets(req, docSet, params, rb) {
@Override
public FacetRequest parseOneFacetReq(SolrQueryRequest req, Map<String, Object> jsonFacet) {
OneFacetParser facetRequestFactory = createFacetRequestFactory(req, jsonFacet);
return facetRequestFactory.parseOneFacetReq(req, jsonFacet);
}
};
}

/**
Expand Down Expand Up @@ -284,7 +293,13 @@ public void process(ResponseBuilder rb) throws IOException {
String[] pivots = params.getParams(FacetParams.FACET_PIVOT);
if (pivots != null && Array.getLength(pivots) != 0) {
PivotFacetProcessor pivotProcessor =
new PivotFacetProcessor(rb.req, rb.getResults().docSet, params, rb);
new PivotFacetProcessor(rb.req, rb.getResults().docSet, params, rb) {
@Override
public FacetRequest parseOneFacetReq(SolrQueryRequest req, Map<String, Object> jsonFacet) {
OneFacetParser facetRequestFactory = createFacetRequestFactory(req, jsonFacet);
return facetRequestFactory.parseOneFacetReq(req, jsonFacet);
}
};
SimpleOrderedMap<List<NamedList<Object>>> v = pivotProcessor.process(pivots);
if (v != null) {
counts.add(PIVOT_KEY, v);
Expand All @@ -311,7 +326,6 @@ public static NamedList<Object> getFacetCounts(SimpleFacets simpleFacets) {
*
* @see SimpleFacets#getFacetQueryCounts
* @see SimpleFacets#getFacetFieldCounts
* @see RangeFacetProcessor#getFacetRangeCounts
* @see RangeFacetProcessor#getFacetIntervalCounts
* @see FacetParams#FACET
* @return a NamedList of Facet Count info or null
Expand All @@ -325,7 +339,13 @@ public static NamedList<Object> getFacetCounts(SimpleFacets simpleFacets, FacetD
simpleFacets.getRequest(),
simpleFacets.getDocsOrig(),
simpleFacets.getGlobalParams(),
simpleFacets.getResponseBuilder());
simpleFacets.getResponseBuilder()) {

@Override
public FacetRequest parseOneFacetReq(SolrQueryRequest req, Map<String, Object> jsonFacet) {
return simpleFacets.parseOneFacetReq(req,jsonFacet);
}
};
NamedList<Object> counts = new SimpleOrderedMap<>();
try {
counts.add(FACET_QUERY_KEY, simpleFacets.getFacetQueryCounts());
Expand Down Expand Up @@ -540,7 +560,7 @@ public void modifyRequest(ResponseBuilder rb, SearchComponent who, ShardRequest

FacetInfo fi = rb._facetInfo;
if (fi == null) {
rb._facetInfo = fi = new FacetInfo();
rb._facetInfo = fi = new FacetInfo(createFacetRequestFactory(rb.req, null));
fi.parse(rb.req.getParams(), rb);
}

Expand Down Expand Up @@ -1246,6 +1266,7 @@ public Category getCategory() {
* @see org.apache.solr.handler.component.FacetComponent.FacetContext
*/
public static class FacetInfo {
private final OneFacetParser facetRequestFactory;
/**
* Incremented counter used to track the values being refined in a given request. This counter
* is used in conjunction with {@link PivotFacet#REFINE_PARAM} to identify which refinement
Expand All @@ -1262,6 +1283,10 @@ public static class FacetInfo {
public SimpleOrderedMap<PivotFacet> pivotFacets = new SimpleOrderedMap<>();
public LinkedHashMap<String, SpatialHeatmapFacets.HeatmapFacet> heatmapFacets;

public FacetInfo(OneFacetParser facetRequestFactory) {
this.facetRequestFactory = facetRequestFactory;
}

void parse(SolrParams params, ResponseBuilder rb) {
queryFacets = new LinkedHashMap<>();
facets = new LinkedHashMap<>();
Expand Down Expand Up @@ -1299,7 +1324,7 @@ void parse(SolrParams params, ResponseBuilder rb) {
}
}

heatmapFacets = SpatialHeatmapFacets.distribParse(params, rb);
heatmapFacets = SpatialHeatmapFacets.distribParse(this.facetRequestFactory, params, rb);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@
import org.apache.solr.search.DocSet;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.SyntaxError;
import org.apache.solr.search.facet.FacetParserFactory;
import org.apache.solr.search.facet.FacetRequest;
import org.apache.solr.util.PivotListEntry;

/** Processes all Pivot facet logic for a single node -- both non-distrib, and per-shard */
public class PivotFacetProcessor extends SimpleFacets {
public abstract class PivotFacetProcessor extends SimpleFacets {
public static final String QUERY = "query";
public static final String RANGE = "range";
protected SolrParams params;
Expand Down Expand Up @@ -446,7 +448,7 @@ protected void addPivotQueriesAndRanges(
assert null != facetRanges;

if (!facetQueries.isEmpty()) {
SimpleFacets facets = new SimpleFacets(req, docs, params);
SimpleFacets facets = newSimpleFacets(req, docs);
NamedList<Integer> res = new SimpleOrderedMap<>();
for (FacetComponent.FacetBase facetQuery : facetQueries) {
try {
Expand All @@ -467,7 +469,13 @@ protected void addPivotQueriesAndRanges(
pivot.add(PivotListEntry.QUERIES.getName(), res);
}
if (!facetRanges.isEmpty()) {
RangeFacetProcessor rangeFacetProcessor = new RangeFacetProcessor(req, docs, params, null);
RangeFacetProcessor rangeFacetProcessor = new RangeFacetProcessor(req, docs, params, null){

@Override
public FacetRequest parseOneFacetReq(SolrQueryRequest req, Map<String, Object> jsonFacet) {
return PivotFacetProcessor.this.parseOneFacetReq(req,jsonFacet);
}
};
NamedList<Object> resOuter = new SimpleOrderedMap<>();
for (RangeFacetRequest rangeFacet : facetRanges) {
try {
Expand All @@ -488,6 +496,16 @@ protected void addPivotQueriesAndRanges(
}
}

protected SimpleFacets newSimpleFacets(
SolrQueryRequest req, DocSet docSet) {
return new SimpleFacets(req, docSet, req.getParams()) {
@Override
public FacetRequest parseOneFacetReq(SolrQueryRequest req, Map<String, Object> jsonFacet) {
return PivotFacetProcessor.this.parseOneFacetReq(req, jsonFacet);
}
};
}

private ParsedParams getParsedParams(
SolrParams params, DocSet docs, FacetComponent.FacetBase facet) {
SolrParams wrapped = SolrParams.wrapDefaults(facet.localParams, global);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
import org.apache.solr.search.SyntaxError;

/** Processor for Range Facets */
public class RangeFacetProcessor extends SimpleFacets {
public abstract class RangeFacetProcessor extends SimpleFacets {

public RangeFacetProcessor(
SolrQueryRequest req, DocSet docs, SolrParams params, ResponseBuilder rb) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.request.SimpleFacets;
import org.apache.solr.search.DocSet;
import org.apache.solr.search.facet.FacetHeatmap;
import org.apache.solr.search.facet.FacetMerger;
import org.apache.solr.search.facet.FacetRequest;
import org.apache.solr.search.facet.OneFacetParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -49,14 +51,14 @@ public class SpatialHeatmapFacets {
/** Called by {@link org.apache.solr.request.SimpleFacets} to compute heatmap facets. */
@SuppressWarnings("unchecked")
public static NamedList<Object> getHeatmapForField(
String fieldKey, String fieldName, ResponseBuilder rb, SolrParams params, DocSet docSet)
SimpleFacets simpleFacets, String fieldKey, String fieldName, ResponseBuilder rb, SolrParams params, DocSet docSet)
throws IOException {
final FacetRequest facetRequest = createHeatmapRequest(fieldKey, fieldName, rb, params);
final FacetRequest facetRequest = createHeatmapRequest(simpleFacets, fieldKey, fieldName, rb, params);
return (NamedList<Object>) facetRequest.process(rb.req, docSet);
}

private static FacetRequest createHeatmapRequest(
String fieldKey, String fieldName, ResponseBuilder rb, SolrParams params) {
OneFacetParser simpleFacets, String fieldKey, String fieldName, ResponseBuilder rb, SolrParams params) {
Map<String, Object> jsonFacet = new HashMap<>();
jsonFacet.put("type", "heatmap");
jsonFacet.put("field", fieldName);
Expand All @@ -78,7 +80,7 @@ private static FacetRequest createHeatmapRequest(
FacetHeatmap.FORMAT_PARAM,
params.getFieldParam(fieldKey, FacetParams.FACET_HEATMAP_FORMAT));

return FacetRequest.parseOneFacetReq(rb.req, jsonFacet);
return simpleFacets.parseOneFacetReq(rb.req, jsonFacet);
}

//
Expand All @@ -87,12 +89,12 @@ private static FacetRequest createHeatmapRequest(

/** Parses request to "HeatmapFacet" instances. */
public static LinkedHashMap<String, HeatmapFacet> distribParse(
SolrParams params, ResponseBuilder rb) {
OneFacetParser facetRequestFactory, SolrParams params, ResponseBuilder rb) {
final LinkedHashMap<String, HeatmapFacet> heatmapFacets = new LinkedHashMap<>();
final String[] heatmapFields = params.getParams(FacetParams.FACET_HEATMAP);
if (heatmapFields != null) {
for (String heatmapField : heatmapFields) {
HeatmapFacet facet = new HeatmapFacet(rb, heatmapField);
HeatmapFacet facet = new HeatmapFacet(facetRequestFactory, rb, heatmapField);
heatmapFacets.put(facet.getKey(), facet);
}
}
Expand Down Expand Up @@ -168,19 +170,19 @@ public static NamedList<NamedList<Object>> distribFinish(

/**
* Goes in {@link org.apache.solr.handler.component.FacetComponent.FacetInfo#heatmapFacets},
* created by {@link #distribParse(org.apache.solr.common.params.SolrParams, ResponseBuilder)}.
* created by {@link #distribParse(OneFacetParser, SolrParams, ResponseBuilder)}.
*/
public static class HeatmapFacet extends FacetComponent.FacetBase {
// note: 'public' following-suit with FacetBase & existing subclasses... though should this
// really be?

public FacetMerger jsonFacetMerger;

public HeatmapFacet(ResponseBuilder rb, String facetStr) {
public HeatmapFacet(OneFacetParser facetRequestFactory, ResponseBuilder rb, String facetStr) {
super(rb, FacetParams.FACET_HEATMAP, facetStr);
// note: logic in super (FacetBase) is partially redundant with SimpleFacet.parseParams :-(
final SolrParams params = SolrParams.wrapDefaults(localParams, rb.req.getParams());
final FacetRequest heatmapRequest = createHeatmapRequest(getKey(), facetOn, rb, params);
final FacetRequest heatmapRequest = createHeatmapRequest(facetRequestFactory, getKey(), facetOn, rb, params);
jsonFacetMerger = heatmapRequest.createFacetMerger(null);
}
}
Expand Down
10 changes: 7 additions & 3 deletions solr/core/src/java/org/apache/solr/request/SimpleFacets.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.SyntaxError;
import org.apache.solr.search.facet.FacetDebugInfo;
import org.apache.solr.search.facet.FacetParserFactory;
import org.apache.solr.search.facet.FacetRequest;
import org.apache.solr.search.facet.OneFacetParser;
import org.apache.solr.search.grouping.GroupingSpecification;
import org.apache.solr.util.BoundedTreeSet;
import org.apache.solr.util.RTimer;
Expand All @@ -104,7 +106,7 @@
* <p>More advanced facet implementations may compose or subclass this class to leverage any of its
* functionality.
*/
public class SimpleFacets {
public abstract class SimpleFacets implements OneFacetParser {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

/** The main set of documents all facet counts should be relative to */
Expand Down Expand Up @@ -627,7 +629,7 @@ private NamedList<Integer> getTermCounts(String field, Integer mincount, ParsedP

// TODO do we handle debug? Should probably already be handled by the legacy code

Object resObj = FacetRequest.parseOneFacetReq(req, jsonFacet).process(req, docs);
Object resObj = parseOneFacetReq(req, jsonFacet).process(req, docs);
// Go through the response to build the expected output for SimpleFacets
counts = new NamedList<>();
if (resObj != null) {
Expand Down Expand Up @@ -674,6 +676,8 @@ private NamedList<Integer> getTermCounts(String field, Integer mincount, ParsedP
return counts;
}

public abstract FacetRequest parseOneFacetReq(SolrQueryRequest req, Map<String, Object> jsonFacet) ;

/**
* @param existsRequested facet.exists=true is passed for the given field
*/
Expand Down Expand Up @@ -1362,7 +1366,7 @@ public NamedList<Object> getHeatmapCounts() throws IOException, SyntaxError {

resOuter.add(
parsed.key,
SpatialHeatmapFacets.getHeatmapForField(
SpatialHeatmapFacets.getHeatmapForField(this,
parsed.key, parsed.facetValue, rb, parsed.params, parsed.docs));
}
return resOuter;
Expand Down
Loading

0 comments on commit 64913d3

Please sign in to comment.