This is an automated email from the ASF dual-hosted git repository. thomasm pushed a commit to branch OAK-12010-subset2 in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit 577d813a0c8b3a4dc78eef0ead3124ad9570c25a Author: Thomas Mueller <[email protected]> AuthorDate: Mon Feb 16 08:59:44 2026 +0100 OAK-12010 Simplified index management (improvements) --- .../oak/plugins/index/diff/DiffIndex.java | 6 +- .../oak/plugins/index/diff/DiffIndexMerger.java | 84 +++++++++++--- .../oak/plugins/index/diff/JsonNodeUpdater.java | 13 ++- .../plugins/index/diff/RootIndexesListService.java | 1 + .../plugins/index/diff/JsonNodeUpdaterTest.java | 126 +++++++++++---------- .../oak/plugins/index/diff/MergeTest.java | 114 +++++++++++++++++++ 6 files changed, 266 insertions(+), 78 deletions(-) diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/DiffIndex.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/DiffIndex.java index 6df72e2ce8..41cb53bca5 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/DiffIndex.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/DiffIndex.java @@ -117,7 +117,7 @@ public class DiffIndex { diffIndexDefinition.setProperty("error", message + ": " + e.getMessage()); } if (!diffIndexDefinition.hasProperty("info")) { - diffIndexDefinition.setProperty("info", "This diff is are automatically merged with other indexes. See https://oak-indexing.github.io/oakTools/simplified.html"); + diffIndexDefinition.setProperty("info", "This diff is automatically merged with other indexes. See https://oak-indexing.github.io/oakTools/simplified.html"); } } return diffs; @@ -131,7 +131,7 @@ public class DiffIndex { * @param diffs the json object with the combined diffs */ private static void processDiffs(NodeStore store, NodeBuilder indexDefinitions, JsonObject diffs) { - LOG.info("Processing a diffs"); + LOG.info("Processing diffs"); JsonObject repositoryDefinitions = RootIndexesListService.getRootIndexDefinitions(indexDefinitions); LOG.debug("Index list {}", repositoryDefinitions); try { @@ -236,7 +236,7 @@ public class DiffIndex { } } for (String r : toRemove) { - LOG.info("Removing old index {}", r); + LOG.info("Removing old index {}", r); definitions.child(r).remove(); updateNodetypeIndexForPath(definitions, r, false); } diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/DiffIndexMerger.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/DiffIndexMerger.java index 7183828db9..2dbb72996d 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/DiffIndexMerger.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/DiffIndexMerger.java @@ -25,7 +25,9 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.TreeMap; +import java.util.TreeSet; import org.apache.jackrabbit.oak.commons.StringUtils; import org.apache.jackrabbit.oak.commons.json.JsonObject; @@ -68,6 +70,17 @@ public class DiffIndexMerger { // whether to log at info level private final static boolean LOG_AT_INFO_LEVEL = Boolean.getBoolean("oak.diffIndex.logAtInfoLevel"); + // the set of top-level properties that is not allowed to be added to an existing index + private final static Set<String> REJECTED_TOP_LEVEL_PROPS_FOR_EXISTING_INDEX = Set.of("selectionPolicy", "valueRegex", "queryFilterRegex", "excludedPaths", "queryPaths"); + + // the set of child properties that is not allowed to be added if the property is already indexed + // eg. the "name" property may not need to be set if the existing property doesn't have it yet (eg. a function-based index), + // or the "function" property may not need to be set unless if it already exists (eg. a name-based index) + private final static Set<String> REJECTED_PROPS_FOR_EXISTING_PROPERTY = Set.of("isRegexp", "index", "function", "name"); + + // set of properties that are allowed to be changed if the property already exists + private final static Set<String> ALLOW_CHANGING_EXISTING_PROPERTY = Set.of("boost", "weight"); + private String[] unsupportedIncludedPaths; private boolean deleteCreatesDummyIndex; private boolean deleteCopiesOutOfTheBoxIndex; @@ -106,7 +119,7 @@ public class DiffIndexMerger { // read the diff.index.optimizer explicitly, // because it's a not a regular index definition, - // and so in the repositoryDefinitions + // and so it is not in the repositoryDefinitions if (repositoryNodeStore != null) { Map<String, JsonObject> diffInRepo = readDiffIndex(repositoryNodeStore, DIFF_INDEX_OPTIMIZER); combined.getChildren().putAll(diffInRepo); @@ -160,7 +173,12 @@ public class DiffIndexMerger { String key = e.getKey(); JsonObject value = e.getValue(); if (key.startsWith("/oak:index/")) { - LOG.warn("The key should contains just the index name, without the '/oak:index' prefix for key {}", key); + +// document this: +// enumerate error messages +// do not log but write to index def + + LOG.warn("The key should contain just the index name, without the '/oak:index' prefix for key {}", key); key = key.substring("/oak:index/".length()); } log("Processing {}", key); @@ -237,6 +255,8 @@ public class DiffIndexMerger { for (Entry<String, JsonObject> e : indexDefs.getChildren().entrySet()) { String key = e.getKey(); JsonObject value = e.getValue(); + // merged indexes always contain "-custom-". Other indexes may in theory contain that term, + // but then they do not contain "mergeInfo". if (key.indexOf("-custom-") < 0 || !value.getProperties().containsKey("mergeInfo")) { continue; } @@ -327,6 +347,7 @@ public class DiffIndexMerger { log("Latest product: {}", latestProductKey); log("Latest customized: {}", latestCustomizedKey); if (latestProduct == null) { + // if it's not a product index, then verify it's a correctly named custom index if (indexName.indexOf('.') >= 0) { // a fully custom index needs to contains a dot log("Fully custom index {}", indexName); @@ -378,7 +399,7 @@ public class DiffIndexMerger { } else { latestIndexVersion = combined.getChildren().get(latestCustomizedKey); } - JsonObject mergedDef = cleanedAndNormalized(switchToLucene(merged)); + JsonObject mergedDef = cleanedAndNormalized(switchToLuceneIfNeeded(merged)); // compute merge checksum for later, but do not yet add String mergeChecksum = computeMergeChecksum(mergedDef); // get the merge checksum before cleaning (cleaning removes it) - if available @@ -388,7 +409,7 @@ public class DiffIndexMerger { key = prefix + indexName + "-1-custom-1"; } else { String latestMergeChecksum = JsonNodeUpdater.oakStringValue(latestIndexVersion, "mergeChecksum"); - JsonObject latestDef = cleanedAndNormalized(switchToLucene(latestIndexVersion)); + JsonObject latestDef = cleanedAndNormalized(switchToLuceneIfNeeded(latestIndexVersion)); if (isSameIgnorePropertyOrder(mergedDef, latestDef)) { // normal case: no change // (even if checksums do not match: checksums might be missing or manipulated) @@ -510,13 +531,12 @@ public class DiffIndexMerger { * @param indexDef the index definition (is not changed by this method) * @return the lucene version (a new JSON object) */ - public static JsonObject switchToLucene(JsonObject indexDef) { + public static JsonObject switchToLuceneIfNeeded(JsonObject indexDef) { JsonObject obj = JsonObject.fromJson(indexDef.toString(), true); String type = JsonNodeUpdater.oakStringValue(obj, "type"); - if (type == null || !"elasticsearch".equals(type) ) { - return obj; + if ("elasticsearch".equals(type) ) { + switchToLuceneChildren(obj); } - switchToLuceneChildren(obj); return obj; } @@ -627,13 +647,16 @@ public class DiffIndexMerger { */ public JsonObject processMerge(JsonObject productIndex, JsonObject diff) { JsonObject result; + boolean isNew; if (productIndex == null) { // fully custom index result = new JsonObject(true); + isNew = true; } else { result = JsonObject.fromJson(productIndex.toString(), true); + isNew = false; } - mergeInto("", diff, result); + mergeInto("", diff, result, isNew); addPrimaryType("", result); return result; } @@ -672,20 +695,51 @@ public class DiffIndexMerger { * @param path the path * @param diff the diff (what to merge) * @param target where to merge into + * @param isNew whether the target node is newly created (didn't exist before) */ - private void mergeInto(String path, JsonObject diff, JsonObject target) { + private void mergeInto(String path, JsonObject diff, JsonObject target, boolean isNew) { for (String p : diff.getProperties().keySet()) { if (path.isEmpty()) { if ("jcr:primaryType".equals(p)) { continue; } } + if (!isNew) { + // for existing nodes, we do a few more checks before the merge + if (path.isEmpty() && REJECTED_TOP_LEVEL_PROPS_FOR_EXISTING_INDEX.contains(p)) { + // at the top level, some properties (eg. selectionPolicy) are not allowed to be added to an existing index + LOG.warn("Ignoring new top-level property {} at {} for existing index", p, path); + continue; + } + if (REJECTED_PROPS_FOR_EXISTING_PROPERTY.contains(p)) { + // the some properties are not allowed to be added if the node already exists + LOG.warn("Ignoring new property {} at {} for existing child", p, path); + continue; + } + } if (target.getProperties().containsKey(p)) { - // we do not currently allow to overwrite most existing properties - if (p.equals("boost")) { + // we do not currently allow to overwrite most existing properties, + // except for: + if (ALLOW_CHANGING_EXISTING_PROPERTY.contains(p)) { // allow overwriting the boost value LOG.info("Overwrite property {} value at {}", p, path); target.getProperties().put(p, diff.getProperties().get(p)); + } else if (path.isEmpty() && (p.equals("includedPaths") || p.equals("queryPaths") || p.equals("tags"))) { + // merge includedPaths, queryPaths, and tags + if (target.getProperties().containsKey(p)) { + // but only if the old value is set, such that it contains more entries + // (if the property is not set, we would make it more restrictive, + // which is not allowed) + TreeSet<String> oldSet = JsonNodeUpdater.getStringSet(target.getProperties().get(p)); + TreeSet<String> newSet = JsonNodeUpdater.getStringSet(diff.getProperties().get(p)); + TreeSet<String> mergedSet = new TreeSet<String>(oldSet); + mergedSet.addAll(newSet); + JsopBuilder buff = new JsopBuilder().array(); + for(String v : mergedSet) { + buff.value(v); + } + target.getProperties().put(p, buff.endArray().toString()); + } } else { LOG.warn("Ignoring existing property {} at {}", p, path); } @@ -694,8 +748,10 @@ public class DiffIndexMerger { } } for (String c : diff.getChildren().keySet()) { + boolean childIsNew; String targetChildName = c; if (!target.getChildren().containsKey(c)) { + childIsNew = true; if (path.endsWith("/properties")) { // search for a property with the same "name" value String propertyName = diff.getChildren().get(c).getProperties().get("name"); @@ -720,8 +776,10 @@ public class DiffIndexMerger { // only create the child (properties are added below) target.getChildren().put(c, new JsonObject()); } + } else { + childIsNew = false; } - mergeInto(path + "/" + targetChildName, diff.getChildren().get(c), target.getChildren().get(targetChildName)); + mergeInto(path + "/" + targetChildName, diff.getChildren().get(c), target.getChildren().get(targetChildName), childIsNew); } if (target.getProperties().isEmpty() && target.getChildren().isEmpty()) { if (deleteCreatesDummyIndex) { diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/JsonNodeUpdater.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/JsonNodeUpdater.java index a5dabdbce7..99e7a74452 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/JsonNodeUpdater.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/JsonNodeUpdater.java @@ -66,14 +66,16 @@ public class JsonNodeUpdater { /** * Add a replace a node, including all child nodes, in the node store. * + * @param builder the builder to add the node to * @param nodeStore the target node store - * @param targetPath the target path where the node(s) is/are replaced + * @param targetPath the target path (relative to the builder) where the node(s) is/are replaced * @param nodeType the node type of the new node (eg. "nt:unstructured") * @param jsonString the json string with the node data * @throws CommitFailedException if storing the nodes failed * @throws IOException if storing a blob failed */ - public static void addOrReplace(NodeBuilder builder, NodeStore nodeStore, String targetPath, String nodeType, String jsonString) throws CommitFailedException, IOException { + public static void addOrReplace(NodeBuilder builder, NodeStore nodeStore, String targetPath, + String nodeType, String jsonString) throws CommitFailedException, IOException { LOG.info("Storing {}: {}", targetPath, jsonString); if (nodeType.contains("/")) { throw new IllegalStateException("Illegal node type: " + nodeType); @@ -245,6 +247,13 @@ public class JsonNodeUpdater { } } + /** + * Parse a raw JSON value and convert it to a set of strings. Also supported is a single string value. + * Everything else (numbers, booleans, etc.) is not supported and returns null. + * + * @param value the raw JSON value + * @return a set of strings or null + */ public static TreeSet<String> getStringSet(String value) { if (value == null) { return null; diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/RootIndexesListService.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/RootIndexesListService.java index 806278f154..f09e495f51 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/RootIndexesListService.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/diff/RootIndexesListService.java @@ -100,6 +100,7 @@ public class RootIndexesListService implements IndexPathService { return list; } for (ChildNodeEntry cn : oakIndex.getChildNodeEntries()) { + // ignore entries that are not of type oak:QueryIndexDefinition if (!IndexConstants.INDEX_DEFINITIONS_NODE_TYPE .equals(cn.getNodeState().getName("jcr:primaryType"))) { continue; diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/diff/JsonNodeUpdaterTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/diff/JsonNodeUpdaterTest.java index 4bcc5db181..4462820011 100644 --- a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/diff/JsonNodeUpdaterTest.java +++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/diff/JsonNodeUpdaterTest.java @@ -29,6 +29,7 @@ import java.util.TreeSet; import org.apache.jackrabbit.oak.api.CommitFailedException; import org.apache.jackrabbit.oak.commons.json.JsonObject; +import org.apache.jackrabbit.oak.commons.json.JsopBuilder; import org.apache.jackrabbit.oak.json.JsonUtils; import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore; import org.apache.jackrabbit.oak.spi.commit.CommitInfo; @@ -59,24 +60,24 @@ public class JsonNodeUpdaterTest { NodeBuilder builder = ns.getRoot().builder(); JsonNodeUpdater.addOrReplace(builder, ns, "/test", "nt:test", json.toString()); ns.merge(builder, new EmptyHook(), CommitInfo.EMPTY); - String json2 = JsonUtils.nodeStateToJson(ns.getRoot(), 5); - json2 = json2.replaceAll("jcr:uuid\" : \".*\"", "jcr:uuid\" : \"...\""); + String json2 = reformatJson(JsonUtils.nodeStateToJson(ns.getRoot(), 5)); + json2 = json2.replaceAll("jcr:uuid\": \".*\"", "jcr:uuid\": \"...\""); assertEquals("{\n" - + " \"test\" : {\n" - + " \"queryPaths\" : \"/same\",\n" - + " \"includedPaths\" : \"/same\",\n" - + " \"jcr:primaryType\" : \"nt:unstructured\",\n" - + " \"type\" : \"lucene\",\n" - + " \":childOrder\" : [ \"diff.json\" ],\n" - + " \"diff.json\" : {\n" - + " \"jcr:primaryType\" : \"nt:file\",\n" - + " \":childOrder\" : [ \"jcr:content\" ],\n" - + " \"jcr:content\" : {\n" - + " \"jcr:mimeType\" : \"application/json\",\n" - + " \"jcr:data\" : \"test\",\n" - + " \"jcr:primaryType\" : \"nt:resource\",\n" - + " \"jcr:uuid\" : \"...\",\n" - + " \":childOrder\" : [ ]\n" + + " \"test\": {\n" + + " \"queryPaths\": \"/same\",\n" + + " \"includedPaths\": \"/same\",\n" + + " \"jcr:primaryType\": \"nt:unstructured\",\n" + + " \"type\": \"lucene\",\n" + + " \":childOrder\": [\"diff.json\"],\n" + + " \"diff.json\": {\n" + + " \"jcr:primaryType\": \"nt:file\",\n" + + " \":childOrder\": [\"jcr:content\"],\n" + + " \"jcr:content\": {\n" + + " \"jcr:mimeType\": \"application/json\",\n" + + " \"jcr:data\": \"test\",\n" + + " \"jcr:primaryType\": \"nt:resource\",\n" + + " \"jcr:uuid\": \"...\",\n" + + " \":childOrder\": []\n" + " }\n" + " }\n" + " }\n" @@ -90,18 +91,18 @@ public class JsonNodeUpdaterTest { JsonNodeUpdater.addOrReplace(builder, ns, "/test", "nt:test", json.toString()); ns.merge(builder, new EmptyHook(), CommitInfo.EMPTY); assertEquals("{\n" - + " \"test\" : {\n" - + " \"number\" : 1,\n" - + " \"double2\" : 1.0,\n" - + " \"jcr:primaryType\" : \"nt:test\",\n" - + " \":childOrder\" : [ \"child2\" ],\n" - + " \"child2\" : {\n" - + " \"y\" : 2,\n" - + " \"jcr:primaryType\" : \"nt:test\",\n" - + " \":childOrder\" : [ ]\n" + + " \"test\": {\n" + + " \"number\": 1,\n" + + " \"double2\": 1.0,\n" + + " \"jcr:primaryType\": \"nt:test\",\n" + + " \":childOrder\": [\"child2\"],\n" + + " \"child2\": {\n" + + " \"y\": 2,\n" + + " \"jcr:primaryType\": \"nt:test\",\n" + + " \":childOrder\": []\n" + " }\n" + " }\n" - + "}", JsonUtils.nodeStateToJson(ns.getRoot(), 5)); + + "}", reformatJson(JsonUtils.nodeStateToJson(ns.getRoot(), 5))); } @Test @@ -118,21 +119,21 @@ public class JsonNodeUpdaterTest { JsonNodeUpdater.addOrReplace(builder, ns, "/test", "nt:test", json.toString()); ns.merge(builder, new EmptyHook(), CommitInfo.EMPTY); assertEquals("{\n" - + " \"test\" : {\n" - + " \"number\" : 1,\n" - + " \"blob\" : \"test\",\n" - + " \"string\" : \"hello\",\n" - + " \"array\" : [ \"a\", \"b\" ],\n" - + " \"double\" : 1.0,\n" - + " \"jcr:primaryType\" : \"nt:test\",\n" - + " \":childOrder\" : [ \"child\" ],\n" - + " \"child\" : {\n" - + " \"x\" : 1,\n" - + " \"jcr:primaryType\" : \"nt:test\",\n" - + " \":childOrder\" : [ ]\n" + + " \"test\": {\n" + + " \"number\": 1,\n" + + " \"blob\": \"test\",\n" + + " \"string\": \"hello\",\n" + + " \"array\": [\"a\", \"b\"],\n" + + " \"double\": 1.0,\n" + + " \"jcr:primaryType\": \"nt:test\",\n" + + " \":childOrder\": [\"child\"],\n" + + " \"child\": {\n" + + " \"x\": 1,\n" + + " \"jcr:primaryType\": \"nt:test\",\n" + + " \":childOrder\": []\n" + " }\n" + " }\n" - + "}", JsonUtils.nodeStateToJson(ns.getRoot(), 5)); + + "}", reformatJson(JsonUtils.nodeStateToJson(ns.getRoot(), 5))); json = JsonObject.fromJson( "{\"number\":1," + @@ -142,18 +143,23 @@ public class JsonNodeUpdaterTest { JsonNodeUpdater.addOrReplace(builder, ns, "/test", "nt:test", json.toString()); ns.merge(builder, new EmptyHook(), CommitInfo.EMPTY); assertEquals("{\n" - + " \"test\" : {\n" - + " \"number\" : 1,\n" - + " \"double2\" : 1.0,\n" - + " \"jcr:primaryType\" : \"nt:test\",\n" - + " \":childOrder\" : [ \"child2\" ],\n" - + " \"child2\" : {\n" - + " \"y\" : 2,\n" - + " \"jcr:primaryType\" : \"nt:test\",\n" - + " \":childOrder\" : [ ]\n" + + " \"test\": {\n" + + " \"number\": 1,\n" + + " \"double2\": 1.0,\n" + + " \"jcr:primaryType\": \"nt:test\",\n" + + " \":childOrder\": [\"child2\"],\n" + + " \"child2\": {\n" + + " \"y\": 2,\n" + + " \"jcr:primaryType\": \"nt:test\",\n" + + " \":childOrder\": []\n" + " }\n" + " }\n" - + "}", JsonUtils.nodeStateToJson(ns.getRoot(), 5)); + + "}", reformatJson(JsonUtils.nodeStateToJson(ns.getRoot(), 5))); + } + + String reformatJson(String json) { + // replace \r\n with \n + return JsopBuilder.prettyPrint(json); } @Test @@ -210,17 +216,17 @@ public class JsonNodeUpdaterTest { JsonNodeUpdater.addOrReplace(builder, ns, "/test", "nt:test", json.toString()); ns.merge(builder, new EmptyHook(), CommitInfo.EMPTY); assertEquals("{\n" - + " \"test\" : {\n" - + " \"namValue\" : \"acme:Test\",\n" - + " \"boolTrue\" : true,\n" - + " \"boolFalse\" : false,\n" - + " \"datValue\" : \"2024-01-19\",\n" - + " \"escapedArray\" : [ \"/content/path\" ],\n" - + " \"jcr:primaryType\" : \"nt:test\",\n" - + " \"strValue\" : \"hello\",\n" - + " \":childOrder\" : [ ]\n" + + " \"test\": {\n" + + " \"namValue\": \"acme:Test\",\n" + + " \"boolTrue\": true,\n" + + " \"boolFalse\": false,\n" + + " \"datValue\": \"2024-01-19\",\n" + + " \"escapedArray\": [\"/content/path\"],\n" + + " \"jcr:primaryType\": \"nt:test\",\n" + + " \"strValue\": \"hello\",\n" + + " \":childOrder\": []\n" + " }\n" - + "}", JsonUtils.nodeStateToJson(ns.getRoot(), 5)); + + "}", reformatJson(JsonUtils.nodeStateToJson(ns.getRoot(), 5))); } } diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/diff/MergeTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/diff/MergeTest.java index b8e63fe9c3..76cafdc642 100644 --- a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/diff/MergeTest.java +++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/diff/MergeTest.java @@ -160,6 +160,120 @@ public class MergeTest { + "}", merged); } + @Test + public void ignoredNewPropertiesForExisting() { + // for existing indexes or properties, + // some additions are not allowed, as they could result in the index + // to be not usable for existing queries + // (eg. the selectionPolicy may not be set if the index already exists) + String merged = new DiffIndexMerger().processMerge(JsonObject.fromJson("{\n" + + " \"jcr:primaryType\": \"nam:oak:IndexDefinition\",\n" + + " \"type\": \"lucene\",\n" + + " \"async\": [\"async\", \"nrt\"],\n" + + " \"indexRules\": {\n" + + " \"dam:Asset\": {\n" + + " \"properties\": {\n" + + " \"named\": {\n" + + " \"name\": \"x\"\n" + + " },\n" + + " \"functionBased\": {\n" + + " \"function\": \"upper(x)\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "", true), JsonObject.fromJson("{ \n" + + " \"tags\": [\"newTag\"],\n" + + " \"selectionPolicy\": \"tag\",\n" + + " \"indexRules\": {\n" + + " \"dam:Asset\": {\n" + + " \"properties\": {\n" + + " \"named\": {\n" + + " \"function\": \"upper(y)\",\n" + + " \"weight\": 10.0\n" + + " },\n" + + " \"functionBased\": {\n" + + " \"name\": \"y\",\n" + + " \"weight\": 20.0\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }", true)).toString(); + assertEquals("{\n" + + " \"jcr:primaryType\": \"nam:oak:IndexDefinition\",\n" + + " \"type\": \"lucene\",\n" + + " \"async\": [\"async\", \"nrt\"],\n" + + " \"tags\": [\"newTag\"],\n" + + " \"indexRules\": {\n" + + " \"jcr:primaryType\": \"nam:nt:unstructured\",\n" + + " \"dam:Asset\": {\n" + + " \"jcr:primaryType\": \"nam:nt:unstructured\",\n" + + " \"properties\": {\n" + + " \"jcr:primaryType\": \"nam:nt:unstructured\",\n" + + " \"named\": {\n" + + " \"name\": \"x\",\n" + + " \"weight\": 10.0,\n" + + " \"jcr:primaryType\": \"nam:nt:unstructured\"\n" + + " },\n" + + " \"functionBased\": {\n" + + " \"function\": \"upper(x)\",\n" + + " \"weight\": 20.0,\n" + + " \"jcr:primaryType\": \"nam:nt:unstructured\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}", merged); + } + + @Test + public void customizeIncludedPathsQueryPathsAndTags() { + String merged = new DiffIndexMerger().processMerge(JsonObject.fromJson("{\n" + + " \"jcr:primaryType\": \"nam:oak:IndexDefinition\",\n" + + " \"type\": \"lucene\",\n" + + " \"async\": [\"async\", \"nrt\"],\n" + + " \"tags\": [\"abc\", \"def\"],\n" + + " \"includedPaths\": \"/content/dam\",\n" + + " \"indexRules\": {\n" + + " \"dam:Asset\": {\n" + + " \"properties\": {\n" + + " \"x\": {\n" + + " \"name\": \"x\",\n" + + " \"propertyIndex\": true\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "", true), JsonObject.fromJson("{ \n" + + " \"includedPaths\": [\"/content/dam\", \"/content/additional\" ],\n" + + " \"tags\": [\"def\", \"ghi\" ]\n" + + " }", true)).toString(); + assertEquals("{\n" + + " \"jcr:primaryType\": \"nam:oak:IndexDefinition\",\n" + + " \"type\": \"lucene\",\n" + + " \"async\": [\"async\", \"nrt\"],\n" + + " \"tags\": [\"abc\", \"def\", \"ghi\"],\n" + + " \"includedPaths\": [\"/content/additional\", \"/content/dam\"],\n" + + " \"indexRules\": {\n" + + " \"jcr:primaryType\": \"nam:nt:unstructured\",\n" + + " \"dam:Asset\": {\n" + + " \"jcr:primaryType\": \"nam:nt:unstructured\",\n" + + " \"properties\": {\n" + + " \"jcr:primaryType\": \"nam:nt:unstructured\",\n" + + " \"x\": {\n" + + " \"name\": \"x\",\n" + + " \"propertyIndex\": true,\n" + + " \"jcr:primaryType\": \"nam:nt:unstructured\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}", merged); + } + @Test public void renamedFunction() { // A function might be indexed twice, by adding two children to the "properties" node
