Ard Schrijvers pushed to branch feature/translations-psp1 at cms / hippo-repository
Commits: 66b8c3f2 by Ard Schrijvers at 2016-02-17T17:06:54+01:00 REPO-1426 Make sure that the custom indexing now indexes on document level the hippo:name from the handle Before, the hippo:translation nodes where used for indexing on document scope. Since this functionality has moved to the handle, we now need to index the hippo:name from the handle. Added unit tests to confirm this - - - - - 5 changed files: - api/src/main/java/org/hippoecm/repository/api/HippoNodeType.java - engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingIndexingConfiguration.java - engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingIndexingConfigurationImpl.java - engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingSearchIndex.java - engine/src/test/java/org/hippoecm/repository/FreeTextSearchTest.java Changes: ===================================== api/src/main/java/org/hippoecm/repository/api/HippoNodeType.java ===================================== --- a/api/src/main/java/org/hippoecm/repository/api/HippoNodeType.java +++ b/api/src/main/java/org/hippoecm/repository/api/HippoNodeType.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2015 Hippo B.V. (http://www.onehippo.com) + * Copyright 2008-2016 Hippo B.V. (http://www.onehippo.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -158,8 +158,16 @@ public interface HippoNodeType { public static final String NT_TEMPLATETYPE = "hipposysedit:templatetype"; + /** + * @deprecated since REPO 4.0.0 (CMS 11.0) + */ + @Deprecated public static final String NT_TRANSLATED = "hippo:translated"; + /** + * @deprecated since REPO 4.0.0 (CMS 11.0) + */ + @Deprecated public static final String NT_TRANSLATION = "hippo:translation"; @Deprecated @@ -284,6 +292,10 @@ public interface HippoNodeType { public static final String HIPPO_MEMBERS = "hipposys:members"; + /** + * @deprecated since REPO 4.0.0 (CMS 11.0) + */ + @Deprecated public static final String HIPPO_MESSAGE = "hippo:message"; public static final String HIPPO_MANDATORY = "hipposysedit:mandatory"; @@ -368,6 +380,10 @@ public interface HippoNodeType { public static final String HIPPO_TEMPLATE = "hipposysedit:template"; + /** + * @deprecated since REPO 4.0.0 (CMS 11.0) + */ + @Deprecated public static final String HIPPO_TRANSLATION = "hippo:translation"; public static final String HIPPOSYS_TYPE = "hipposys:type"; ===================================== engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingIndexingConfiguration.java ===================================== --- a/engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingIndexingConfiguration.java +++ b/engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingIndexingConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2013 Hippo B.V. (http://www.onehippo.com) + * Copyright 2008-2016 Hippo B.V. (http://www.onehippo.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,21 +49,19 @@ public interface ServicingIndexingConfiguration extends IndexingConfiguration { Name getHippoDocumentName(); /** - * @return QName of hippo:translation + * @return QName for hippo:named mixin */ - Name getHippoTranslationName(); + Name getHippoNamedName(); /** - * @return QName of hippo:message + * @return QName fir hippo:name property */ - Name getHippoMessageName(); - - String getTranslationMessageFieldName(); + Name getHippoNameName(); /** - * @return QName of hippo:translated + * @return the Lucene field name for {@link #getHippoNameName()} */ - Name getHippoTranslatedName(); + String getHippoNameFieldName(); /** * @return QName of the hippo:paths property ===================================== engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingIndexingConfigurationImpl.java ===================================== --- a/engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingIndexingConfigurationImpl.java +++ b/engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingIndexingConfigurationImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2013 Hippo B.V. (http://www.onehippo.com) + * Copyright 2008-2016 Hippo B.V. (http://www.onehippo.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +35,6 @@ import org.apache.jackrabbit.spi.commons.conversion.NameResolver; import org.apache.jackrabbit.spi.commons.conversion.ParsingNameResolver; import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl; import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver; -import org.hippoecm.repository.api.HippoNodeType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Attr; @@ -45,6 +44,14 @@ import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import static org.hippoecm.repository.api.HippoNodeType.HIPPO_NAME; +import static org.hippoecm.repository.api.HippoNodeType.HIPPO_PATHS; +import static org.hippoecm.repository.api.HippoNodeType.HIPPO_TEXT; +import static org.hippoecm.repository.api.HippoNodeType.NT_DOCUMENT; +import static org.hippoecm.repository.api.HippoNodeType.NT_HANDLE; +import static org.hippoecm.repository.api.HippoNodeType.NT_NAMED; +import static org.hippoecm.repository.api.HippoNodeType.NT_SKIPINDEX; + public class ServicingIndexingConfigurationImpl extends IndexingConfigurationImpl implements ServicingIndexingConfiguration { @@ -73,13 +80,11 @@ public class ServicingIndexingConfigurationImpl extends IndexingConfigurationImp private Name hippoDocument; - private Name hippoTranslation; - - private Name hippoMessage; + private Name hippoNamed; - private Name hippoTranslated; + private Name hippoName; - private String translationMessageFieldName; + private String hippoNameFieldName; /** * QName's of all the child node that should be aggregated @@ -191,16 +196,15 @@ public class ServicingIndexingConfigurationImpl extends IndexingConfigurationImp } } - hippoPath = nameResolver.getQName(HippoNodeType.HIPPO_PATHS); - hippoText = nameResolver.getQName(HippoNodeType.HIPPO_TEXT); - hippoHandle = nameResolver.getQName(HippoNodeType.NT_HANDLE); - hippoDocument = nameResolver.getQName(HippoNodeType.NT_DOCUMENT); - hippoTranslation = nameResolver.getQName(HippoNodeType.HIPPO_TRANSLATION); - hippoMessage = nameResolver.getQName(HippoNodeType.HIPPO_MESSAGE); - hippoTranslated = nameResolver.getQName(HippoNodeType.NT_TRANSLATED); - skipIndex = nameResolver.getQName(HippoNodeType.NT_SKIPINDEX); + hippoPath = nameResolver.getQName(HIPPO_PATHS); + hippoText = nameResolver.getQName(HIPPO_TEXT); + hippoHandle = nameResolver.getQName(NT_HANDLE); + hippoDocument = nameResolver.getQName(NT_DOCUMENT); + hippoNamed = nameResolver.getQName(NT_NAMED); + hippoName = nameResolver.getQName(HIPPO_NAME); + hippoNameFieldName = nameResolver.getJCRName(hippoName); + skipIndex = nameResolver.getQName(NT_SKIPINDEX); hippoAggregates = idxHippoAggregates.toArray(new Name[idxHippoAggregates.size()]); - translationMessageFieldName = nameResolver.getJCRName(hippoTranslation) + "/" + nameResolver.getJCRName(hippoMessage); aggregateRules = super.getAggregateRules(); if (aggregateRules == null) { aggregateRules = new AggregateRule[0]; @@ -306,24 +310,20 @@ public class ServicingIndexingConfigurationImpl extends IndexingConfigurationImp return hippoDocument; } - @Override - public Name getHippoTranslationName() { - return hippoTranslation; - } @Override - public Name getHippoMessageName() { - return hippoMessage; + public Name getHippoNamedName() { + return hippoNamed; } @Override - public Name getHippoTranslatedName() { - return hippoTranslated; + public Name getHippoNameName() { + return hippoName; } @Override - public String getTranslationMessageFieldName() { - return translationMessageFieldName; + public String getHippoNameFieldName() { + return hippoNameFieldName; } public Name getHippoPathPropertyName() { ===================================== engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingSearchIndex.java ===================================== --- a/engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingSearchIndex.java +++ b/engine/src/main/java/org/hippoecm/repository/query/lucene/ServicingSearchIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2015 Hippo B.V. (http://www.onehippo.com) + * Copyright 2008-2016 Hippo B.V. (http://www.onehippo.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -395,105 +395,108 @@ public class ServicingSearchIndex extends SearchIndex implements HippoQueryHandl @Override public void updateNodes(Iterator<NodeId> remove, Iterator<NodeState> add) throws RepositoryException, IOException { - Map<NodeId, NodeState> includedNodeStates = new HashMap<>(); - // since NodeState does not have hashcode/equals impls, we need to use NodeId for caches - Set<NodeId> excludedIdsCache = new HashSet<>(); - Set<NodeId> includedIdsCache = new HashSet<>(); + + final Set<NodeId> augmentedRemove = new HashSet<>(); + while (remove.hasNext()) { + augmentedRemove.add(remove.next()); + } + + // NodeState does not implement equals hence we need NodeId + final Map<NodeId, NodeState> augmentedAdd = new HashMap<>(); while (add.hasNext()) { - NodeState state = add.next(); - if (state != null) { - if (!skipIndexing(state, excludedIdsCache, includedIdsCache)) { - includedNodeStates.put(state.getNodeId(), state); - } else { - log.debug("Nodestate '{}' is marked to be skipped for indexing.", state.getId()); - } - } + final NodeState nodeState = add.next(); + // since NodeState does not have hashcode/equals impls, we need to use NodeId for equals in Map + augmentedAdd.put(nodeState.getNodeId(), nodeState); } - NodeIdsNodeStatesHolder augmentedNodeIdsNodeStatesHolder = new NodeIdsNodeStatesHolder(remove, includedNodeStates); - augmentDocumentsToUpdate(augmentedNodeIdsNodeStatesHolder); + appendDocumentsThatHaveChangedChildNodesOrChangedHandles(augmentedRemove, augmentedAdd); - super.updateNodes(augmentedNodeIdsNodeStatesHolder.remove.iterator(), - augmentedNodeIdsNodeStatesHolder.add.values().iterator()); + // now filter out documents that have a 'skip index' marker + Map<NodeId, NodeState> includedNodeStates = getSkipIndexFilteredNodeStates(augmentedAdd); - } + super.updateNodes(augmentedRemove.iterator(), + includedNodeStates.values().iterator()); - private void augmentDocumentsToUpdate(final NodeIdsNodeStatesHolder augmentedNodeIdsNodeStatesHolder) throws IOException, RepositoryException { - appendContainingDocumentStates(augmentedNodeIdsNodeStatesHolder); - appendDocumentsForTranslations(augmentedNodeIdsNodeStatesHolder); } - private void appendDocumentsForTranslations(NodeIdsNodeStatesHolder nodeIdsNodeStatesHolder) throws IOException, RepositoryException { - List<NodeState> toAdd = new ArrayList<>(); - for (Map.Entry<NodeId, NodeState> addEntry : nodeIdsNodeStatesHolder.add.entrySet()) { - final NodeState addedState = addEntry.getValue(); - if (!isTranslation(addedState.getNodeTypeName())) { - continue; - } - try { - final NodeId parentId = addedState.getParentId(); - if (parentId == null) { - continue; - } - final NodeState parentState = getNodeState(parentId); - if (!isHandle(parentState)) { - continue; - } - for (ChildNodeEntry siblingNodeEntry : parentState.getChildNodeEntries()) { - final NodeId siblingId = siblingNodeEntry.getId(); - - if(nodeIdsNodeStatesHolder.add.containsKey(siblingId) || - nodeIdsNodeStatesHolder.remove.contains(siblingId)) { - continue; - } - - final NodeState siblingState = getNodeState(siblingId); - if (!isHippoDocument(siblingState)) { - continue; - } + private Map<NodeId, NodeState> getSkipIndexFilteredNodeStates(final Map<NodeId, NodeState> augmentedAdd) throws RepositoryException { + Map<NodeId, NodeState> includedNodeStates = new HashMap<>(); + // since NodeState does not have hashcode/equals impls, we need to use NodeId for caches + Set<NodeId> excludedIdsCache = new HashSet<>(); + Set<NodeId> includedIdsCache = new HashSet<>(); - if(nodeIdsNodeStatesHolder.add.containsKey(siblingId) || - nodeIdsNodeStatesHolder.remove.contains(siblingId)) { - continue; - } - toAdd.add(siblingState); + for (NodeState nodeState : augmentedAdd.values()) { + if (nodeState != null) { + if (!skipIndexing(nodeState, excludedIdsCache, includedIdsCache)) { + includedNodeStates.put(nodeState.getNodeId(), nodeState); + } else { + log.debug("Nodestate '{}' is marked to be skipped for indexing.", nodeState.getId()); } - } catch (ItemStateException e) { - log.debug("Unable to retrieve state: {}", e.getMessage()); } } - for (NodeState nodeState : toAdd) { - nodeIdsNodeStatesHolder.add.put(nodeState.getNodeId(), nodeState); - nodeIdsNodeStatesHolder.remove.add(nodeState.getNodeId()); - } + return includedNodeStates; } /* - * If node states have been updated that are descendants of hippo:document nodes, then those hippo:document - * nodes need to be re-indexed. + * If node states (below documents) have been newly ADDED (can not yet be found via retrieveAggregateRoot + * since no org.apache.jackrabbit.core.query.lucene.FieldNames.AGGREGATED_NODE_UUID indexed on document level ) + * that are descendants of hippo:document nodes, then those hippo:document nodes need to be re-indexed. + * + * Also re-index documents below changed handles */ - private void appendContainingDocumentStates(NodeIdsNodeStatesHolder nodeIdsNodeStatesHolder) throws RepositoryException, IOException { + private void appendDocumentsThatHaveChangedChildNodesOrChangedHandles(final Set<NodeId> augmentedRemove, + final Map<NodeId, NodeState> augmentedAdd) throws RepositoryException, IOException { final Set<NodeId> checkedIds = new HashSet<>(); - List<NodeState> toAdd = new ArrayList<>(); - for (Map.Entry<NodeId, NodeState> addEntry : nodeIdsNodeStatesHolder.add.entrySet()) { + List<NodeState> nodeStatesToAdd = new ArrayList<>(); + final ItemStateManager itemStateManager = getItemStateManager(); + for (Map.Entry<NodeId, NodeState> addEntry : augmentedAdd.entrySet()) { try { - NodeState document = getContainingDocument(addEntry.getValue(), checkedIds); - if (document != null) { - final NodeId nodeId = document.getNodeId(); - if(nodeIdsNodeStatesHolder.add.containsKey(nodeId) || - nodeIdsNodeStatesHolder.remove.contains(nodeId)) { - continue; + final NodeState state = addEntry.getValue(); + if (isHandle(state)) { + // changed handle (hippo:name translation perhaps, hence re-index the variants) + for (ChildNodeEntry childNodeEntry : state.getChildNodeEntries()) { + if (childNodeEntry.getId() instanceof HippoNodeId) { + // do not index virtual child nodes, ever + continue; + } + + final NodeState childState = (NodeState)itemStateManager.getItemState(childNodeEntry.getId()); + if (isHippoDocument(childState)) { + // found document below changed handle. Add document to be reindexed + addStateIfNeeded(augmentedRemove, augmentedAdd, nodeStatesToAdd, childState); + } } - toAdd.add(document); + continue; + } + + NodeState document = getContainingDocument(state, checkedIds, itemStateManager); + if (document != null) { + addStateIfNeeded(augmentedRemove, augmentedAdd, nodeStatesToAdd, document); + continue; } } catch (ItemStateException e) { log.debug("Unable to retrieve state: {}", e.getMessage()); } } - for (NodeState nodeState : toAdd) { - nodeIdsNodeStatesHolder.add.put(nodeState.getNodeId(), nodeState); - nodeIdsNodeStatesHolder.remove.add(nodeState.getNodeId()); + for (NodeState nodeState : nodeStatesToAdd) { + augmentedAdd.put(nodeState.getNodeId(), nodeState); + augmentedRemove.add(nodeState.getNodeId()); + } + } + + private void addStateIfNeeded(final Set<NodeId> augmentedRemove, + final Map<NodeId, NodeState> augmentedAdd, + final List<NodeState> nodeStates, final NodeState state) { + final NodeId nodeId = state.getNodeId(); + if (nodeId instanceof HippoNodeId) { + // do not index virtual child nodes, ever + return; } + if (augmentedAdd.containsKey(nodeId) || + augmentedRemove.contains(nodeId)) { + return; + } + nodeStates.add(state); } @Override @@ -616,19 +619,15 @@ public class ServicingSearchIndex extends SearchIndex implements HippoQueryHandl return false; } - private boolean isHandle(NodeState node) { + private boolean isHandle(final NodeState node) { return node.getNodeTypeName().equals(getIndexingConfig().getHippoHandleName()); } - private boolean isTranslated(NodeState state) { - return state.getMixinTypeNames().contains(getIndexingConfig().getHippoTranslatedName()); + private boolean isTranslation(final NodeState state) { + return state.getMixinTypeNames().contains(getIndexingConfig().getHippoNamedName()); } - private boolean isTranslation(Name name) { - return name.equals(getIndexingConfig().getHippoTranslationName()); - } - - private boolean isHippoDocument(NodeState node) { + private boolean isHippoDocument(final NodeState node) { try { final EffectiveNodeType nodeType = getContext().getNodeTypeRegistry().getEffectiveNodeType(node.getNodeTypeName()); return nodeType.includesNodeType(getIndexingConfig().getHippoDocumentName()); @@ -642,7 +641,8 @@ public class ServicingSearchIndex extends SearchIndex implements HippoQueryHandl * @return the <code>NodeState</code> of the Document variant which is an ancestor of the state * or <code>null</code> if this state was not a child of a document variant */ - private NodeState getContainingDocument(NodeState state, Set<NodeId> checkedIds) throws ItemStateException { + private NodeState getContainingDocument(final NodeState state, final Set<NodeId> checkedIds, + final ItemStateManager itemStateManager) throws ItemStateException { if (checkedIds.contains(state.getNodeId())) { // already checked these ancestors: no need to do it again return null; @@ -651,24 +651,27 @@ public class ServicingSearchIndex extends SearchIndex implements HippoQueryHandl if (isDocumentVariant(state)) { return state; } - ItemStateManager ism = getItemStateManager(); if (state.getParentId() == null) { return null; } - NodeState parent = (NodeState) ism.getItemState(state.getParentId()); + NodeState parent = (NodeState) itemStateManager.getItemState(state.getParentId()); if (parent == null) { return null; } - return getContainingDocument(parent, checkedIds); + return getContainingDocument(parent, checkedIds, itemStateManager); } /** * Adds the fulltext index field of the child states to Document doc + * * @param aggregateChildTypes When <code>true</code>, properties of child nodes will also be indexed as explicit - * fields on <code>doc</code> if configured as aggregate/childType in indexing_configuration.xml + * fields on <code>doc</code> if configured as aggregate/childType in + * indexing_configuration.xml */ - private void aggregateDescendants(NodeState state, Document doc, IndexFormatVersion indexFormatVersion, ServicingNodeIndexer indexer, boolean aggregateChildTypes) { + private void aggregateDescendants(final NodeState state, final Document doc, + final IndexFormatVersion indexFormatVersion, + final ServicingNodeIndexer indexer, final boolean aggregateChildTypes) { for (ChildNodeEntry childNodeEntry : state.getChildNodeEntries()) { if (childNodeEntry.getId() instanceof HippoNodeId) { // do not index virtual child nodes, ever @@ -753,25 +756,19 @@ public class ServicingSearchIndex extends SearchIndex implements HippoQueryHandl if (parentId == null) { return; } - final NodeState parentState = getNodeState(parentId); - if (!isHandle(parentState) || !isTranslated(parentState)) { + final NodeState handleState = getNodeState(parentId); + if (!isHandle(handleState)) { return; } - for (ChildNodeEntry childNodeEntry : parentState.getChildNodeEntries()) { - final Name childName = childNodeEntry.getName(); - if (!isTranslation(childName)) { - continue; - } - final NodeId translationId = childNodeEntry.getId(); - final NodeState translationState = getNodeState(translationId); - final PropertyId messagePropertyId = new PropertyId(translationState.getNodeId(), getIndexingConfig().getHippoMessageName()); - final PropertyState messagePropertyState = getPropertyState(messagePropertyId); - if (messagePropertyState.getValues().length == 0 || messagePropertyState.getValues()[0] == null || messagePropertyState.getValues()[0].getString().isEmpty()) { - continue; - } - doc.add(new Field(FieldNames.AGGREGATED_NODE_UUID, translationId.toString(), Field.Store.NO, Field.Index.NOT_ANALYZED_NO_NORMS)); - indexer.addStringValue(doc, getIndexingConfig().getTranslationMessageFieldName(), messagePropertyState.getValues()[0].getString(), true, true, 2.0f, true, false); + if (isTranslation(handleState)) { + final PropertyId namePropertyId = new PropertyId(handleState.getNodeId(), getIndexingConfig().getHippoNameName()); + final PropertyState namePropertyState = getPropertyState(namePropertyId); + indexer.addStringValue(doc, getIndexingConfig().getHippoNameFieldName(), namePropertyState.getValues()[0].getString(), true, true, 2.0f, true, false); + } + // make sure that if the handle gets the mixin 'hippo:named' or gets its 'hippo:name' changed, it triggers a re-index on the documents (variants) + doc.add(new Field(FieldNames.AGGREGATED_NODE_UUID, parentId.toString(), Field.Store.NO, Field.Index.NOT_ANALYZED_NO_NORMS)); + } catch (ItemStateException | RepositoryException e) { final String message = "Unable to add index translations of document " + state.getId(); if (log.isDebugEnabled()) { @@ -794,18 +791,4 @@ public class ServicingSearchIndex extends SearchIndex implements HippoQueryHandl return getContext().getItemStateManager(); } - private class NodeIdsNodeStatesHolder { - - Set<NodeId> remove = new HashSet<>(); - // NodeState does not implement equals hence we need NodeId - Map<NodeId, NodeState> add = new HashMap<>(); - - NodeIdsNodeStatesHolder(Iterator<NodeId> remove, Map<NodeId, NodeState> add) { - while(remove.hasNext()) { - this.remove.add(remove.next()); - } - this.add = add; - } - } - } ===================================== engine/src/test/java/org/hippoecm/repository/FreeTextSearchTest.java ===================================== --- a/engine/src/test/java/org/hippoecm/repository/FreeTextSearchTest.java +++ b/engine/src/test/java/org/hippoecm/repository/FreeTextSearchTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2015 Hippo B.V. (http://www.onehippo.com) + * Copyright 2008-2016 Hippo B.V. (http://www.onehippo.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,8 @@ import org.hippoecm.repository.jackrabbit.RepositoryImpl; import org.junit.Test; import org.onehippo.repository.testutils.RepositoryTestCase; +import static org.hippoecm.repository.api.HippoNodeType.HIPPO_NAME; +import static org.hippoecm.repository.api.HippoNodeType.NT_NAMED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -80,18 +82,15 @@ public class FreeTextSearchTest extends RepositoryTestCase { resource.setProperty("jcr:data", new ByteArrayInputStream(data.toByteArray())); resource.setProperty("jcr:lastModified", Calendar.getInstance()); - // set translation node + // set translation Node handle = session.getNode("/test/Document1"); - handle.addMixin("hippo:translated"); - final Node translation = handle.addNode("hippo:translation", "hippo:translation"); - translation.setProperty("hippo:language", "en"); - translation.setProperty("hippo:message", TRANSLATED_DOCUMENT_NAME); + handle.addMixin(NT_NAMED); + handle.setProperty(HIPPO_NAME, TRANSLATED_DOCUMENT_NAME); session.save(); flushIndex(session.getRepository()); } - - + @Test public void testSimpleFreeTextSearch() throws Exception { @@ -140,7 +139,7 @@ public class FreeTextSearchTest extends RepositoryTestCase { */ @Test public void testSecondLevelChildNodeFreeTextSearch() throws Exception { - + createContent(defaultContent); String xpath = "//element(*,hippo:testsearchdocument)[jcr:contains(.,'"+HTML_CONTENT_PART+"')] order by @jcr:score descending"; @@ -163,7 +162,7 @@ public class FreeTextSearchTest extends RepositoryTestCase { */ @Test public void testSecondChildNodeBinaryFreeTextSearch() throws Exception { - + createContent(defaultContent); String xpath = "//element(*,hippo:testsearchdocument)[jcr:contains(.,'"+BINARY_CONTENT_PART+"')] order by @jcr:score descending"; QueryResult queryResult = session.getWorkspace().getQueryManager().createQuery(xpath, "xpath").execute(); @@ -178,6 +177,7 @@ public class FreeTextSearchTest extends RepositoryTestCase { } /** + * This test is to prove we require the FieldNames.AGGREGATED_NODE_UUID logic in ServicingSearchIndex * When we search on the text property of a direct child node below the hippo:document, we should * not find the hippo:document anymore when the child node is removed. This test is to assure that, * when a direct child node is removed, the hippo:document is reindexed in the repository. @@ -187,7 +187,7 @@ public class FreeTextSearchTest extends RepositoryTestCase { */ @Test public void testDeleteFirstLevelChildNode() throws Exception { - + createContent(defaultContent); String xpath = "//element(*,hippo:testsearchdocument)[jcr:contains(.,'"+COMPOUNDDOCUMENT_TITLE_PART+"')] order by @jcr:score descending"; @@ -214,6 +214,7 @@ public class FreeTextSearchTest extends RepositoryTestCase { } /** + * This test is to prove we require the FieldNames.AGGREGATED_NODE_UUID logic in ServicingSearchIndex * When we search on the text property of some child node at some level below the hippo:document, we should * not find the hippo:document anymore when the child node is removed. This test is to assure that, * when a deeper located child node is removed, the hippo:document must is in the repository. @@ -223,7 +224,7 @@ public class FreeTextSearchTest extends RepositoryTestCase { */ @Test public void testDeleteSecondLevelChildNode() throws Exception { - + createContent(defaultContent); String xpath = "//element(*,hippo:testsearchdocument)[jcr:contains(.,'"+HTML_CONTENT_PART+"')] order by @jcr:score descending"; @@ -236,6 +237,7 @@ public class FreeTextSearchTest extends RepositoryTestCase { Node n = session.getNode("/test/Document1/Document1/compoundchild"); n.getNode("hippo:testhtml").remove(); + n.getSession().save(); flushIndex(session.getRepository()); @@ -270,7 +272,7 @@ public class FreeTextSearchTest extends RepositoryTestCase { assertTrue(doc.getName().equals("Document1")); } } - + @Test public void testAddSecondLevelChildNode() throws Exception { String word = "addedhtmlnode"; @@ -281,7 +283,7 @@ public class FreeTextSearchTest extends RepositoryTestCase { }; createContent(defaultContent, extraSecondLevelChildNodeContent); - + String xpath = "//element(*,hippo:testsearchdocument)[jcr:contains(.,'"+word+"')] order by @jcr:score descending"; QueryResult queryResult = session.getWorkspace().getQueryManager().createQuery(xpath, "xpath").execute(); NodeIterator nodes = queryResult.getNodes(); @@ -291,6 +293,40 @@ public class FreeTextSearchTest extends RepositoryTestCase { assertTrue(doc.getName().equals("Document1")); } } + + /** + * This test is to prove {@code }org.hippoecm.repository.query.lucene.ServicingSearchIndex#augmentDocumentsToUpdate} is + * really required. Namely a newly added node won't trigger a document reindex through org.apache.jackrabbit.core.query.lucene.FieldNames.AGGREGATED_NODE_UUID + */ + @Test + public void testAddSecondLevelChildNode_to_existing_document() throws Exception { + String word = "addedhtmlnode"; + createContent(defaultContent); + + session.save(); + flushIndex(session.getRepository()); + { + String xpath = "//element(*,hippo:testsearchdocument)[jcr:contains(.,'" + word + "')] order by @jcr:score descending"; + QueryResult queryResult = session.getWorkspace().getQueryManager().createQuery(xpath, "xpath").execute(); + NodeIterator nodes = queryResult.getNodes(); + assertEquals(0L, nodes.getSize()); + } + final Node html = session.getNode("/test/Document1/Document1/compoundchild").addNode("hippo:html2", "hippo:testhtml"); + html.setProperty("hippo:testcontent", "The content property of testhtml node containing " + word); + session.save(); + flushIndex(session.getRepository()); + + { + String xpath = "//element(*,hippo:testsearchdocument)[jcr:contains(.,'" + word + "')] order by @jcr:score descending"; + QueryResult queryResult = session.getWorkspace().getQueryManager().createQuery(xpath, "xpath").execute(); + NodeIterator nodes = queryResult.getNodes(); + assertEquals(1L, nodes.getSize()); + while (nodes.hasNext()) { + Node doc = nodes.nextNode(); + assertTrue(doc.getName().equals("Document1")); + } + } + } @Test public void testModifyFirstLevelChildNode() throws Exception { @@ -322,6 +358,7 @@ public class FreeTextSearchTest extends RepositoryTestCase { Node html = session.getNode("/test/Document1/Document1/compoundchild/hippo:testhtml"); String word = "changedtesthtml"; html.setProperty("hippo:testcontent", "The content property of testhtml node now containing " + word); + n.getSession().save(); flushIndex(session.getRepository()); @@ -337,11 +374,10 @@ public class FreeTextSearchTest extends RepositoryTestCase { } /** - * All hippo:message properties of hippo:translation nodes under a handle are included - * in the fulltext index of the document. + * new style translation : hippo:name on handle must be indexed on document level */ @Test - public void testSearchOnTranslatedDocumentName() throws Exception { + public void test_translation_SearchOnTranslatedDocumentName() throws Exception { createContent(defaultContent); String xpath = "//element(*,hippo:testsearchdocument)[jcr:contains(.,'"+TRANSLATED_DOCUMENT_NAME+"')] order by @jcr:score descending"; @@ -352,20 +388,32 @@ public class FreeTextSearchTest extends RepositoryTestCase { assertEquals("/test/Document1/Document1", node.getPath()); } - /** - * When the hippo:translation node under a hippo:handle is removed the document's index is updated - */ @Test - public void testRemoveTranslationUpdatesDocumentIndex() throws Exception { + public void test_translation_RemoveTranslation_andAddTranslation_UpdatesDocumentIndex() throws Exception { createContent(defaultContent); - session.getNode("/test/Document1/hippo:translation").remove(); + final Node handle = session.getNode("/test/Document1"); + handle.removeMixin(NT_NAMED); session.save(); flushIndex(session.getRepository()); - String xpath = "//element(*,hippo:testsearchdocument)[jcr:contains(.,'"+TRANSLATED_DOCUMENT_NAME+"')] order by @jcr:score descending"; - final QueryResult queryResult = session.getWorkspace().getQueryManager().createQuery(xpath, "xpath").execute(); - final NodeIterator nodes = queryResult.getNodes(); - assertEquals(0L, nodes.getSize()); + { + String xpath = "//element(*,hippo:testsearchdocument)[jcr:contains(.,'" + TRANSLATED_DOCUMENT_NAME + "')] order by @jcr:score descending"; + final QueryResult queryResult = session.getWorkspace().getQueryManager().createQuery(xpath, "xpath").execute(); + final NodeIterator nodes = queryResult.getNodes(); + assertEquals(0L, nodes.getSize()); + } + + // again adding the translation should result in the document being found by TRANSLATED_DOCUMENT_NAME + handle.addMixin(NT_NAMED); + handle.setProperty(HIPPO_NAME, TRANSLATED_DOCUMENT_NAME); + session.save(); + flushIndex(session.getRepository()); + { + String xpath = "//element(*,hippo:testsearchdocument)[jcr:contains(.,'"+TRANSLATED_DOCUMENT_NAME+"')] order by @jcr:score descending"; + final QueryResult queryResult = session.getWorkspace().getQueryManager().createQuery(xpath, "xpath").execute(); + final NodeIterator nodes = queryResult.getNodes(); + assertEquals(1L, nodes.getSize()); + } } @Test View it on GitLab: https://code.onehippo.org/cms/hippo-repository/commit/66b8c3f2f42cdfc89b66768a7c8c3cccdd67e133
_______________________________________________ Hippocms-svn mailing list Hippocms-svn@lists.onehippo.org https://lists.onehippo.org/mailman/listinfo/hippocms-svn