mirror of https://github.com/apache/lucene.git
SOLR-9897: re-indent UnifiedSolrHighlighter.java
This commit is contained in:
parent
9d606d8ff0
commit
9bd152804d
|
@ -110,256 +110,256 @@ import org.apache.solr.util.plugin.PluginInfoInitialized;
|
|||
*/
|
||||
public class UnifiedSolrHighlighter extends SolrHighlighter implements PluginInfoInitialized {
|
||||
|
||||
protected static final String SNIPPET_SEPARATOR = "\u0000";
|
||||
private static final String[] ZERO_LEN_STR_ARRAY = new String[0];
|
||||
protected static final String SNIPPET_SEPARATOR = "\u0000";
|
||||
private static final String[] ZERO_LEN_STR_ARRAY = new String[0];
|
||||
|
||||
@Override
|
||||
public void init(PluginInfo info) {
|
||||
@Override
|
||||
public void init(PluginInfo info) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedList<Object> doHighlighting(DocList docs, Query query, SolrQueryRequest req, String[] defaultFields) throws IOException {
|
||||
final SolrParams params = req.getParams();
|
||||
|
||||
// if highlighting isn't enabled, then why call doHighlighting?
|
||||
if (!isHighlightingEnabled(params))
|
||||
return null;
|
||||
|
||||
int[] docIDs = toDocIDs(docs);
|
||||
|
||||
// fetch the unique keys
|
||||
String[] keys = getUniqueKeys(req.getSearcher(), docIDs);
|
||||
|
||||
// query-time parameters
|
||||
String[] fieldNames = getHighlightFields(query, req, defaultFields);
|
||||
|
||||
int maxPassages[] = new int[fieldNames.length];
|
||||
for (int i = 0; i < fieldNames.length; i++) {
|
||||
maxPassages[i] = params.getFieldInt(fieldNames[i], HighlightParams.SNIPPETS, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedList<Object> doHighlighting(DocList docs, Query query, SolrQueryRequest req, String[] defaultFields) throws IOException {
|
||||
final SolrParams params = req.getParams();
|
||||
UnifiedHighlighter highlighter = getHighlighter(req);
|
||||
Map<String, String[]> snippets = highlighter.highlightFields(fieldNames, query, docIDs, maxPassages);
|
||||
return encodeSnippets(keys, fieldNames, snippets);
|
||||
}
|
||||
|
||||
// if highlighting isn't enabled, then why call doHighlighting?
|
||||
if (!isHighlightingEnabled(params))
|
||||
return null;
|
||||
/**
|
||||
* Creates an instance of the Lucene {@link UnifiedHighlighter}. Provided for subclass extension so that
|
||||
* a subclass can return a subclass of {@link SolrExtendedUnifiedHighlighter}.
|
||||
*/
|
||||
protected UnifiedHighlighter getHighlighter(SolrQueryRequest req) {
|
||||
return new SolrExtendedUnifiedHighlighter(req);
|
||||
}
|
||||
|
||||
int[] docIDs = toDocIDs(docs);
|
||||
|
||||
// fetch the unique keys
|
||||
String[] keys = getUniqueKeys(req.getSearcher(), docIDs);
|
||||
|
||||
// query-time parameters
|
||||
String[] fieldNames = getHighlightFields(query, req, defaultFields);
|
||||
|
||||
int maxPassages[] = new int[fieldNames.length];
|
||||
for (int i = 0; i < fieldNames.length; i++) {
|
||||
maxPassages[i] = params.getFieldInt(fieldNames[i], HighlightParams.SNIPPETS, 1);
|
||||
}
|
||||
|
||||
UnifiedHighlighter highlighter = getHighlighter(req);
|
||||
Map<String, String[]> snippets = highlighter.highlightFields(fieldNames, query, docIDs, maxPassages);
|
||||
return encodeSnippets(keys, fieldNames, snippets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of the Lucene {@link UnifiedHighlighter}. Provided for subclass extension so that
|
||||
* a subclass can return a subclass of {@link SolrExtendedUnifiedHighlighter}.
|
||||
*/
|
||||
protected UnifiedHighlighter getHighlighter(SolrQueryRequest req) {
|
||||
return new SolrExtendedUnifiedHighlighter(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the resulting snippets into a namedlist
|
||||
*
|
||||
* @param keys the document unique keys
|
||||
* @param fieldNames field names to highlight in the order
|
||||
* @param snippets map from field name to snippet array for the docs
|
||||
* @return encoded namedlist of summaries
|
||||
*/
|
||||
protected NamedList<Object> encodeSnippets(String[] keys, String[] fieldNames, Map<String, String[]> snippets) {
|
||||
NamedList<Object> list = new SimpleOrderedMap<>();
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
NamedList<Object> summary = new SimpleOrderedMap<>();
|
||||
for (String field : fieldNames) {
|
||||
String snippet = snippets.get(field)[i];
|
||||
if (snippet == null) {
|
||||
//TODO reuse logic of DefaultSolrHighlighter.alternateField
|
||||
summary.add(field, ZERO_LEN_STR_ARRAY);
|
||||
} else {
|
||||
// we used a special snippet separator char and we can now split on it.
|
||||
summary.add(field, snippet.split(SNIPPET_SEPARATOR));
|
||||
}
|
||||
}
|
||||
list.add(keys[i], summary);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts solr's DocList to the int[] docIDs
|
||||
*/
|
||||
protected int[] toDocIDs(DocList docs) {
|
||||
int[] docIDs = new int[docs.size()];
|
||||
DocIterator iterator = docs.iterator();
|
||||
for (int i = 0; i < docIDs.length; i++) {
|
||||
if (!iterator.hasNext()) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
docIDs[i] = iterator.nextDoc();
|
||||
}
|
||||
if (iterator.hasNext()) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
return docIDs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the unique keys for the topdocs to key the results
|
||||
*/
|
||||
protected String[] getUniqueKeys(SolrIndexSearcher searcher, int[] docIDs) throws IOException {
|
||||
IndexSchema schema = searcher.getSchema();
|
||||
SchemaField keyField = schema.getUniqueKeyField();
|
||||
if (keyField != null) {
|
||||
Set<String> selector = Collections.singleton(keyField.getName());
|
||||
String[] uniqueKeys = new String[docIDs.length];
|
||||
for (int i = 0; i < docIDs.length; i++) {
|
||||
int docid = docIDs[i];
|
||||
Document doc = searcher.doc(docid, selector);
|
||||
String id = schema.printableUniqueKey(doc);
|
||||
uniqueKeys[i] = id;
|
||||
}
|
||||
return uniqueKeys;
|
||||
/**
|
||||
* Encodes the resulting snippets into a namedlist
|
||||
*
|
||||
* @param keys the document unique keys
|
||||
* @param fieldNames field names to highlight in the order
|
||||
* @param snippets map from field name to snippet array for the docs
|
||||
* @return encoded namedlist of summaries
|
||||
*/
|
||||
protected NamedList<Object> encodeSnippets(String[] keys, String[] fieldNames, Map<String, String[]> snippets) {
|
||||
NamedList<Object> list = new SimpleOrderedMap<>();
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
NamedList<Object> summary = new SimpleOrderedMap<>();
|
||||
for (String field : fieldNames) {
|
||||
String snippet = snippets.get(field)[i];
|
||||
if (snippet == null) {
|
||||
//TODO reuse logic of DefaultSolrHighlighter.alternateField
|
||||
summary.add(field, ZERO_LEN_STR_ARRAY);
|
||||
} else {
|
||||
return new String[docIDs.length];
|
||||
// we used a special snippet separator char and we can now split on it.
|
||||
summary.add(field, snippet.split(SNIPPET_SEPARATOR));
|
||||
}
|
||||
}
|
||||
list.add(keys[i], summary);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts solr's DocList to the int[] docIDs
|
||||
*/
|
||||
protected int[] toDocIDs(DocList docs) {
|
||||
int[] docIDs = new int[docs.size()];
|
||||
DocIterator iterator = docs.iterator();
|
||||
for (int i = 0; i < docIDs.length; i++) {
|
||||
if (!iterator.hasNext()) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
docIDs[i] = iterator.nextDoc();
|
||||
}
|
||||
if (iterator.hasNext()) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
return docIDs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the unique keys for the topdocs to key the results
|
||||
*/
|
||||
protected String[] getUniqueKeys(SolrIndexSearcher searcher, int[] docIDs) throws IOException {
|
||||
IndexSchema schema = searcher.getSchema();
|
||||
SchemaField keyField = schema.getUniqueKeyField();
|
||||
if (keyField != null) {
|
||||
Set<String> selector = Collections.singleton(keyField.getName());
|
||||
String[] uniqueKeys = new String[docIDs.length];
|
||||
for (int i = 0; i < docIDs.length; i++) {
|
||||
int docid = docIDs[i];
|
||||
Document doc = searcher.doc(docid, selector);
|
||||
String id = schema.printableUniqueKey(doc);
|
||||
uniqueKeys[i] = id;
|
||||
}
|
||||
return uniqueKeys;
|
||||
} else {
|
||||
return new String[docIDs.length];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* From {@link #getHighlighter(org.apache.solr.request.SolrQueryRequest)}.
|
||||
*/
|
||||
protected static class SolrExtendedUnifiedHighlighter extends UnifiedHighlighter {
|
||||
protected final SolrParams params;
|
||||
protected final IndexSchema schema;
|
||||
|
||||
protected final RTimerTree loadFieldValuesTimer;
|
||||
|
||||
public SolrExtendedUnifiedHighlighter(SolrQueryRequest req) {
|
||||
super(req.getSearcher(), req.getSchema().getIndexAnalyzer());
|
||||
this.params = req.getParams();
|
||||
this.schema = req.getSchema();
|
||||
this.setMaxLength(
|
||||
params.getInt(HighlightParams.MAX_CHARS, UnifiedHighlighter.DEFAULT_MAX_LENGTH));
|
||||
this.setCacheFieldValCharsThreshold(
|
||||
params.getInt(HighlightParams.CACHE_FIELD_VAL_CHARS_THRESHOLD, DEFAULT_CACHE_CHARS_THRESHOLD));
|
||||
|
||||
// SolrRequestInfo is a thread-local singleton providing access to the ResponseBuilder to code that
|
||||
// otherwise can't get it in a nicer way.
|
||||
SolrQueryRequest request = SolrRequestInfo.getRequestInfo().getReq();
|
||||
final RTimerTree timerTree;
|
||||
if (request.getRequestTimer() != null) { //It may be null if not used in a search context.
|
||||
timerTree = request.getRequestTimer();
|
||||
} else {
|
||||
timerTree = new RTimerTree(); // since null checks are annoying
|
||||
}
|
||||
loadFieldValuesTimer = timerTree.sub("loadFieldValues"); // we assume a new timer, state of STARTED
|
||||
loadFieldValuesTimer.pause(); // state of PAUSED now with about zero time. Will fail if state isn't STARTED.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OffsetSource getOffsetSource(String field) {
|
||||
String sourceStr = params.getFieldParam(field, HighlightParams.OFFSET_SOURCE);
|
||||
if (sourceStr != null) {
|
||||
return OffsetSource.valueOf(sourceStr.toUpperCase(Locale.ROOT));
|
||||
} else {
|
||||
return super.getOffsetSource(field);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxNoHighlightPassages(String field) {
|
||||
boolean defaultSummary = params.getFieldBool(field, HighlightParams.DEFAULT_SUMMARY, false);
|
||||
if (defaultSummary) {
|
||||
return -1;// signifies return first hl.snippets passages worth of the content
|
||||
} else {
|
||||
return 0;// will return null
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PassageFormatter getFormatter(String fieldName) {
|
||||
String preTag = params.getFieldParam(fieldName, HighlightParams.TAG_PRE,
|
||||
params.getFieldParam(fieldName, HighlightParams.SIMPLE_PRE, "<em>")
|
||||
);
|
||||
|
||||
String postTag = params.getFieldParam(fieldName, HighlightParams.TAG_POST,
|
||||
params.getFieldParam(fieldName, HighlightParams.SIMPLE_POST, "</em>")
|
||||
);
|
||||
String ellipsis = params.getFieldParam(fieldName, HighlightParams.TAG_ELLIPSIS, SNIPPET_SEPARATOR);
|
||||
String encoder = params.getFieldParam(fieldName, HighlightParams.ENCODER, "simple");
|
||||
return new DefaultPassageFormatter(preTag, postTag, ellipsis, "html".equals(encoder));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PassageScorer getScorer(String fieldName) {
|
||||
float k1 = params.getFieldFloat(fieldName, HighlightParams.SCORE_K1, 1.2f);
|
||||
float b = params.getFieldFloat(fieldName, HighlightParams.SCORE_B, 0.75f);
|
||||
float pivot = params.getFieldFloat(fieldName, HighlightParams.SCORE_PIVOT, 87f);
|
||||
return new PassageScorer(k1, b, pivot);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BreakIterator getBreakIterator(String field) {
|
||||
String language = params.getFieldParam(field, HighlightParams.BS_LANGUAGE);
|
||||
String country = params.getFieldParam(field, HighlightParams.BS_COUNTRY);
|
||||
String variant = params.getFieldParam(field, HighlightParams.BS_VARIANT);
|
||||
Locale locale = parseLocale(language, country, variant);
|
||||
String type = params.getFieldParam(field, HighlightParams.BS_TYPE);
|
||||
return parseBreakIterator(type, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* From {@link #getHighlighter(org.apache.solr.request.SolrQueryRequest)}.
|
||||
* parse a break iterator type for the specified locale
|
||||
*/
|
||||
protected static class SolrExtendedUnifiedHighlighter extends UnifiedHighlighter {
|
||||
protected final SolrParams params;
|
||||
protected final IndexSchema schema;
|
||||
|
||||
protected final RTimerTree loadFieldValuesTimer;
|
||||
|
||||
public SolrExtendedUnifiedHighlighter(SolrQueryRequest req) {
|
||||
super(req.getSearcher(), req.getSchema().getIndexAnalyzer());
|
||||
this.params = req.getParams();
|
||||
this.schema = req.getSchema();
|
||||
this.setMaxLength(
|
||||
params.getInt(HighlightParams.MAX_CHARS, UnifiedHighlighter.DEFAULT_MAX_LENGTH));
|
||||
this.setCacheFieldValCharsThreshold(
|
||||
params.getInt(HighlightParams.CACHE_FIELD_VAL_CHARS_THRESHOLD, DEFAULT_CACHE_CHARS_THRESHOLD));
|
||||
|
||||
// SolrRequestInfo is a thread-local singleton providing access to the ResponseBuilder to code that
|
||||
// otherwise can't get it in a nicer way.
|
||||
SolrQueryRequest request = SolrRequestInfo.getRequestInfo().getReq();
|
||||
final RTimerTree timerTree;
|
||||
if (request.getRequestTimer() != null) { //It may be null if not used in a search context.
|
||||
timerTree = request.getRequestTimer();
|
||||
} else {
|
||||
timerTree = new RTimerTree(); // since null checks are annoying
|
||||
}
|
||||
loadFieldValuesTimer = timerTree.sub("loadFieldValues"); // we assume a new timer, state of STARTED
|
||||
loadFieldValuesTimer.pause(); // state of PAUSED now with about zero time. Will fail if state isn't STARTED.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OffsetSource getOffsetSource(String field) {
|
||||
String sourceStr = params.getFieldParam(field, HighlightParams.OFFSET_SOURCE);
|
||||
if (sourceStr != null) {
|
||||
return OffsetSource.valueOf(sourceStr.toUpperCase(Locale.ROOT));
|
||||
} else {
|
||||
return super.getOffsetSource(field);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxNoHighlightPassages(String field) {
|
||||
boolean defaultSummary = params.getFieldBool(field, HighlightParams.DEFAULT_SUMMARY, false);
|
||||
if (defaultSummary) {
|
||||
return -1;// signifies return first hl.snippets passages worth of the content
|
||||
} else {
|
||||
return 0;// will return null
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PassageFormatter getFormatter(String fieldName) {
|
||||
String preTag = params.getFieldParam(fieldName, HighlightParams.TAG_PRE,
|
||||
params.getFieldParam(fieldName, HighlightParams.SIMPLE_PRE, "<em>")
|
||||
);
|
||||
|
||||
String postTag = params.getFieldParam(fieldName, HighlightParams.TAG_POST,
|
||||
params.getFieldParam(fieldName, HighlightParams.SIMPLE_POST, "</em>")
|
||||
);
|
||||
String ellipsis = params.getFieldParam(fieldName, HighlightParams.TAG_ELLIPSIS, SNIPPET_SEPARATOR);
|
||||
String encoder = params.getFieldParam(fieldName, HighlightParams.ENCODER, "simple");
|
||||
return new DefaultPassageFormatter(preTag, postTag, ellipsis, "html".equals(encoder));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PassageScorer getScorer(String fieldName) {
|
||||
float k1 = params.getFieldFloat(fieldName, HighlightParams.SCORE_K1, 1.2f);
|
||||
float b = params.getFieldFloat(fieldName, HighlightParams.SCORE_B, 0.75f);
|
||||
float pivot = params.getFieldFloat(fieldName, HighlightParams.SCORE_PIVOT, 87f);
|
||||
return new PassageScorer(k1, b, pivot);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BreakIterator getBreakIterator(String field) {
|
||||
String language = params.getFieldParam(field, HighlightParams.BS_LANGUAGE);
|
||||
String country = params.getFieldParam(field, HighlightParams.BS_COUNTRY);
|
||||
String variant = params.getFieldParam(field, HighlightParams.BS_VARIANT);
|
||||
Locale locale = parseLocale(language, country, variant);
|
||||
String type = params.getFieldParam(field, HighlightParams.BS_TYPE);
|
||||
return parseBreakIterator(type, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a break iterator type for the specified locale
|
||||
*/
|
||||
protected BreakIterator parseBreakIterator(String type, Locale locale) {
|
||||
if (type == null || "SENTENCE".equals(type)) {
|
||||
return BreakIterator.getSentenceInstance(locale);
|
||||
} else if ("LINE".equals(type)) {
|
||||
return BreakIterator.getLineInstance(locale);
|
||||
} else if ("WORD".equals(type)) {
|
||||
return BreakIterator.getWordInstance(locale);
|
||||
} else if ("CHARACTER".equals(type)) {
|
||||
return BreakIterator.getCharacterInstance(locale);
|
||||
} else if ("WHOLE".equals(type)) {
|
||||
return new WholeBreakIterator();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown " + HighlightParams.BS_TYPE + ": " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a locale from a language+country+variant spec
|
||||
*/
|
||||
protected Locale parseLocale(String language, String country, String variant) {
|
||||
if (language == null && country == null && variant == null) {
|
||||
return Locale.ROOT;
|
||||
} else if (language == null) {
|
||||
throw new IllegalArgumentException("language is required if country or variant is specified");
|
||||
} else if (country == null && variant != null) {
|
||||
throw new IllegalArgumentException("To specify variant, country is required");
|
||||
} else if (country != null && variant != null) {
|
||||
return new Locale(language, country, variant);
|
||||
} else if (country != null) {
|
||||
return new Locale(language, country);
|
||||
} else {
|
||||
return new Locale(language);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<CharSequence[]> loadFieldValues(String[] fields, DocIdSetIterator docIter, int
|
||||
cacheCharsThreshold) throws IOException {
|
||||
// Time loading field values. It can be an expensive part of highlighting.
|
||||
loadFieldValuesTimer.resume();
|
||||
try {
|
||||
return super.loadFieldValues(fields, docIter, cacheCharsThreshold);
|
||||
} finally {
|
||||
loadFieldValuesTimer.pause(); // note: doesn't need to be "stopped"; pause is fine.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldHandleMultiTermQuery(String field) {
|
||||
return params.getFieldBool(field, HighlightParams.HIGHLIGHT_MULTI_TERM, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldHighlightPhrasesStrictly(String field) {
|
||||
return params.getFieldBool(field, HighlightParams.USE_PHRASE_HIGHLIGHTER, true);
|
||||
}
|
||||
|
||||
protected BreakIterator parseBreakIterator(String type, Locale locale) {
|
||||
if (type == null || "SENTENCE".equals(type)) {
|
||||
return BreakIterator.getSentenceInstance(locale);
|
||||
} else if ("LINE".equals(type)) {
|
||||
return BreakIterator.getLineInstance(locale);
|
||||
} else if ("WORD".equals(type)) {
|
||||
return BreakIterator.getWordInstance(locale);
|
||||
} else if ("CHARACTER".equals(type)) {
|
||||
return BreakIterator.getCharacterInstance(locale);
|
||||
} else if ("WHOLE".equals(type)) {
|
||||
return new WholeBreakIterator();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown " + HighlightParams.BS_TYPE + ": " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* parse a locale from a language+country+variant spec
|
||||
*/
|
||||
protected Locale parseLocale(String language, String country, String variant) {
|
||||
if (language == null && country == null && variant == null) {
|
||||
return Locale.ROOT;
|
||||
} else if (language == null) {
|
||||
throw new IllegalArgumentException("language is required if country or variant is specified");
|
||||
} else if (country == null && variant != null) {
|
||||
throw new IllegalArgumentException("To specify variant, country is required");
|
||||
} else if (country != null && variant != null) {
|
||||
return new Locale(language, country, variant);
|
||||
} else if (country != null) {
|
||||
return new Locale(language, country);
|
||||
} else {
|
||||
return new Locale(language);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<CharSequence[]> loadFieldValues(String[] fields, DocIdSetIterator docIter, int
|
||||
cacheCharsThreshold) throws IOException {
|
||||
// Time loading field values. It can be an expensive part of highlighting.
|
||||
loadFieldValuesTimer.resume();
|
||||
try {
|
||||
return super.loadFieldValues(fields, docIter, cacheCharsThreshold);
|
||||
} finally {
|
||||
loadFieldValuesTimer.pause(); // note: doesn't need to be "stopped"; pause is fine.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldHandleMultiTermQuery(String field) {
|
||||
return params.getFieldBool(field, HighlightParams.HIGHLIGHT_MULTI_TERM, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldHighlightPhrasesStrictly(String field) {
|
||||
return params.getFieldBool(field, HighlightParams.USE_PHRASE_HIGHLIGHTER, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue