1717package org .apache .solr .response .transform ;
1818
1919import java .io .IOException ;
20+ import java .util .Arrays ;
2021import java .util .List ;
2122import java .util .Map ;
2223import org .apache .lucene .index .LeafReaderContext ;
2324import org .apache .lucene .index .ReaderUtil ;
25+ import org .apache .lucene .internal .hppc .IntObjectHashMap ;
2426import org .apache .lucene .queries .function .FunctionValues ;
2527import org .apache .lucene .queries .function .ValueSource ;
2628import org .apache .solr .common .SolrDocument ;
3840 * @since solr 4.0
3941 */
4042public class ValueSourceAugmenter extends DocTransformer {
43+ private static final Object NULL_SENTINEL = new Object ();
4144 public final String name ;
4245 public final QParser qparser ;
4346 public final ValueSource valueSource ;
47+ private final int maxPrefetchSize ;
4448
4549 public ValueSourceAugmenter (String name , QParser qparser , ValueSource valueSource ) {
4650 this .name = name ;
4751 this .qparser = qparser ;
4852 this .valueSource = valueSource ;
53+ String maxPrefetchSizeRaw = qparser .getParam ("preFetchDocs" );
54+ this .maxPrefetchSize = maxPrefetchSizeRaw != null ? Integer .parseInt (maxPrefetchSizeRaw ) : 1000 ;
4955 }
5056
5157 @ Override
@@ -61,32 +67,66 @@ public void setContext(ResultContext context) {
6167 readerContexts = searcher .getIndexReader ().leaves ();
6268 fcontext = ValueSource .newContext (searcher );
6369 this .valueSource .createWeight (fcontext , searcher );
70+ final var docList = context .getDocList ();
71+ if (docList == null ) {
72+ return ;
73+ }
74+
75+ final int prefetchSize = Math .min (docList .size (), maxPrefetchSize );
76+ final int [] ids = new int [prefetchSize ];
77+ int i = 0 ;
78+ var iter = docList .iterator ();
79+ while (iter .hasNext () && i < prefetchSize ) {
80+ ids [i ++] = iter .nextDoc ();
81+ }
82+ Arrays .sort (ids );
83+ cachedValuesById = new IntObjectHashMap <>(ids .length );
84+
85+ FunctionValues values = null ;
86+ int docBase = -1 ;
87+ int currentIdx = -1 ;
88+ for (int docid : ids ) {
89+ int idx = ReaderUtil .subIndex (docid , readerContexts );
90+ if (currentIdx != idx ) {
91+ currentIdx = idx ;
92+ LeafReaderContext rcontext = readerContexts .get (idx );
93+ docBase = rcontext .docBase ;
94+ values = valueSource .getValues (fcontext , rcontext );
95+ }
96+ int localId = docid - docBase ;
97+ var value = values .objectVal (localId );
98+ cachedValuesById .put (docid , value != null ? value : NULL_SENTINEL );
99+ }
64100 } catch (IOException e ) {
65- throw new SolrException (SolrException .ErrorCode .SERVER_ERROR , e );
101+ throw new SolrException (
102+ SolrException .ErrorCode .SERVER_ERROR , "exception for valuesource " + valueSource , e );
66103 }
67104 }
68105
69106 Map <Object , Object > fcontext ;
70107 SolrIndexSearcher searcher ;
71108 List <LeafReaderContext > readerContexts ;
109+ IntObjectHashMap <Object > cachedValuesById ;
72110
73111 @ Override
74- public void transform (SolrDocument doc , int docid , DocIterationInfo docInfo ) {
75- // This is only good for random-access functions
76-
77- try {
78-
79- // TODO: calculate this stuff just once across diff functions
80- int idx = ReaderUtil .subIndex (docid , readerContexts );
81- LeafReaderContext rcontext = readerContexts .get (idx );
82- FunctionValues values = valueSource .getValues (fcontext , rcontext );
83- int localId = docid - rcontext .docBase ;
84- setValue (doc , values .objectVal (localId ));
85- } catch (IOException e ) {
86- throw new SolrException (
87- SolrException .ErrorCode .SERVER_ERROR ,
88- "exception at docid " + docid + " for valuesource " + valueSource ,
89- e );
112+ public void transform (SolrDocument doc , int docid , DocIterationInfo docIterationInfo ) {
113+ Object cacheValue = (cachedValuesById != null ) ? cachedValuesById .get (docid ) : null ;
114+ if (cacheValue != null ) {
115+ setValue (doc , cacheValue != NULL_SENTINEL ? cacheValue : null );
116+ } else {
117+ // Fallback to on-demand calculation for documents not in the pre-calculated set, RTG use case
118+ try {
119+ int idx = ReaderUtil .subIndex (docid , readerContexts );
120+ LeafReaderContext rcontext = readerContexts .get (idx );
121+ FunctionValues values = valueSource .getValues (fcontext , rcontext );
122+ int localId = docid - rcontext .docBase ;
123+ setValue (doc , values .objectVal (localId ));
124+ } catch (IOException e ) {
125+ throw new SolrException (
126+ SolrException .ErrorCode .SERVER_ERROR ,
127+ "exception at docid " + docid + " for valuesource " + valueSource ,
128+ e );
129+ }
90130 }
91131 }
92132
0 commit comments