mirror of
https://github.com/Alfresco/SearchServices.git
synced 2026-09-16 18:12:56 +00:00
Merge pull request #1502 from Alfresco/servicepack/MNT-23154_cherrypick
Servicepack/MNT-23154 (cherrypick)
This commit is contained in:
+27
@@ -36,6 +36,7 @@ import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
@@ -45,6 +46,7 @@ import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
@@ -128,17 +130,42 @@ import static org.alfresco.solr.SolrInformationServer.UNIT_OF_TIME_YEAR_FIELD_SU
|
||||
*/
|
||||
public class AlfrescoSolrDataModel implements QueryConstants
|
||||
{
|
||||
public static class ContentPropertySpecs {
|
||||
public final String fieldName;
|
||||
public final String locale;
|
||||
|
||||
public ContentPropertySpecs(String fieldName, String locale) {
|
||||
this.fieldName = fieldName;
|
||||
this.locale = locale;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TenantDbId
|
||||
{
|
||||
public String tenant;
|
||||
public Long dbId;
|
||||
|
||||
private List<ContentPropertySpecs> contentPropertySpecsList;
|
||||
|
||||
public Map<String, Object> optionalBag = new HashMap<>();
|
||||
|
||||
public void setProperty(String name, Object value)
|
||||
{
|
||||
optionalBag.put(name, value);
|
||||
}
|
||||
|
||||
public boolean hasAtLeastOneContentProperty() {
|
||||
return contentPropertySpecsList != null && !contentPropertySpecsList.isEmpty();
|
||||
}
|
||||
|
||||
public void addContentPropertiesSpecs(List<ContentPropertySpecs> specsList)
|
||||
{
|
||||
contentPropertySpecsList = Collections.unmodifiableList(specsList);
|
||||
}
|
||||
|
||||
public Stream<ContentPropertySpecs> contentPropertySpecsStream() {
|
||||
return contentPropertySpecsList.stream();
|
||||
}
|
||||
}
|
||||
|
||||
public enum FieldUse
|
||||
|
||||
+37
-15
@@ -28,8 +28,10 @@ package org.alfresco.solr;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Optional.empty;
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.alfresco.repo.search.adaptor.QueryConstants.FIELD_ACLID;
|
||||
import static org.alfresco.repo.search.adaptor.QueryConstants.FIELD_ACLTXCOMMITTIME;
|
||||
import static org.alfresco.repo.search.adaptor.QueryConstants.FIELD_ACLTXID;
|
||||
@@ -361,6 +363,9 @@ public class SolrInformationServer implements InformationServer
|
||||
private static final long CONTENT_OUTDATED_MARKER = -10;
|
||||
private static final long CONTENT_UPDATED_MARKER = -20;
|
||||
|
||||
private static final String CONTENT_FIELD_NAME = "contentFieldName";
|
||||
|
||||
private static final String CONTENT_LOCALE = "contentLocale";
|
||||
private static final String CONTENT_LOCALE_FIELD = "content@s__locale@{http://www.alfresco.org/model/content/1.0}content";
|
||||
private static final Set<String> ID_AND_CONTENT_VERSION_ID_AND_CONTENT_LOCALE =
|
||||
new HashSet<>(asList(FIELD_SOLR4_ID, LATEST_APPLIED_CONTENT_VERSION_ID, CONTENT_LOCALE_FIELD));
|
||||
@@ -460,6 +465,8 @@ public class SolrInformationServer implements InformationServer
|
||||
|
||||
private final boolean dateFieldDestructuringHasBeenEnabledOnThisInstance;
|
||||
|
||||
private final boolean enabledIndexCustomContent;
|
||||
|
||||
static class DocListCollector implements Collector, LeafCollector
|
||||
{
|
||||
private final IntArrayList docs = new IntArrayList();
|
||||
@@ -642,6 +649,8 @@ public class SolrInformationServer implements InformationServer
|
||||
port = portNumber(props);
|
||||
baseUrl = baseUrl(props);
|
||||
|
||||
enabledIndexCustomContent = Boolean.parseBoolean(coreConfiguration.getProperty("solr.enableIndexingCustomContent", "false"));
|
||||
|
||||
dateFieldDestructuringHasBeenEnabledOnThisInstance = Boolean.parseBoolean(coreConfiguration.getProperty("alfresco.destructureDateFields", "true"));
|
||||
LOGGER.info(
|
||||
"Date fields destructuring has been {} on this instance.",
|
||||
@@ -999,9 +1008,17 @@ public class SolrInformationServer implements InformationServer
|
||||
String idString = id.stringValue();
|
||||
TenantDbId tenantAndDbId = AlfrescoSolrDataModel.decodeNodeDocumentId(idString);
|
||||
|
||||
ofNullable(document.getField(CONTENT_LOCALE_FIELD))
|
||||
.map(IndexableField::stringValue)
|
||||
.ifPresent(value -> tenantAndDbId.setProperty(CONTENT_LOCALE_FIELD, value));
|
||||
tenantAndDbId.addContentPropertiesSpecs(
|
||||
enabledIndexCustomContent
|
||||
? document.getFields().stream()
|
||||
.filter(field -> field.name().startsWith(AlfrescoSolrDataModel.CONTENT_S_LOCALE_PREFIX))
|
||||
.map(field -> new AlfrescoSolrDataModel.ContentPropertySpecs(field.name(),field.stringValue()))
|
||||
.collect(toList())
|
||||
: ofNullable(document.getField(CONTENT_LOCALE_FIELD))
|
||||
.map(IndexableField::stringValue)
|
||||
.map(value -> new AlfrescoSolrDataModel.ContentPropertySpecs(CONTENT_LOCALE_FIELD, value))
|
||||
.map(Collections::singletonList)
|
||||
.orElse(emptyList()));
|
||||
|
||||
tenantAndDbId.setProperty(
|
||||
LATEST_APPLIED_CONTENT_VERSION_ID,
|
||||
@@ -1879,7 +1896,7 @@ public class SolrInformationServer implements InformationServer
|
||||
nmdp.setMaxResults(1);
|
||||
// Gets only one
|
||||
Optional<Collection<NodeMetaData>> nodeMetaDatas = getNodesMetaDataFromRepository(nmdp);
|
||||
allNodeMetaDatas.addAll(nodeMetaDatas.orElse(Collections.emptyList()));
|
||||
allNodeMetaDatas.addAll(nodeMetaDatas.orElse(emptyList()));
|
||||
}
|
||||
|
||||
return allNodeMetaDatas;
|
||||
@@ -1933,7 +1950,7 @@ public class SolrInformationServer implements InformationServer
|
||||
docRef.tenant,
|
||||
docRef.dbId));
|
||||
|
||||
if (docRef.optionalBag.containsKey(CONTENT_LOCALE_FIELD))
|
||||
if (docRef.hasAtLeastOneContentProperty())
|
||||
{
|
||||
addContentToDoc(docRef, doc, docRef.dbId);
|
||||
}
|
||||
@@ -1985,8 +2002,8 @@ public class SolrInformationServer implements InformationServer
|
||||
categorizeNodes(nodes, nodeIdsToNodes, nodeStatusToNodeIds);
|
||||
|
||||
List<Long> deletedNodeIds = notNullOrEmpty(nodeStatusToNodeIds.get(SolrApiNodeStatus.DELETED));
|
||||
List<Long> shardDeletedNodeIds = Collections.emptyList();
|
||||
List<Long> shardUpdatedNodeIds = Collections.emptyList();
|
||||
List<Long> shardDeletedNodeIds = emptyList();
|
||||
List<Long> shardUpdatedNodeIds = emptyList();
|
||||
if (cascadeTrackingEnabled())
|
||||
{
|
||||
shardDeletedNodeIds = notNullOrEmpty(nodeStatusToNodeIds.get(SolrApiNodeStatus.NON_SHARD_DELETED));
|
||||
@@ -2438,7 +2455,7 @@ public class SolrInformationServer implements InformationServer
|
||||
dataModel.getIndexedFieldNamesForProperty(propertyQName).getFields()
|
||||
.stream()
|
||||
.map(FieldInstance::getField)
|
||||
.collect(Collectors.toList()));
|
||||
.collect(toList()));
|
||||
|
||||
for (PropertyValue singleValue : typedValue.getValues())
|
||||
{
|
||||
@@ -2711,12 +2728,17 @@ public class SolrInformationServer implements InformationServer
|
||||
}
|
||||
}
|
||||
|
||||
private void addContentToDoc(TenantDbId docRef, SolrInputDocument doc, long dbId) throws AuthenticationException, IOException
|
||||
private void addContentToDoc(TenantDbId docRef, SolrInputDocument doc, long dbId)
|
||||
{
|
||||
String locale = (String) docRef.optionalBag.get(CONTENT_LOCALE_FIELD);
|
||||
String qNamePart = CONTENT_LOCALE_FIELD.substring(AlfrescoSolrDataModel.CONTENT_S_LOCALE_PREFIX.length());
|
||||
QName propertyQName = QName.createQName(qNamePart);
|
||||
addContentPropertyToDocUsingAlfrescoRepository(doc, propertyQName, dbId, locale);
|
||||
docRef.contentPropertySpecsStream()
|
||||
.forEach(propertySpecs -> {
|
||||
try {
|
||||
var propertyQName = QName.createQName(propertySpecs.fieldName.substring(AlfrescoSolrDataModel.CONTENT_S_LOCALE_PREFIX.length()));
|
||||
addContentPropertyToDocUsingAlfrescoRepository(doc, propertyQName, dbId, propertySpecs.locale);
|
||||
} catch (AuthenticationException | IOException exception) {
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -2829,7 +2851,7 @@ public class SolrInformationServer implements InformationServer
|
||||
{
|
||||
if (mlTextPropertyValue == null)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
List<String> values = new ArrayList<>();
|
||||
@@ -2891,7 +2913,7 @@ public class SolrInformationServer implements InformationServer
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(mlTextPropertyValue::getValue)
|
||||
.collect(Collectors.toList());
|
||||
.collect(toList());
|
||||
|
||||
if (!localisedValues.isEmpty())
|
||||
{
|
||||
|
||||
+5
@@ -234,6 +234,11 @@ solr.request.content.compress=false
|
||||
#
|
||||
solr.initial.transaction.range=0-2000
|
||||
|
||||
|
||||
# set it to true to allow custom d:content fields to be indexed.
|
||||
# N.B. At most one content field can be indexed for each document
|
||||
solr.enableIndexingCustomContent=false
|
||||
|
||||
# Facet query limit when retrieving info for the stats (used in the acl transaction and index transaction reports
|
||||
# and fix)
|
||||
alfresco.stats.facetLimit=100
|
||||
|
||||
+20
@@ -29,6 +29,8 @@ package org.alfresco.solr;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.alfresco.repo.search.adaptor.QueryConstants.FIELD_DOC_TYPE;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.solr.client.Node;
|
||||
import org.alfresco.solr.client.NodeMetaData;
|
||||
import org.alfresco.solr.client.SOLRAPIQueueClient;
|
||||
@@ -79,6 +81,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
@@ -776,6 +779,23 @@ public abstract class AbstractAlfrescoDistributedIT extends SolrITInitializer
|
||||
//First map the nodes to a transaction.
|
||||
SOLRAPIQueueClient.NODE_MAP.put(transaction.getId(), nodes);
|
||||
|
||||
//Next map a node to the NodeMetaData
|
||||
int i=0;
|
||||
for(NodeMetaData nodeMetaData : nodeMetaDatas)
|
||||
{
|
||||
SOLRAPIQueueClient.NODE_META_DATA_MAP.put(nodeMetaData.getId(), nodeMetaData);
|
||||
SOLRAPIQueueClient.NODE_CONTENT_MAP.put(nodeMetaData.getId(), Map.of(ContentModel.PROP_CONTENT, content.get(i++)));
|
||||
}
|
||||
|
||||
//Next add the transaction to the queue
|
||||
SOLRAPIQueueClient.TRANSACTION_QUEUE.add(transaction);
|
||||
}
|
||||
|
||||
public static void indexTransactionWithMultipleContentFields(Transaction transaction, List<Node> nodes, List<NodeMetaData> nodeMetaDatas, List<Map<QName, String>> content)
|
||||
{
|
||||
//First map the nodes to a transaction.
|
||||
SOLRAPIQueueClient.NODE_MAP.put(transaction.getId(), nodes);
|
||||
|
||||
//Next map a node to the NodeMetaData
|
||||
int i=0;
|
||||
for(NodeMetaData nodeMetaData : nodeMetaDatas)
|
||||
|
||||
+3
-1
@@ -26,6 +26,7 @@
|
||||
|
||||
package org.alfresco.solr;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.search.impl.parsers.FTSQueryParser;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.search.SearchParameters;
|
||||
@@ -85,6 +86,7 @@ import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import static java.util.Optional.of;
|
||||
@@ -662,7 +664,7 @@ public abstract class AbstractAlfrescoSolrIT implements SolrTestFiles, AlfrescoS
|
||||
for(NodeMetaData nodeMetaData : nodeMetaDatas)
|
||||
{
|
||||
SOLRAPIQueueClient.NODE_META_DATA_MAP.put(nodeMetaData.getId(), nodeMetaData);
|
||||
SOLRAPIQueueClient.NODE_CONTENT_MAP.put(nodeMetaData.getId(), content.get(i++));
|
||||
SOLRAPIQueueClient.NODE_CONTENT_MAP.put(nodeMetaData.getId(), Map.of(ContentModel.PROP_CONTENT, content.get(i++)));
|
||||
}
|
||||
|
||||
//Next add the transaction to the queue
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Search Services
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -46,7 +46,7 @@ import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ContentTrackerIT
|
||||
public class ContentTrackerTest
|
||||
{
|
||||
private ContentTracker contentTracker;
|
||||
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Search Services
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
package org.alfresco.solr.tracker;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.solr.AbstractAlfrescoDistributedIT;
|
||||
import org.alfresco.solr.client.Acl;
|
||||
import org.alfresco.solr.client.ContentPropertyValue;
|
||||
import org.alfresco.solr.client.Node;
|
||||
import org.alfresco.solr.client.NodeMetaData;
|
||||
import org.alfresco.solr.client.Transaction;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static java.util.stream.IntStream.range;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.MAX_WAIT_TIME;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getAcl;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getAclChangeSet;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getAclReaders;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getNode;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getNodeMetaData;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.getTransaction;
|
||||
import static org.alfresco.solr.AlfrescoSolrUtils.indexAclChangeSet;
|
||||
|
||||
@SolrTestCaseJ4.SuppressSSL
|
||||
public class DistributedContentPropertiesIT extends AbstractAlfrescoDistributedIT
|
||||
{
|
||||
@BeforeClass
|
||||
public static void initData() throws Throwable
|
||||
{
|
||||
var solrCoreProperties = DEFAULT_CORE_PROPS;
|
||||
solrCoreProperties.setProperty("solr.enableIndexingCustomContent", "true");
|
||||
|
||||
initSolrServers(3, DistributedContentPropertiesIT.class.getSimpleName(), solrCoreProperties);
|
||||
}
|
||||
|
||||
@After
|
||||
public void clearData() throws Exception
|
||||
{
|
||||
deleteByQueryAllClients("*:*");
|
||||
explicitCommitOnAllClients();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroyData()
|
||||
{
|
||||
dismissSolrServers();
|
||||
}
|
||||
|
||||
/**
|
||||
* In this scenario we have n nodes.
|
||||
* Among them:
|
||||
*
|
||||
* <ul>
|
||||
* <li>n-m have one default cm:content field </li>
|
||||
* <li>the m do not have a value for the content field (i.e. the value of the content field is empty) </li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
public void eachNodeHasAtMaximumOneCmContentField() throws Exception
|
||||
{
|
||||
putHandleDefaults();
|
||||
|
||||
var aclChangeSet = getAclChangeSet(1, 1);
|
||||
var acl = getAcl(aclChangeSet);
|
||||
|
||||
var aclReaders = getAclReaders(aclChangeSet, acl, singletonList("joel"), singletonList("phil"), null);
|
||||
indexAclChangeSet(aclChangeSet, singletonList(acl), singletonList(aclReaders));
|
||||
|
||||
var howManyTestNodes = 10;
|
||||
|
||||
var transaction = getTransaction(0, howManyTestNodes);
|
||||
|
||||
var nodes = nodes(howManyTestNodes, transaction, acl);
|
||||
var metadata = metadata(nodes, transaction, acl);
|
||||
|
||||
var howManyNodesWithContent = howManyTestNodes - 3;
|
||||
indexTransaction(transaction, nodes, metadata, textContent(nodes, "Lorem ipsum dolor sit amet", howManyNodesWithContent));
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "ipsum")),
|
||||
howManyNodesWithContent, MAX_WAIT_TIME);
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}" + ContentModel.PROP_PERSONDESC.getLocalName(), "ipsum")),
|
||||
0, MAX_WAIT_TIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* In this scenario we have n nodes.
|
||||
* Among them:
|
||||
*
|
||||
* <ul>
|
||||
* <li>n-m have one custom content field (i.e. a field different from cm:content).</li>
|
||||
* <li>the m do not have a value for the content field (i.e. the value of the content field is empty) </li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
public void eachNodeHasAtMaximumOneCustomContentField() throws Exception
|
||||
{
|
||||
putHandleDefaults();
|
||||
|
||||
var aclChangeSet = getAclChangeSet(1, 1);
|
||||
var acl = getAcl(aclChangeSet);
|
||||
|
||||
// Arbitrary acl data.
|
||||
var aclReaders = getAclReaders(aclChangeSet, acl, singletonList("joel"), singletonList("phil"), null);
|
||||
indexAclChangeSet(aclChangeSet, singletonList(acl), singletonList(aclReaders));
|
||||
|
||||
var howManyTestNodes = 10;
|
||||
|
||||
var transaction = getTransaction(0, howManyTestNodes);
|
||||
|
||||
var nodes = nodes(howManyTestNodes, transaction, acl);
|
||||
var metadata =
|
||||
metadata(nodes, transaction, acl).stream()
|
||||
.peek(nodeMetadata -> {
|
||||
nodeMetadata.getProperties().remove(ContentModel.PROP_CONTENT);
|
||||
nodeMetadata.getProperties().put(ContentModel.PROP_PERSONDESC,
|
||||
new ContentPropertyValue(Locale.US, 0L, "UTF-8", "text/plain", null));})
|
||||
.collect(toList());
|
||||
|
||||
var howManyNodesWithContent = howManyTestNodes - 4;
|
||||
var howManyNodesWithoutContent = howManyTestNodes - howManyNodesWithContent;
|
||||
|
||||
var textContents =
|
||||
Stream.concat(
|
||||
range(0, howManyNodesWithContent)
|
||||
.mapToObj(index -> Map.of(ContentModel.PROP_PERSONDESC, "consectetur Adipiscing elit " + System.currentTimeMillis())),
|
||||
range(0, howManyNodesWithoutContent)
|
||||
.mapToObj(index -> Map.of(ContentModel.PROP_PERSONDESC, "")))
|
||||
.collect(toList());
|
||||
|
||||
indexTransactionWithMultipleContentFields(transaction, nodes, metadata, textContents);
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}" + ContentModel.PROP_PERSONDESC.getLocalName(), "adipiscing")),
|
||||
howManyNodesWithContent,
|
||||
MAX_WAIT_TIME);
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "adipiscing")),
|
||||
0, MAX_WAIT_TIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* In this scenario we have n nodes.
|
||||
* Among them:
|
||||
*
|
||||
* <ul>
|
||||
* <li>n-m have one default and one custom content field (i.e. a field different from cm:content).</li>
|
||||
* <li>the m do not have a value for those content fields (i.e. the value of the content fields is empty) </li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
public void eachNodeHasOneCustomAndOneDefaultContentField() throws Exception
|
||||
{
|
||||
putHandleDefaults();
|
||||
|
||||
var aclChangeSet = getAclChangeSet(1, 1);
|
||||
var acl = getAcl(aclChangeSet);
|
||||
|
||||
var aclReaders = getAclReaders(aclChangeSet, acl, singletonList("joel"), singletonList("phil"), null);
|
||||
indexAclChangeSet(aclChangeSet, singletonList(acl), singletonList(aclReaders));
|
||||
|
||||
var howManyTestNodes = 10;
|
||||
|
||||
var transaction = getTransaction(0, howManyTestNodes);
|
||||
|
||||
var nodes = nodes(howManyTestNodes, transaction, acl);
|
||||
var metadata =
|
||||
metadata(nodes, transaction, acl).stream()
|
||||
.peek(nodeMetadata ->
|
||||
nodeMetadata.getProperties().put(ContentModel.PROP_PERSONDESC,
|
||||
new ContentPropertyValue(Locale.US, 0L, "UTF-8", "text/plain", null)))
|
||||
.collect(toList());
|
||||
|
||||
var howManyNodesWithContent = howManyTestNodes - 2;
|
||||
|
||||
indexTransactionWithMultipleContentFields(
|
||||
transaction,
|
||||
nodes,
|
||||
metadata,
|
||||
textContentWithMultipleContentFields(
|
||||
nodes,
|
||||
"Lorem ipsum dolor sit amet",
|
||||
"consectetur Adipiscing elit",
|
||||
howManyNodesWithContent));
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}" + ContentModel.PROP_PERSONDESC.getLocalName(), "consectetur")),
|
||||
howManyNodesWithContent,
|
||||
MAX_WAIT_TIME);
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "ipsum")),
|
||||
howManyNodesWithContent, MAX_WAIT_TIME);
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}" + ContentModel.PROP_PERSONDESC.getLocalName(), "ipsum")),
|
||||
0,
|
||||
MAX_WAIT_TIME);
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "elit")),
|
||||
0, MAX_WAIT_TIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* In this scenario we have n + m + y nodes.
|
||||
* Among them:
|
||||
*
|
||||
* <ul>
|
||||
* <li>n nodes have one custom content field (i.e. a field different from cm:content).</li>
|
||||
* <li>m nodes have one default content field (i.e. cm:content).</li>
|
||||
* <li>y nodes do not have a value for the content field </li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
public void someNodeHasOneCustomAndSomeNodeHasOneDefaultContentField() throws Exception
|
||||
{
|
||||
putHandleDefaults();
|
||||
|
||||
var aclChangeSet = getAclChangeSet(1, 1);
|
||||
var acl = getAcl(aclChangeSet);
|
||||
|
||||
var aclReaders = getAclReaders(aclChangeSet, acl, singletonList("joel"), singletonList("phil"), null);
|
||||
indexAclChangeSet(aclChangeSet, singletonList(acl), singletonList(aclReaders));
|
||||
|
||||
var howManyTestNodes = 10;
|
||||
|
||||
var transaction = getTransaction(0, howManyTestNodes);
|
||||
|
||||
var nodes = nodes(howManyTestNodes, transaction, acl);
|
||||
var metadata =
|
||||
metadata(nodes, transaction, acl).stream()
|
||||
.peek(nodeMetadata ->
|
||||
nodeMetadata.getProperties().put(ContentModel.PROP_PERSONDESC,
|
||||
new ContentPropertyValue(Locale.US, 0L, "UTF-8", "text/plain", null)))
|
||||
.collect(toList());
|
||||
|
||||
var howManyNodesWithContent = howManyTestNodes - 2;
|
||||
var howManyNodesWithDefaultContentField = 3;
|
||||
var howManyNodesWithCustomContentField = howManyNodesWithContent - howManyNodesWithDefaultContentField;
|
||||
var howManyNodesWithoutContent = howManyTestNodes - howManyNodesWithContent;
|
||||
|
||||
var baseCmContentText = "Lorem ipsum dolor sit amet";
|
||||
var basePersonDescriptionText = "consectetur Adipiscing elit";
|
||||
|
||||
var texts =
|
||||
Stream.concat(
|
||||
range(0, howManyNodesWithDefaultContentField)
|
||||
.mapToObj(index -> Map.of(
|
||||
ContentModel.PROP_CONTENT, baseCmContentText + " " + System.currentTimeMillis(),
|
||||
ContentModel.PROP_PERSONDESC, "")),
|
||||
range(0, howManyNodesWithCustomContentField)
|
||||
.mapToObj(index -> Map.of(
|
||||
ContentModel.PROP_CONTENT, "",
|
||||
ContentModel.PROP_PERSONDESC, basePersonDescriptionText + " " + System.currentTimeMillis())));
|
||||
|
||||
var textContents =
|
||||
Stream.concat(
|
||||
texts,
|
||||
range(0, howManyNodesWithoutContent)
|
||||
.mapToObj(index -> Map.of(
|
||||
ContentModel.PROP_CONTENT, "",
|
||||
ContentModel.PROP_PERSONDESC, ""))).collect(toList());
|
||||
|
||||
indexTransactionWithMultipleContentFields(
|
||||
transaction,
|
||||
nodes,
|
||||
metadata,
|
||||
textContents);
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}" + ContentModel.PROP_PERSONDESC.getLocalName(), "consectetur")),
|
||||
howManyNodesWithCustomContentField,
|
||||
MAX_WAIT_TIME);
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "ipsum")),
|
||||
howManyNodesWithDefaultContentField, MAX_WAIT_TIME);
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}" + ContentModel.PROP_PERSONDESC.getLocalName(), "ipsum")),
|
||||
0,
|
||||
MAX_WAIT_TIME);
|
||||
|
||||
waitForDocCount(
|
||||
new TermQuery(
|
||||
new Term("content@s___t@{http://www.alfresco.org/model/content/1.0}content", "elit")),
|
||||
0, MAX_WAIT_TIME);
|
||||
}
|
||||
|
||||
private List<Node> nodes(int howMany, Transaction transaction, Acl acl)
|
||||
{
|
||||
return range(0, howMany)
|
||||
.mapToObj(index -> getNode(transaction, acl, Node.SolrApiNodeStatus.UPDATED))
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
private List<NodeMetaData> metadata(List<Node> nodes, Transaction transaction, Acl acl)
|
||||
{
|
||||
return nodes.stream()
|
||||
.map(node -> getNodeMetaData(node, transaction, acl, "mike", null, false))
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
private List<String> textContent(List<Node> nodes, String baseText, int limit)
|
||||
{
|
||||
return Stream.concat(
|
||||
nodes.stream()
|
||||
.map(node -> baseText + " " + System.currentTimeMillis())
|
||||
.limit(limit),
|
||||
range(0, nodes.size() - limit)
|
||||
.mapToObj(index -> "")).collect(toList());
|
||||
}
|
||||
|
||||
private List<Map<QName, String>> textContentWithMultipleContentFields(List<Node> nodes, String baseCmContentText, String basePersonDescriptionText, int limit)
|
||||
{
|
||||
var texts = nodes.stream()
|
||||
.map(node -> Map.of(
|
||||
ContentModel.PROP_CONTENT, baseCmContentText + " " + System.currentTimeMillis(),
|
||||
ContentModel.PROP_PERSONDESC, basePersonDescriptionText + " " + System.currentTimeMillis()))
|
||||
.limit(limit);
|
||||
|
||||
return Stream.concat(
|
||||
texts,
|
||||
range(0, nodes.size() - limit)
|
||||
.mapToObj(index -> Map.of(
|
||||
ContentModel.PROP_CONTENT, "",
|
||||
ContentModel.PROP_PERSONDESC, ""))).collect(toList());
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Search Services
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -65,7 +65,7 @@ public class SOLRAPIQueueClient extends SOLRAPIClient
|
||||
public final static List<Transaction> TRANSACTION_QUEUE = Collections.synchronizedList(new ArrayList<>());
|
||||
public final static Map<Long, List<Node>> NODE_MAP = Collections.synchronizedMap(new HashMap<>());
|
||||
public final static Map<Long, NodeMetaData> NODE_META_DATA_MAP = Collections.synchronizedMap(new HashMap<>());
|
||||
public final static Map<Long, String> NODE_CONTENT_MAP = Collections.synchronizedMap(new HashMap<>());
|
||||
public final static Map<Long, Map<QName, String>> NODE_CONTENT_MAP = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
private static boolean throwException;
|
||||
|
||||
@@ -154,7 +154,6 @@ public class SOLRAPIQueueClient extends SOLRAPIClient
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
|
||||
public List<AlfrescoModelDiff> getModelsDiff(String coreName, List<AlfrescoModel> currentModels) throws IOException, JSONException
|
||||
{
|
||||
if(throwException)
|
||||
@@ -365,7 +364,7 @@ public class SOLRAPIQueueClient extends SOLRAPIClient
|
||||
|
||||
if(NODE_CONTENT_MAP.containsKey(nodeId))
|
||||
{
|
||||
return new GetTextContentResponse(new DummyResponse(NODE_CONTENT_MAP.get(nodeId)));
|
||||
return new GetTextContentResponse(new DummyResponse(NODE_CONTENT_MAP.get(nodeId).get(propertyQName)));
|
||||
}
|
||||
|
||||
return new GetTextContentResponse(new DummyResponse("Hello world " + nodeId));
|
||||
|
||||
Reference in New Issue
Block a user