[ SEARCH-2091 ] first draft (highlighter tests green)

This commit is contained in:
agazzarini
2020-02-11 12:05:28 +01:00
parent 4f83588af3
commit 79daa41755
7 changed files with 1217 additions and 1151 deletions

View File

@@ -776,29 +776,34 @@ public class AlfrescoSolrDataModel implements QueryConstants
} }
} }
// TODO: make it better
private void addHighlightSearchFields( PropertyDefinition propertyDefinition , IndexedField indexedField) private void addHighlightSearchFields( PropertyDefinition propertyDefinition , IndexedField indexedField)
{ {
FieldInstance field = new FieldInstance("text@s_stored@" + propertyDefinition.getName(), false, false); QName propertyDataTypeQName = propertyDefinition.getDataType().getName();
StringBuilder builder =
new StringBuilder()
.append(propertyDataTypeQName.getLocalName())
.append("@");
if(propertyDataTypeQName.equals(DataTypeDefinition.MLTEXT))
{
builder.append('m');
}
else if(propertyDataTypeQName.equals(DataTypeDefinition.CONTENT))
{
builder.append('s');
}
else
{
builder.append(propertyDefinition.isMultiValued() ? "m" : "s");
}
builder.append("_stored_lt@").append(propertyDefinition.getName().toString());
System.out.println(propertyDefinition.getName() + " has been mapped to " + builder);
FieldInstance field = new FieldInstance(builder.toString(), true, false);
indexedField.getFields().add(field); indexedField.getFields().add(field);
/*
if ((propertyDefinition.getIndexTokenisationMode() == IndexTokenisationMode.TRUE)
|| (propertyDefinition.getIndexTokenisationMode() == IndexTokenisationMode.BOTH))
{
if(crossLocaleSearchDataTypes.contains(propertyDefinition.getDataType().getName()) || crossLocaleSearchProperties.contains(propertyDefinition.getName()))
{
indexedField.addField(getFieldForText(false, true, false, propertyDefinition), false, false);
indexedField.addField(getFieldForText(true, true, false, propertyDefinition), false, false);
}
else
{
indexedField.addField(getFieldForText(true, true, false, propertyDefinition), false, false);
}
}
else
{
indexedField.addField(getFieldForText(false, false, false, propertyDefinition), false, false);
}
*/
} }
/* /*

View File

@@ -2193,6 +2193,67 @@ public class SolrInformationServer implements InformationServer
"FIELD: Name = " + field.getField() + ", Localised = " + field.localised + ", Sort = " + field.sort; "FIELD: Name = " + field.getField() + ", Localised = " + field.localised + ", Sort = " + field.sort;
} }
static void mltextProperty(QName propertyQName, MLTextPropertyValue value, final BiConsumer<String, Object> valueHolder)
{
AlfrescoSolrDataModel dataModel = AlfrescoSolrDataModel.getInstance();
List<FieldInstance> fields = dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields();
// TODO: is there a better way to determine if the field is a mltext or not
// (for example) a boolean or a primitive (the default model always associates 1 field to such types)
// Boolean properties (like isIndexed) are caught in this loop because they are classified as StringPropertyValue
if (fields.size() > 1) {
// TODO: this should be got from AlfrescoSolrDataModel
String storedFieldName = "mltext@m_stored_lt@" + propertyQName;
valueHolder.accept(storedFieldName, getLocalisedValues(value));
// mltext Sort fields concatenate multiple values (1 locale - 1 value) in a single string
// we cannot do that using copyfield or update request processor so the only possible approach
// is to send the sort field separately (like we do for doc values "text" fields)
fields.stream()
.filter(FieldInstance::isSort)
.forEach(field -> addMLTextProperty(valueHolder, field, value));
} else {
// Theoretically we should never be in this branch (primitive types are not mltext)
dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields()
.forEach(field -> addMLTextProperty(valueHolder, field, value));
}
}
static void stringProperty(QName propertyQName, StringPropertyValue value, PropertyValue locale, final BiConsumer<String, Object> valueHolder)
{
AlfrescoSolrDataModel dataModel = AlfrescoSolrDataModel.getInstance();
List<FieldInstance> fields = dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields();
// TODO: is there a better way to determine if the field is a text/mltext/content or not
// (for example) a boolean or a primitive (the default model always associates 1 field to such types)
// Boolean properties (like isIndexed) are caught in this loop because they are classified as StringPropertyValue
if (fields.size() > 1) {
// TODO: this should be got from AlfrescoSolrDataModel
String storedFieldName = "text@s_stored_lt@" + propertyQName;
valueHolder.accept(storedFieldName, getLocalisedValue((StringPropertyValue) value, locale));
/* the schema have been changed so all the stored field above is copied on every text@...@ fields
The only exception is the text@sd___@ which has docvalues enabled. We can't copy the stored field
there because the locale prefix cannot be removed (as it happens with the other non-localised text@ fields)
*/
dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields()
.stream()
.filter(field -> field.getField().startsWith("text@sd___@"))
.forEach(field -> addStringProperty(valueHolder, field, (StringPropertyValue) value, locale));
} else {
// OLD CODE: this relates to primitive/non-text fields/properties (like LID, APATH or boolean@...)
dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields()
.forEach(field -> addStringProperty(valueHolder, field, (StringPropertyValue) value, locale));
}
}
static void populateProperties( static void populateProperties(
Map<QName, PropertyValue> properties, Map<QName, PropertyValue> properties,
boolean contentIndexingHasBeenRequestedForThisNode, boolean contentIndexingHasBeenRequestedForThisNode,
@@ -2211,6 +2272,8 @@ public class SolrInformationServer implements InformationServer
final BiConsumer<String, Object> setValue = document::setField; final BiConsumer<String, Object> setValue = document::setField;
final BiConsumer<String, Object> addValue = document::addField; final BiConsumer<String, Object> addValue = document::addField;
final BiConsumer<String, Object> collectName = (name, value) -> addFieldIfNotSet(document, name); final BiConsumer<String, Object> collectName = (name, value) -> addFieldIfNotSet(document, name);
final BiConsumer<String, Object> setAndCollect = setValue.andThen(collectName);
final BiConsumer<String, Object> addAndCollect = addValue.andThen(collectName);
for (Entry<QName, PropertyValue> property : properties.entrySet()) for (Entry<QName, PropertyValue> property : properties.entrySet())
{ {
@@ -2221,54 +2284,22 @@ public class SolrInformationServer implements InformationServer
PropertyValue value = property.getValue(); PropertyValue value = property.getValue();
if(value != null) if(value != null)
{ {
AlfrescoSolrDataModel dataModel = AlfrescoSolrDataModel.getInstance();
if (value instanceof StringPropertyValue) if (value instanceof StringPropertyValue)
{ {
/* stringProperty(propertyQName, (StringPropertyValue) value, properties.get(ContentModel.PROP_LOCALE), setAndCollect);
*
* Boolean properties (like isIndexed) are classified are StringPropertyValue
*/
List<FieldInstance> fields = dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields();
if (fields.size() > 1) {
System.out.println(propertyQName + "=>" + dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields().size());
String storedFieldName = "text@s_stored@" + propertyQName;
System.out.println(storedFieldName);
document.setField(storedFieldName, getLocalisedValue((StringPropertyValue) value, properties));
/* the schema have been changed so all the stored field above is copied on every text@...@ fields
The only exception is the text@sd___@ which has docvalues enabled. We can't copy the stored field
there because the locale prefix cannot be removed (as it happens with the other non-localised text@ fields)
*/
dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields()
.stream()
.filter(field -> field.getField().startsWith("text@sd___@"))
.forEach(field -> addStringProperty(setValue.andThen(collectName), field, (StringPropertyValue) value, properties));
} else {
// OLD CODE
dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields()
.stream()
//.peek(field -> System.out.println(propertyToString(document.get("DBID"), "Single StringPropertyValue", propertyQName, value, field)))
.forEach(field -> addStringProperty(setValue.andThen(collectName), field, (StringPropertyValue) value, properties));
}
} }
else if (value instanceof MLTextPropertyValue) else if (value instanceof MLTextPropertyValue)
{ {
dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields() mltextProperty(propertyQName,(MLTextPropertyValue) value, setAndCollect);
.stream()
//.peek(field -> System.out.println(propertyToString(document.get("id"), "Single MLTextPropertyValue", propertyQName, value, field)))
.forEach(field -> addMLTextProperty(setValue.andThen(collectName), field, (MLTextPropertyValue) value));
} }
else if (value instanceof ContentPropertyValue) else if (value instanceof ContentPropertyValue)
{ {
addContentProperty(setValue.andThen(collectName), document, propertyQName, (ContentPropertyValue) value, contentIndexingIsEnabled); addContentProperty(setAndCollect, document, propertyQName, (ContentPropertyValue) value, contentIndexingIsEnabled);
} }
else if (value instanceof MultiPropertyValue) else if (value instanceof MultiPropertyValue)
{ {
MultiPropertyValue typedValue = (MultiPropertyValue) value; MultiPropertyValue typedValue = (MultiPropertyValue) value;
AlfrescoSolrDataModel dataModel = AlfrescoSolrDataModel.getInstance();
clearFields( clearFields(
document, document,
dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields() dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields()
@@ -2280,20 +2311,15 @@ public class SolrInformationServer implements InformationServer
{ {
if (singleValue instanceof StringPropertyValue) if (singleValue instanceof StringPropertyValue)
{ {
dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields() stringProperty(propertyQName, (StringPropertyValue) singleValue, properties.get(ContentModel.PROP_LOCALE), addAndCollect);
.stream()
.peek(field -> System.out.println(propertyToString(document.get("DBID"), "Multiple StringPropertyValue", propertyQName, value, field)))
.forEach(field -> addStringProperty(addValue.andThen(collectName), field, (StringPropertyValue) singleValue, properties));
} }
else if (singleValue instanceof MLTextPropertyValue) else if (singleValue instanceof MLTextPropertyValue)
{ {
dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields() mltextProperty(propertyQName,(MLTextPropertyValue) singleValue, addAndCollect);
.stream()
.peek(field -> System.out.println(propertyToString(document.get("DBID"), "Multiple MLTextPropertyValue", propertyQName, value, field))) .forEach(field -> addMLTextProperty(addValue.andThen(collectName), field, (MLTextPropertyValue) singleValue));
} }
else if (singleValue instanceof ContentPropertyValue) else if (singleValue instanceof ContentPropertyValue)
{ {
addContentProperty(addValue.andThen(collectName), document, propertyQName, (ContentPropertyValue) singleValue, contentIndexingIsEnabled); addContentProperty(addAndCollect, document, propertyQName, (ContentPropertyValue) singleValue, contentIndexingIsEnabled);
} }
} }
} }
@@ -2630,18 +2656,37 @@ public class SolrInformationServer implements InformationServer
this.getTrackerStats().addDocTransformationTime(System.nanoTime() - start); this.getTrackerStats().addDocTransformationTime(System.nanoTime() - start);
dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields() // TODO: The field name should be retrieved from AlfrescoSolrDataModel
.stream() String storedField = "content@s_stored_lt@" + propertyQName;
.peek(field -> doc.removeField(field.getField()))
.forEach(field -> {
doc.addField(
field.getField(),
field.isLocalised()
? "\u0000" + locale + "\u0000" + textContent
: textContent);
addFieldIfNotSet(doc, field.getField()); doc.setField(storedField, "\u0000" + locale + "\u0000" + textContent);
});
dataModel.getIndexedFieldNamesForProperty(propertyQName)
.getFields()
.forEach(field -> addFieldIfNotSet(doc, field.getField()));
}
private static List<String> getLocalisedValues(MLTextPropertyValue mlTextPropertyValue)
{
if (mlTextPropertyValue == null)
{
return Collections.emptyList();
}
List<String> values = new ArrayList<>();
for (Locale locale : mlTextPropertyValue.getLocales())
{
final String propValue = mlTextPropertyValue.getValue(locale);
if((locale == null) || propValue == null)
{
continue;
}
StringBuilder builder = new StringBuilder(propValue.length() + 16);
builder.append("\u0000").append(locale.toString()).append("\u0000").append(propValue);
values.add(builder.toString());
}
return values;
} }
private static void addMLTextProperty(BiConsumer<String, Object> consumer, FieldInstance field, MLTextPropertyValue mlTextPropertyValue) private static void addMLTextProperty(BiConsumer<String, Object> consumer, FieldInstance field, MLTextPropertyValue mlTextPropertyValue)
@@ -3820,10 +3865,10 @@ public class SolrInformationServer implements InformationServer
} }
} }
private static String getLocalisedValue(StringPropertyValue property, Map<QName, PropertyValue> properties) private static String getLocalisedValue(StringPropertyValue property, PropertyValue localeProperty)
{ {
Locale locale = Locale locale =
ofNullable(properties.get(ContentModel.PROP_LOCALE)) ofNullable(localeProperty)
.map(StringPropertyValue.class::cast) .map(StringPropertyValue.class::cast)
.map(StringPropertyValue::getValue) .map(StringPropertyValue::getValue)
.map(value -> DefaultTypeConverter.INSTANCE.convert(Locale.class, value)) .map(value -> DefaultTypeConverter.INSTANCE.convert(Locale.class, value))
@@ -3832,23 +3877,9 @@ public class SolrInformationServer implements InformationServer
return "\u0000" + locale.toString() + "\u0000" + property.getValue(); return "\u0000" + locale.toString() + "\u0000" + property.getValue();
} }
private static void addStringProperty(BiConsumer<String, Object> consumer, FieldInstance field, StringPropertyValue property, Map<QName, PropertyValue> properties) private static void addStringProperty(BiConsumer<String, Object> consumer, FieldInstance field, StringPropertyValue property, PropertyValue localeProperty)
{ {
if(field.isLocalised()) consumer.accept(field.getField(), field.isLocalised() ? getLocalisedValue(property, localeProperty) : property.getValue());
{
Locale locale =
ofNullable(properties.get(ContentModel.PROP_LOCALE))
.map(StringPropertyValue.class::cast)
.map(StringPropertyValue::getValue)
.map(value -> DefaultTypeConverter.INSTANCE.convert(Locale.class, value))
.orElse(I18NUtil.getLocale());
consumer.accept(field.getField(), "\u0000" + locale.toString() + "\u0000" + property.getValue());
}
else
{
consumer.accept(field.getField(), property.getValue());
}
} }
private static void addFieldIfNotSet(SolrInputDocument doc, String name) private static void addFieldIfNotSet(SolrInputDocument doc, String name)

View File

@@ -241,6 +241,7 @@ public class AlfrescoSolrHighlighter extends DefaultSolrHighlighter implements P
// Additional mappings coming from this 2nd round // Additional mappings coming from this 2nd round
Map<String, String> additionalMappings = new HashMap<>(); Map<String, String> additionalMappings = new HashMap<>();
/*
identifiers.keySet() identifiers.keySet()
.forEach(id -> { .forEach(id -> {
final NamedList<Object> docHighlighting = (NamedList<Object>) highlightingResponse.get(id); final NamedList<Object> docHighlighting = (NamedList<Object>) highlightingResponse.get(id);
@@ -257,7 +258,8 @@ public class AlfrescoSolrHighlighter extends DefaultSolrHighlighter implements P
mappings.putAll(additionalMappings); mappings.putAll(additionalMappings);
withDebug(mappings); withDebug(mappings);
*/
/*
// We are going to re-call the highlight for those documents/fields which didnt' produce any result in the // We are going to re-call the highlight for those documents/fields which didnt' produce any result in the
// previous step. In order to do that we need // previous step. In order to do that we need
// - a (Solr) field name: the second-level choice coming from Alfresco Data Model // - a (Solr) field name: the second-level choice coming from Alfresco Data Model
@@ -295,6 +297,8 @@ public class AlfrescoSolrHighlighter extends DefaultSolrHighlighter implements P
.filter(notNullAndNotEmpty) .filter(notNullAndNotEmpty)
.collect(toList()); .collect(toList());
// Combine (actually reduce) the highlight response coming from the first try, with each // Combine (actually reduce) the highlight response coming from the first try, with each
// partial highlight response coming from subsequent calls // partial highlight response coming from subsequent calls
NamedList<Object> responseBeforeRenamingFields = partialHighlightingResponses.stream() NamedList<Object> responseBeforeRenamingFields = partialHighlightingResponses.stream()
@@ -315,8 +319,9 @@ public class AlfrescoSolrHighlighter extends DefaultSolrHighlighter implements P
}); });
return accumulator; return accumulator;
}); });
*/
NamedList<Object> responseBeforeRenamingFields = highlightingResponse;
// Final step: under each document section, highlight snippets are associated with Solr field names, // Final step: under each document section, highlight snippets are associated with Solr field names,
// so we need to replace them with fields actually requested // so we need to replace them with fields actually requested
// In addition, beside the snippets we want to have the document DBID as well. // In addition, beside the snippets we want to have the document DBID as well.

View File

@@ -115,9 +115,9 @@
<tokenizer class="solr.ICUTokenizerFactory"/> <tokenizer class="solr.ICUTokenizerFactory"/>
<filter class="solr.ICUNormalizer2FilterFactory" name="nfkc_cf" mode="compose" /> <filter class="solr.ICUNormalizer2FilterFactory" name="nfkc_cf" mode="compose" />
<filter class="solr.ShingleFilterFactory" minShingleSize="5" maxShingleSize="5" outputUnigrams="false" outputUnigramsIfNoShingles="false" tokenSeparator=" " /> <filter class="solr.ShingleFilterFactory" minShingleSize="5" maxShingleSize="5" outputUnigrams="false" outputUnigramsIfNoShingles="false" tokenSeparator=" " />
<!-- <!--
<filter class="org.apache.lucene.analysis.minhash.ContextAccumulatingFilterFactory" /> <filter class="org.apache.lucene.analysis.minhash.ContextAccumulatingFilterFactory" />
--> -->
<filter class="org.apache.lucene.analysis.minhash.MinHashFilterFactory" hashCount="1" hashSetSize="1" bucketCount="512" /> <filter class="org.apache.lucene.analysis.minhash.MinHashFilterFactory" hashCount="1" hashSetSize="1" bucketCount="512" />
</analyzer> </analyzer>
<analyzer type="query"> <analyzer type="query">
@@ -1030,7 +1030,7 @@
<dynamicField name="noderef@md@*" type="identifiers" stored="true" docValues="true" sortMissingLast="true"/> <dynamicField name="noderef@md@*" type="identifiers" stored="true" docValues="true" sortMissingLast="true"/>
<!-- GX --> <!-- GX -->
<dynamicField name="text@s_stored@*" type="identifier" indexed="false" stored="true"/> <dynamicField name="text@s_stored_lt@*" type="alfrescoFieldType" indexed="false" stored="true" />
<dynamicField name="text@s____@*" type="text-identifier" /> <dynamicField name="text@s____@*" type="text-identifier" />
<dynamicField name="text@s__l_@*" type="alfrescoFieldType" omitNorms="true" stored="false"/> <dynamicField name="text@s__l_@*" type="alfrescoFieldType" omitNorms="true" stored="false"/>
@@ -1041,13 +1041,15 @@
<!-- END --> <!-- END -->
<copyField source="text@s_stored@*" dest="text@s____@*" /> <copyField source="text@s_stored_lt@*" dest="text@s____@*" />
<copyField source="text@s_stored@*" dest="text@s__l_@*" /> <copyField source="text@s_stored_lt@*" dest="text@s__l_@*" />
<copyField source="text@s_stored@*" dest="text@s___t@*" /> <copyField source="text@s_stored_lt@*" dest="text@s__lt@*" />
<copyField source="text@s_stored@*" dest="text@s___t@*" /> <copyField source="text@s_stored_lt@*" dest="text@s___t@*" />
<copyField source="text@s_stored@*" dest="text@s__sort@*" /> <copyField source="text@s_stored_lt@*" dest="text@s__sort@*" />
<!--
<copyField source="text@s_stored@*" dest="text@sd___@*" /> <copyField source="text@s_stored@*" dest="text@sd___@*" />
<copyField source="text@s_stored@*" dest="suggest_*" /> -->
<copyField source="text@s_stored_lt@*" dest="suggest_*" />
<dynamicField name="text@m____@*" type="identifiers" /> <dynamicField name="text@m____@*" type="identifiers" />
@@ -1057,14 +1059,29 @@
<dynamicField name="text@md___@*" type="identifiers" stored="true" docValues="true" /> <dynamicField name="text@md___@*" type="identifiers" stored="true" docValues="true" />
<dynamicField name="mltext@m____@*" type="identifiers" /> <dynamicField name="mltext@m_stored_lt@*" type="alfrescoFieldType" indexed="false" stored="true" multiValued="true"/>
<dynamicField name="mltext@m__l_@*" type="alfrescoFieldType" omitNorms="true" multiValued="true" />
<dynamicField name="mltext@m__lt@*" type="alfrescoFieldType" omitNorms="true" multiValued="true" /> <dynamicField name="mltext@m____@*" type="identifiers" stored="false"/>
<dynamicField name="mltext@m___t@*" type="text___" multiValued="true" /> <dynamicField name="mltext@m__l_@*" type="alfrescoFieldType" omitNorms="true" multiValued="true" stored="false"/>
<dynamicField name="mltext@m__lt@*" type="alfrescoFieldType" omitNorms="true" multiValued="true" stored="false"/>
<dynamicField name="mltext@m___t@*" type="text___" multiValued="true" stored="false" />
<copyField source="mltext@m_stored_lt@*" dest="mltext@m____@*" />
<copyField source="mltext@m_stored_lt@*" dest="mltext@m__l_@*" />
<copyField source="mltext@m_stored_lt@*" dest="mltext@m__lt@*" />
<copyField source="mltext@m_stored_lt@*" dest="mltext@m___t@*" />
<copyField source="mltext@m_stored_lt@*" dest="suggest_*" />
<!-- this cannot be copied so it must be sent by the client-->
<!-- TODO: cehck if this field can be docvalues -->
<dynamicField name="mltext@m__sort@*" type="alfrescoCollatableMLTextFieldType" /> <dynamicField name="mltext@m__sort@*" type="alfrescoCollatableMLTextFieldType" />
<!-- ############################### -->
<dynamicField name="content@s__size@*" type="long" stored="true" docValues="true" /> <dynamicField name="content@s__size@*" type="long" stored="true" docValues="true" />
<dynamicField name="content@s__locale@*" type="identifier" stored="true" docValues="true" useDocValuesAsStored="true"/> <dynamicField name="content@s__locale@*" type="identifier" stored="true" docValues="true"/>
<dynamicField name="content@s__mimetype@*" type="identifier" stored="true" docValues="true" /> <dynamicField name="content@s__mimetype@*" type="identifier" stored="true" docValues="true" />
<dynamicField name="content@s__encoding@*" type="identifier" stored="true" docValues="true" /> <dynamicField name="content@s__encoding@*" type="identifier" stored="true" docValues="true" />
<dynamicField name="content@s__docid@*" type="long" stored="true" docValues="true" /> <dynamicField name="content@s__docid@*" type="long" stored="true" docValues="true" />
@@ -1072,11 +1089,18 @@
<dynamicField name="content@s__tr_time@*" type="long" /> <dynamicField name="content@s__tr_time@*" type="long" />
<dynamicField name="content@s__tr_status@*" type="lowercase_id" /> <dynamicField name="content@s__tr_status@*" type="lowercase_id" />
<dynamicField name="content@s____@*" type="identifier" termPositions="false" /> <dynamicField name="content@s_stored_lt@*" type="alfrescoFieldType" indexed="false" stored="true"/>
<dynamicField name="content@s__l_@*" type="alfrescoFieldType" omitNorms="true" termPositions="false" /> <dynamicField name="content@s____@*" type="identifier" stored="false"/>
<dynamicField name="content@s__lt@*" type="alfrescoFieldType" omitNorms="false" /> <dynamicField name="content@s__l_@*" type="alfrescoFieldType" omitNorms="true" stored="false"/>
<dynamicField name="content@s___t@*" type="text___" /> <dynamicField name="content@s__lt@*" type="alfrescoFieldType" omitNorms="false" stored="false"/>
<dynamicField name="content@s___t@*" type="text___" stored="false"/>
<copyField source="content@s_stored_lt@*" dest="content@s____@*" />
<copyField source="content@s_stored_lt@*" dest="content@s__l_@*" />
<copyField source="content@s_stored_lt@*" dest="content@s__lt@*" />
<copyField source="content@s_stored_lt@*" dest="content@s___t@*" />
<!-- "m" FIELDS are never used at the moment -->
<dynamicField name="content@m__size@*" type="longs" stored="true" docValues="true" /> <dynamicField name="content@m__size@*" type="longs" stored="true" docValues="true" />
<dynamicField name="content@m__locale@*" type="identifiers" stored="true" docValues="true" /> <dynamicField name="content@m__locale@*" type="identifiers" stored="true" docValues="true" />
<dynamicField name="content@m__mimetype@*" type="identifiers" stored="true" docValues="true" /> <dynamicField name="content@m__mimetype@*" type="identifiers" stored="true" docValues="true" />
@@ -1091,7 +1115,10 @@
<dynamicField name="content@m__lt@*" type="alfrescoFieldType" omitNorms="true" multiValued="true" /> <dynamicField name="content@m__lt@*" type="alfrescoFieldType" omitNorms="true" multiValued="true" />
<dynamicField name="content@m___t@*" type="text___" multiValued="true" /> <dynamicField name="content@m___t@*" type="text___" multiValued="true" />
<!-- END "m" FIELDS section -->
<!-- Suggestion --> <!-- Suggestion -->
<!-- Understand better this field(s) -->
<field name="suggest" type="text_shingle" indexed="true" omitNorms="true" omitPositions="true" stored="true" multiValued="true" /> <field name="suggest" type="text_shingle" indexed="true" omitNorms="true" omitPositions="true" stored="true" multiValued="true" />
<dynamicField name="suggest_*" type="ignored" multiValued="true"/> <dynamicField name="suggest_*" type="ignored" multiValued="true"/>

View File

@@ -219,7 +219,7 @@ public class AlfrescoSolrUtils
nodeMetaData.setAncestors(ancestors); nodeMetaData.setAncestors(ancestors);
Map<QName, PropertyValue> props = new HashMap<>(); Map<QName, PropertyValue> props = new HashMap<>();
props.put(ContentModel.PROP_IS_INDEXED, new StringPropertyValue("true")); props.put(ContentModel.PROP_IS_INDEXED, new StringPropertyValue("true"));
props.put(ContentModel.PROP_CONTENT, new ContentPropertyValue(Locale.US, 0l, "UTF-8", "text/plain", null)); props.put(ContentModel.PROP_CONTENT, new ContentPropertyValue(Locale.US, 0L, "UTF-8", "text/plain", null));
nodeMetaData.setProperties(props); nodeMetaData.setProperties(props);
//If create createError is true then we leave out the nodeRef which will cause an error //If create createError is true then we leave out the nodeRef which will cause an error
if(!createError) { if(!createError) {

View File

@@ -70,7 +70,7 @@ public class AlfrescoHighlighterIT extends AbstractAlfrescoSolrIT
List<Map<String, String>> data = asList( List<Map<String, String>> data = asList(
of(NAME_METADATA_ATTRIBUTE, "some very long name", of(NAME_METADATA_ATTRIBUTE, "some very long name",
DESCRIPTION_METADATA_ATTRIBUTE, "mydesc", DESCRIPTION_METADATA_ATTRIBUTE, "is this a long description? No, I do not think is so long",
TITLE_METADATA_ATTRIBUTE, "title1 is very long"), TITLE_METADATA_ATTRIBUTE, "title1 is very long"),
of(NAME_METADATA_ATTRIBUTE, long_text, of(NAME_METADATA_ATTRIBUTE, long_text,
TITLE_METADATA_ATTRIBUTE, "title2"), TITLE_METADATA_ATTRIBUTE, "title2"),
@@ -180,7 +180,7 @@ public class AlfrescoHighlighterIT extends AbstractAlfrescoSolrIT
SolrServletRequest req = areq(params("q", "name:long", "qt", "/afts", "start", "0", "rows", "5", SolrServletRequest req = areq(params("q", "name:long", "qt", "/afts", "start", "0", "rows", "5",
HighlightParams.HIGHLIGHT, "true", HighlightParams.HIGHLIGHT, "true",
HighlightParams.Q, "long", HighlightParams.Q, "long",
HighlightParams.FIELDS, "content,name,title", HighlightParams.FIELDS, "content,name,title,description",
HighlightParams.SNIPPETS, "4", HighlightParams.SNIPPETS, "4",
HighlightParams.FRAGSIZE, "40"), HighlightParams.FRAGSIZE, "40"),
"{" + "{" +
@@ -190,12 +190,14 @@ public class AlfrescoHighlighterIT extends AbstractAlfrescoSolrIT
assertQ(req, assertQ(req,
"*[count(//lst[@name='highlighting']/lst)=2]", "*[count(//lst[@name='highlighting']/lst)=2]",
"//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.='some very <em>long</em> name']", "//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.='this is some <em>long</em> text. It has the']",
"//lst[@name='highlighting']/lst[1]/arr[@name='title']/str[.='title1 is very <em>long</em>']", "//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.=' word <em>long</em> in many places. In fact, it has']",
"//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.='this is some <em>long</em> text. It has the']", "//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.=' <em>long</em> on some different fragments. Let us']",
"//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.=' word <em>long</em> in many places. In fact, it has']", "//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.=' see what happens to <em>long</em> in this case.']",
"//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.=' <em>long</em> on some different fragments. Let us']", "//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.='some very <em>long</em> name']",
"//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.=' see what happens to <em>long</em> in this case.']"); "//lst[@name='highlighting']/lst[2]/arr[@name='description']/str[.='is this a <em>long</em> description? No, I do']",
"//lst[@name='highlighting']/lst[2]/arr[@name='description']/str[.=' not think is so <em>long</em>']",
"//lst[@name='highlighting']/lst[2]/arr[@name='title']/str[.='title1 is very <em>long</em>']");
} }
@Test @Test
@@ -246,8 +248,8 @@ public class AlfrescoHighlighterIT extends AbstractAlfrescoSolrIT
assertQ(req, assertQ(req,
"*[count(//lst[@name='highlighting']/lst)=2]", "*[count(//lst[@name='highlighting']/lst)=2]",
"*[count(//lst[@name='highlighting']/lst/arr[@name='name'])=2]", "*[count(//lst[@name='highlighting']/lst/arr[@name='name'])=2]",
"//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.='some very {long} name']", "//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.='some very {long} name']",
"//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.='this is some {long}']"); "//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.='this is some {long}']");
} }
@Test @Test
@@ -288,13 +290,13 @@ public class AlfrescoHighlighterIT extends AbstractAlfrescoSolrIT
assertQ(req, assertQ(req,
"*[count(//lst[@name='highlighting']/lst/arr[@name='name'])=2]", "*[count(//lst[@name='highlighting']/lst/arr[@name='name'])=2]",
"*[count(//lst[@name='highlighting']/lst/str[@name='DBID'])=2]", "*[count(//lst[@name='highlighting']/lst/str[@name='DBID'])=2]",
"//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.='some very [long] name']", "//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.='some very [long] name']",
"//lst[@name='highlighting']/lst[1]/arr[@name='title']/str[.='title1 is very (long)']", "//lst[@name='highlighting']/lst[2]/arr[@name='title']/str[.='title1 is very (long)']",
"//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.='this is some [long] text. It has the word [long] in many places. In fact, it has [long] on some']"); "//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.='this is some [long] text. It has the word [long] in many places. In fact, it has [long] on some']");
} }
@Test @Test
public void highlightingRequiredFieldsTest() public void highlightingRequiredFields()
{ {
SolrServletRequest req = areq(params("q", "name:long", "qt", "/afts", "start", "0", "rows", "5", SolrServletRequest req = areq(params("q", "name:long", "qt", "/afts", "start", "0", "rows", "5",
HighlightParams.HIGHLIGHT, "true", HighlightParams.HIGHLIGHT, "true",
@@ -307,7 +309,7 @@ public class AlfrescoHighlighterIT extends AbstractAlfrescoSolrIT
assertQ(req, assertQ(req,
"*[count(//lst[@name='highlighting']/lst)=2]", "*[count(//lst[@name='highlighting']/lst)=2]",
"*[count(//lst[@name='highlighting']/lst/arr[@name='title'])=1]", "*[count(//lst[@name='highlighting']/lst/arr[@name='title'])=1]",
"//lst[@name='highlighting']/lst[1]/arr[@name='title']/str[.='title1 is very {long}']"); "//lst[@name='highlighting']/lst[2]/arr[@name='title']/str[.='title1 is very {long}']");
req = areq(params("q", "name:long OR title:long", "qt", "/afts", "start", "0", "rows", "5", req = areq(params("q", "name:long OR title:long", "qt", "/afts", "start", "0", "rows", "5",
HighlightParams.HIGHLIGHT, "true", HighlightParams.HIGHLIGHT, "true",
@@ -322,7 +324,7 @@ public class AlfrescoHighlighterIT extends AbstractAlfrescoSolrIT
"*[count(//lst[@name='highlighting']/lst)=2]", "*[count(//lst[@name='highlighting']/lst)=2]",
"*[count(//lst[@name='highlighting']/lst/arr[@name='title'])=1]", "*[count(//lst[@name='highlighting']/lst/arr[@name='title'])=1]",
"*[count(//lst[@name='highlighting']/lst/arr[@name='name'])=0]", "*[count(//lst[@name='highlighting']/lst/arr[@name='name'])=0]",
"//lst[@name='highlighting']/lst[1]/arr[@name='title']/str[.='title1 is very {long}']"); "//lst[@name='highlighting']/lst[2]/arr[@name='title']/str[.='title1 is very {long}']");
} }
@Test @Test
@@ -330,7 +332,7 @@ public class AlfrescoHighlighterIT extends AbstractAlfrescoSolrIT
{ {
SolrServletRequest req = areq(params("q", "name:long", "qt", "/afts", "start", "0", "rows", "5", SolrServletRequest req = areq(params("q", "name:long", "qt", "/afts", "start", "0", "rows", "5",
HighlightParams.HIGHLIGHT, "true", HighlightParams.HIGHLIGHT, "true",
HighlightParams.Q, "long", HighlightParams.Q, "world",
HighlightParams.FIELDS, "content,name,title", HighlightParams.FIELDS, "content,name,title",
HighlightParams.SIMPLE_PRE, "<al>", HighlightParams.SIMPLE_PRE, "<al>",
HighlightParams.SIMPLE_POST, "<fresco>", HighlightParams.SIMPLE_POST, "<fresco>",
@@ -340,12 +342,11 @@ public class AlfrescoHighlighterIT extends AbstractAlfrescoSolrIT
assertQ(req, assertQ(req,
"*[count(//lst[@name='highlighting']/lst)=2]", "*[count(//lst[@name='highlighting']/lst)=2]",
"//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.='some very <al>long<fresco> name']", "//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.='some very <al>long<fresco> name']",
"//lst[@name='highlighting']/lst[1]/arr[@name='title']/str[.='title1 is very <al>long<fresco>']", "//lst[@name='highlighting']/lst[2]/arr[@name='title']/str[.='title1 is very <al>long<fresco>']",
"//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.='this is some <al>long<fresco> text. It has the']", "//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.='this is some <al>long<fresco> text']",
"//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.=' word <al>long<fresco> in many places. In fact, it has']", "//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.='. It has the word <al>long<fresco> in many places. In fact, it has <al>long<fresco>']",
"//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.=' <al>long<fresco> on some different fragments. Let us']", "//lst[@name='highlighting']/lst[1]/arr[@name='name']/str[.=' on some different fragments. Let us see what happens to <al>long<fresco> in this case.']");
"//lst[@name='highlighting']/lst[2]/arr[@name='name']/str[.=' see what happens to <al>long<fresco> in this case.']");
} }
@Test @Test
@@ -373,7 +374,6 @@ public class AlfrescoHighlighterIT extends AbstractAlfrescoSolrIT
{ {
SolrServletRequest req = areq(params("q", "name:plural", "qt", "/afts", "start", "0", "rows", "5", SolrServletRequest req = areq(params("q", "name:plural", "qt", "/afts", "start", "0", "rows", "5",
HighlightParams.HIGHLIGHT, "true", HighlightParams.HIGHLIGHT, "true",
//HighlightParams.Q, "lon*",
HighlightParams.FIELDS, NAME_METADATA_ATTRIBUTE, HighlightParams.FIELDS, NAME_METADATA_ATTRIBUTE,
HighlightParams.HIGHLIGHT_MULTI_TERM, "false", HighlightParams.HIGHLIGHT_MULTI_TERM, "false",
HighlightParams.SIMPLE_PRE, "{", HighlightParams.SIMPLE_PRE, "{",

View File

@@ -35,17 +35,15 @@ import java.util.List;
*/ */
public class MultiPropertyValue extends PropertyValue public class MultiPropertyValue extends PropertyValue
{ {
private List<PropertyValue> values; private final List<PropertyValue> values;
public MultiPropertyValue() public MultiPropertyValue()
{ {
super(); this.values = new ArrayList<>();
this.values = new ArrayList<PropertyValue>(10);
} }
public MultiPropertyValue(List<PropertyValue> values) public MultiPropertyValue(List<PropertyValue> values)
{ {
super();
this.values = values; this.values = values;
} }