mirror of https://github.com/apache/lucene.git
SOLR-5127: Multiple highlight fields and wildcards are now supported e.g. hl.fl=title,text_*
(Sven-S. Porst, Daniel Debray, Simon Endele, Christine Poerschke)
This commit is contained in:
parent
e62a3ff46c
commit
f9ca49a8d5
|
@ -215,6 +215,9 @@ Bug Fixes
|
||||||
|
|
||||||
* SOLR-10472: Fixed uninversion (aka: FieldCache) bugs with the numeric PointField classes, and CurrencyField (hossman)
|
* SOLR-10472: Fixed uninversion (aka: FieldCache) bugs with the numeric PointField classes, and CurrencyField (hossman)
|
||||||
|
|
||||||
|
* SOLR-5127: Multiple highlight fields and wildcards are now supported e.g. hl.fl=title,text_*
|
||||||
|
(Sven-S. Porst, Daniel Debray, Simon Endele, Christine Poerschke)
|
||||||
|
|
||||||
Other Changes
|
Other Changes
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,9 @@ import org.apache.solr.search.DocList;
|
||||||
import org.apache.solr.util.SolrPluginUtils;
|
import org.apache.solr.util.SolrPluginUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public abstract class SolrHighlighter
|
public abstract class SolrHighlighter
|
||||||
{
|
{
|
||||||
|
@ -60,27 +60,19 @@ public abstract class SolrHighlighter
|
||||||
if (emptyArray(defaultFields)) {
|
if (emptyArray(defaultFields)) {
|
||||||
String defaultSearchField = request.getSchema().getDefaultSearchFieldName();
|
String defaultSearchField = request.getSchema().getDefaultSearchFieldName();
|
||||||
fields = null == defaultSearchField ? new String[]{} : new String[]{defaultSearchField};
|
fields = null == defaultSearchField ? new String[]{} : new String[]{defaultSearchField};
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
fields = defaultFields;
|
fields = defaultFields;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (fields.length == 1) {
|
|
||||||
if (fields[0].contains("*")) {
|
|
||||||
// create a Java regular expression from the wildcard string
|
|
||||||
String fieldRegex = fields[0].replaceAll("\\*", ".*");
|
|
||||||
Collection<String> storedHighlightFieldNames = request.getSearcher().getDocFetcher().getStoredHighlightFieldNames();
|
|
||||||
List<String> storedFieldsToHighlight = new ArrayList<>();
|
|
||||||
for (String storedFieldName: storedHighlightFieldNames) {
|
|
||||||
if (storedFieldName.matches(fieldRegex)) {
|
|
||||||
storedFieldsToHighlight.add(storedFieldName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fields = storedFieldsToHighlight.toArray(new String[storedFieldsToHighlight.size()]);
|
|
||||||
} else {
|
} else {
|
||||||
// if there's a single request/handler value, it may be a space/comma separated list
|
Set<String> expandedFields = new LinkedHashSet<String>();
|
||||||
fields = SolrPluginUtils.split(fields[0]);
|
Collection<String> storedHighlightFieldNames = request.getSearcher().getDocFetcher().getStoredHighlightFieldNames();
|
||||||
|
for (String field : fields) {
|
||||||
|
expandWildcardsInHighlightFields(
|
||||||
|
expandedFields,
|
||||||
|
storedHighlightFieldNames,
|
||||||
|
SolrPluginUtils.split(field));
|
||||||
}
|
}
|
||||||
|
fields = expandedFields.toArray(new String[]{});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trim them now in case they haven't been yet. Not needed for all code-paths above but do it here.
|
// Trim them now in case they haven't been yet. Not needed for all code-paths above but do it here.
|
||||||
|
@ -94,6 +86,25 @@ public abstract class SolrHighlighter
|
||||||
return (arr == null || arr.length == 0 || arr[0] == null || arr[0].trim().length() == 0);
|
return (arr == null || arr.length == 0 || arr[0] == null || arr[0].trim().length() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static private void expandWildcardsInHighlightFields (
|
||||||
|
Set<String> expandedFields,
|
||||||
|
Collection<String> storedHighlightFieldNames,
|
||||||
|
String... fields) {
|
||||||
|
for (String field : fields) {
|
||||||
|
if (field.contains("*")) {
|
||||||
|
// create a Java regular expression from the wildcard string
|
||||||
|
String fieldRegex = field.replaceAll("\\*", ".*");
|
||||||
|
for (String storedFieldName : storedHighlightFieldNames) {
|
||||||
|
if (storedFieldName.matches(fieldRegex)) {
|
||||||
|
expandedFields.add(storedFieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expandedFields.add(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a list of Highlighted query fragments for each item in a list
|
* Generates a list of Highlighted query fragments for each item in a list
|
||||||
* of documents, or returns null if highlighting is disabled.
|
* of documents, or returns null if highlighting is disabled.
|
||||||
|
|
|
@ -20,7 +20,9 @@ import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.lucene.analysis.Analyzer;
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
import org.apache.lucene.analysis.TokenStream;
|
import org.apache.lucene.analysis.TokenStream;
|
||||||
|
@ -35,6 +37,7 @@ import org.apache.solr.common.params.HighlightParams;
|
||||||
import org.apache.solr.handler.component.HighlightComponent;
|
import org.apache.solr.handler.component.HighlightComponent;
|
||||||
import org.apache.solr.handler.component.ResponseBuilder;
|
import org.apache.solr.handler.component.ResponseBuilder;
|
||||||
import org.apache.solr.handler.component.SearchComponent;
|
import org.apache.solr.handler.component.SearchComponent;
|
||||||
|
import org.apache.solr.request.LocalSolrQueryRequest;
|
||||||
import org.apache.solr.request.SolrQueryRequest;
|
import org.apache.solr.request.SolrQueryRequest;
|
||||||
import org.apache.solr.response.SolrQueryResponse;
|
import org.apache.solr.response.SolrQueryResponse;
|
||||||
import org.apache.solr.search.DocSet;
|
import org.apache.solr.search.DocSet;
|
||||||
|
@ -868,6 +871,8 @@ public class HighlighterTest extends SolrTestCaseJ4 {
|
||||||
"text", "test", // static not stored
|
"text", "test", // static not stored
|
||||||
"foo_s", "test", // dynamic stored
|
"foo_s", "test", // dynamic stored
|
||||||
"foo_sI", "test", // dynamic not stored
|
"foo_sI", "test", // dynamic not stored
|
||||||
|
"bar_s", "test", // dynamic stored
|
||||||
|
"bar_sI", "test", // dynamic not stored
|
||||||
"weight", "1.0")); // stored but not text
|
"weight", "1.0")); // stored but not text
|
||||||
assertU(commit());
|
assertU(commit());
|
||||||
assertU(optimize());
|
assertU(optimize());
|
||||||
|
@ -898,6 +903,21 @@ public class HighlighterTest extends SolrTestCaseJ4 {
|
||||||
assertEquals("Expected to highlight on field \"foo_s\"", "foo_s",
|
assertEquals("Expected to highlight on field \"foo_s\"", "foo_s",
|
||||||
highlightFieldNames.get(0));
|
highlightFieldNames.get(0));
|
||||||
request.close();
|
request.close();
|
||||||
|
|
||||||
|
// SOLR-5127
|
||||||
|
args.put("hl.fl", (random().nextBoolean() ? "foo_*,bar_*" : "bar_*,foo_*"));
|
||||||
|
lrf = h.getRequestFactory("standard", 0, 10, args);
|
||||||
|
// hl.fl ordering need not be preserved in output
|
||||||
|
final Set<String> highlightedSetExpected = new HashSet<String>();
|
||||||
|
highlightedSetExpected.add("foo_s");
|
||||||
|
highlightedSetExpected.add("bar_s");
|
||||||
|
try (LocalSolrQueryRequest localRequest = lrf.makeRequest("test")) {
|
||||||
|
highlighter = HighlightComponent.getHighlighter(h.getCore());
|
||||||
|
final Set<String> highlightedSetActual = new HashSet<String>(
|
||||||
|
Arrays.asList(highlighter.getHighlightFields(null,
|
||||||
|
localRequest, new String[] {})));
|
||||||
|
assertEquals(highlightedSetExpected, highlightedSetActual);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -99,6 +99,19 @@ public class TestPostingsSolrHighlighter extends SolrTestCaseJ4 {
|
||||||
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text3']/str='crappier <em>document</em>'");
|
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text3']/str='crappier <em>document</em>'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SOLR-5127
|
||||||
|
public void testMultipleFieldsViaWildcard() {
|
||||||
|
assertQ("highlighting text and text3*",
|
||||||
|
req("q", (random().nextBoolean() ? "text:document text3:document" : "text3:document text:document"),
|
||||||
|
"sort", "id asc", "hl", "true",
|
||||||
|
"hl.fl", (random().nextBoolean() ? "text,text3*" : "text3*,text")),
|
||||||
|
"count(//lst[@name='highlighting']/*)=2",
|
||||||
|
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text']/str='<em>document</em> one'",
|
||||||
|
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text3']/str='crappy <em>document</em>'",
|
||||||
|
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text']/str='second <em>document</em>'",
|
||||||
|
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text3']/str='crappier <em>document</em>'");
|
||||||
|
}
|
||||||
|
|
||||||
public void testMisconfiguredField() {
|
public void testMisconfiguredField() {
|
||||||
ignoreException("was indexed without offsets");
|
ignoreException("was indexed without offsets");
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -179,6 +179,19 @@ public class TestUnifiedSolrHighlighter extends SolrTestCaseJ4 {
|
||||||
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text3']/str='crappier <em>document</em>'");
|
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text3']/str='crappier <em>document</em>'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SOLR-5127
|
||||||
|
public void testMultipleFieldsViaWildcard() {
|
||||||
|
assertQ("highlighting text and text3*",
|
||||||
|
req("q", (random().nextBoolean() ? "text:document text3:document" : "text3:document text:document"),
|
||||||
|
"sort", "id asc", "hl", "true",
|
||||||
|
"hl.fl", (random().nextBoolean() ? "text,text3*" : "text3*,text")),
|
||||||
|
"count(//lst[@name='highlighting']/*)=2",
|
||||||
|
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text']/str='<em>document</em> one'",
|
||||||
|
"//lst[@name='highlighting']/lst[@name='101']/arr[@name='text3']/str='crappy <em>document</em>'",
|
||||||
|
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text']/str='second <em>document</em>'",
|
||||||
|
"//lst[@name='highlighting']/lst[@name='102']/arr[@name='text3']/str='crappier <em>document</em>'");
|
||||||
|
}
|
||||||
|
|
||||||
public void testTags() {
|
public void testTags() {
|
||||||
assertQ("different pre/post tags",
|
assertQ("different pre/post tags",
|
||||||
req("q", "text:document", "sort", "id asc", "hl", "true", "hl.tag.pre", "[", "hl.tag.post", "]"),
|
req("q", "text:document", "sort", "id asc", "hl", "true", "hl.tag.pre", "[", "hl.tag.post", "]"),
|
||||||
|
|
Loading…
Reference in New Issue