This is an automated email from the ASF dual-hosted git repository.

nfsantos pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git


The following commit(s) were added to refs/heads/trunk by this push:
     new dde6148344 OAK-11764 - Query planner: when multiple indexes have same 
cost, planner should choose index deterministically (#2349)
dde6148344 is described below

commit dde6148344c448c8cb77a7e870aed2c4f9adb630
Author: Nuno Santos <[email protected]>
AuthorDate: Wed Jun 25 10:29:54 2025 +0200

    OAK-11764 - Query planner: when multiple indexes have same cost, planner 
should choose index deterministically (#2349)
---
 .../jackrabbit/oak/plugins/index/IndexName.java    |  2 +-
 .../org/apache/jackrabbit/oak/query/QueryImpl.java |  3 +-
 .../index/lucene/LuceneIndexInfoProviderTest.java  |  4 +--
 .../index/lucene/LuceneIndexLookupTest.java        |  8 ++---
 .../index/lucene/LucenePropertyIndexTest.java      | 34 ++++++++++++++++++++--
 5 files changed, 40 insertions(+), 11 deletions(-)

diff --git 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexName.java 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexName.java
index 6ad2005a56..3597079d28 100644
--- 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexName.java
+++ 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexName.java
@@ -210,7 +210,7 @@ public class IndexName implements Comparable<IndexName> {
      * @return the filtered list
      */
     public static Collection<String> filterReplacedIndexes(Collection<String> 
indexPaths, NodeState rootState, boolean checkIsActive) {
-        HashMap<String, IndexName> latestVersions = new HashMap<String, 
IndexName>();
+        HashMap<String, IndexName> latestVersions = new HashMap<>();
         for (String p : indexPaths) {
             IndexName indexName = IndexName.parse(p);
             if (indexName.isVersioned && checkIsActive) {
diff --git 
a/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java 
b/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
index 397e1c201b..35ada0ad68 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
@@ -1132,7 +1132,8 @@ public class QueryImpl implements Query {
                         String msg = String.format("cost for [%s] of type (%s) 
with plan [%s] is %1.2f", p.getPlanName(), indexName, plan, c);
                         logDebug(msg);
                     }
-                    if (c < bestCost) {
+                    // In case of cost being the same, chose the index with 
the lowest name by alphabetic order
+                    if (c < bestCost || (c == bestCost && bestPlan != null && 
p.getPlanName().compareTo(bestPlan.getPlanName()) < 0 )) {
                         almostBestCost = bestCost;
                         almostBestIndex = bestIndex;
                         almostBestPlan = bestPlan;
diff --git 
a/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProviderTest.java
 
b/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProviderTest.java
index 3dc6c61812..275be4b660 100644
--- 
a/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProviderTest.java
+++ 
b/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProviderTest.java
@@ -43,8 +43,8 @@ public class LuceneIndexInfoProviderTest {
 
     @Rule
     public final TemporaryFolder temporaryFolder = new TemporaryFolder(new 
File("target"));
-    private NodeStore store = new MemoryNodeStore();
-    private AsyncIndexInfoService asyncService = 
mock(AsyncIndexInfoService.class);
+    private final NodeStore store = new MemoryNodeStore();
+    private final AsyncIndexInfoService asyncService = 
mock(AsyncIndexInfoService.class);
     private LuceneIndexInfoProvider provider;
 
     @Before
diff --git 
a/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexLookupTest.java
 
b/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexLookupTest.java
index af486e9bba..e360a8d89e 100644
--- 
a/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexLookupTest.java
+++ 
b/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexLookupTest.java
@@ -35,12 +35,12 @@ import static 
org.apache.jackrabbit.oak.InitialContentHelper.INITIAL_CONTENT;
 import static org.junit.Assert.assertEquals;
 
 public class LuceneIndexLookupTest {
-    private NodeState root = INITIAL_CONTENT;
+    private final NodeState root = INITIAL_CONTENT;
 
-    private NodeBuilder builder = root.builder();
+    private final NodeBuilder builder = root.builder();
 
     @Test
-    public void collectPathOnRootNode() throws Exception{
+    public void collectPathOnRootNode() {
         NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
         newLuceneIndexDefinition(index, "l1", Set.of(TYPENAME_STRING));
         newLuceneIndexDefinition(index, "l2", Set.of(TYPENAME_STRING));
@@ -53,7 +53,7 @@ public class LuceneIndexLookupTest {
     }
 
     @Test
-    public void collectPathOnSubNode() throws Exception{
+    public void collectPathOnSubNode() {
         NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
         newLuceneIndexDefinition(index, "l1", Set.of(TYPENAME_STRING));
 
diff --git 
a/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
 
b/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
index bc7edbb592..53dd4e788c 100644
--- 
a/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
+++ 
b/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
@@ -317,7 +317,7 @@ public class LucenePropertyIndexTest extends 
AbstractQueryTest {
     public void declaringNodeTypeSameProp() throws Exception {
         createIndex("test1", Set.of("propa"));
 
-        Tree indexWithType = createIndex("test2", Set.of("propa"));
+        Tree indexWithType = createIndex("atest2", Set.of("propa"));
         indexWithType.setProperty(PropertyStates
                 .createProperty(DECLARING_NODE_TYPES, 
Set.of("nt:unstructured"),
                         Type.STRINGS));
@@ -339,7 +339,7 @@ public class LucenePropertyIndexTest extends 
AbstractQueryTest {
         root.commit();
 
         String propabQuery = "select [jcr:path] from [nt:unstructured] where 
[propa] = 'foo'";
-        assertThat(explain(propabQuery), containsString("lucene:test2"));
+        assertThat(explain(propabQuery), containsString("lucene:atest2"));
         assertQuery(propabQuery, List.of("/test/a", "/test/b"));
 
         String propcdQuery = "select [jcr:path] from [nt:base] where [propa] = 
'foo'";
@@ -347,6 +347,34 @@ public class LucenePropertyIndexTest extends 
AbstractQueryTest {
         assertQuery(propcdQuery, List.of("/test/a", "/test/b", "/test/c", 
"/test/d"));
     }
 
+
+    @Test
+    public void selectLowerAlphabeticOrderWhenSameCost() throws Exception {
+        createIndex("test3", Set.of("propa"));
+        createIndex("test1", Set.of("propa"));
+        createIndex("test2", Set.of("propa"));
+
+        Tree test = root.getTree("/").addChild("test");
+        test.setProperty("jcr:primaryType", "nt:unstructured", Type.NAME);
+        root.commit();
+
+        Tree a = test.addChild("a");
+        a.setProperty("jcr:primaryType", "nt:unstructured", Type.NAME);
+        a.setProperty("propa", "foo");
+        Tree b = test.addChild("b");
+        b.setProperty("jcr:primaryType", "nt:unstructured", Type.NAME);
+        b.setProperty("propa", "foo");
+
+        test.addChild("c").setProperty("propa", "foo");
+        test.addChild("d").setProperty("propa", "foo");
+
+        root.commit();
+
+        String propabQuery = "select [jcr:path] from [nt:unstructured] where 
[propa] = 'foo'";
+        assertThat(explain(propabQuery), containsString("lucene:test1"));
+        assertQuery(propabQuery, List.of("/test/a", "/test/b"));
+    }
+
     @Test
     public void declaringNodeTypeSingleIndex() throws Exception {
         Tree indexWithType = createIndex("test2", Set.of("propa", "propb"));
@@ -2064,7 +2092,7 @@ public class LucenePropertyIndexTest extends 
AbstractQueryTest {
             s.append("foo bar ").append(k).append(" ");
         }
         String text = s.toString();
-        List<String> names = new LinkedList<String>();
+        List<String> names = new LinkedList<>();
         for (int j = 0; j < 30; j++) {
             Tree test = root.getTree("/").addChild("ex-test-" + j);
             for (int i = 0; i < 100; i++) {

Reply via email to