You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by fo...@apache.org on 2023/03/21 10:55:00 UTC

[jackrabbit-oak] branch trunk updated: OAK-10146: oak-search-elastic: similarity search does not work for some nodes (#873)

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

fortino 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 05a85635b4 OAK-10146: oak-search-elastic: similarity search does not work for some nodes (#873)
05a85635b4 is described below

commit 05a85635b4d9b45a9e715951121f304d464bd5d4
Author: Fabrizio Fortino <fa...@gmail.com>
AuthorDate: Tue Mar 21 11:54:54 2023 +0100

    OAK-10146: oak-search-elastic: similarity search does not work for some nodes (#873)
    
    * OAK-10146: removed duplicate tests already part of oak-search common tests
    
    * OAK-10146: workaround for https://github.com/elastic/elasticsearch/pull/94518
    
    * OAK-10146: consolidate usage of java 9/10 immutable data structures
---
 .../index/elastic/query/ElasticRequestHandler.java |  12 +-
 .../index/elastic/ElasticSimilarQueryTest.java     | 113 +++++--------------
 .../plugins/index/elastic/ElasticTestServer.java   |  19 ++--
 .../oak/plugins/index/IndexQueryCommonTest.java    | 123 +++++++++++----------
 4 files changed, 106 insertions(+), 161 deletions(-)

diff --git a/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticRequestHandler.java b/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticRequestHandler.java
index 5a61bee0e1..324945d801 100644
--- a/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticRequestHandler.java
+++ b/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elastic/query/ElasticRequestHandler.java
@@ -35,7 +35,6 @@ import java.io.IOException;
 import java.io.StringReader;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Base64;
 import java.util.HashMap;
 import java.util.List;
@@ -116,7 +115,7 @@ public class ElasticRequestHandler {
     private static final Logger LOG = LoggerFactory.getLogger(ElasticRequestHandler.class);
     private final static String SPELLCHECK_PREFIX = "spellcheck?term=";
     protected final static String SUGGEST_PREFIX = "suggest?term=";
-    private static final List<SortOptions> DEFAULT_SORTS = Arrays.asList(
+    private static final List<SortOptions> DEFAULT_SORTS = List.of(
             SortOptions.of(so -> so.field(f -> f.field("_score").order(SortOrder.Desc))),
             SortOptions.of(so -> so.field(f -> f.field(FieldNames.PATH).order(SortOrder.Asc)))
     );
@@ -389,11 +388,14 @@ public class ElasticRequestHandler {
             // We store path as the _id so no need to do anything extra here
             // We expect Similar impl to send a query where text would have evaluated to
             // node path.
-            mlt.like(l -> l.document(d -> d.id(id)));
+            mlt.like(l -> l.document(d -> d.id(id)
+                    // this is needed to workaround https://github.com/elastic/elasticsearch/pull/94518 that causes empty
+                    // results when the _ignored metadata field is part of the input document
+                    .perFieldAnalyzer("_ignored", "keyword")));
         } else {
             // This is for native queries if someone sends additional fields via
             // mlt.fl=field1,field2
-            mlt.like(l -> l.document(d -> d.fields(Arrays.asList(fields.split(","))).id(id)));
+            mlt.like(l -> l.document(d -> d.fields(List.of(fields.split(","))).id(id)));
         }
         // include the input doc to align the Lucene behaviour TODO: add configuration
         // parameter
@@ -424,7 +426,7 @@ public class ElasticRequestHandler {
             mltParamSetter.accept(MoreLikeThisHelperUtil.MLT_STOP_WORDS, (val) -> {
                 // TODO : Read this from a stopwords text file, configured via index defn maybe
                 // ?
-                mlt.stopWords(Arrays.asList(val.split(",")));
+                mlt.stopWords(List.of(val.split(",")));
             });
 
             if (!shallowMltParams.isEmpty()) {
diff --git a/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticSimilarQueryTest.java b/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticSimilarQueryTest.java
index 74696a4b47..b4a51d6c51 100644
--- a/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticSimilarQueryTest.java
+++ b/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticSimilarQueryTest.java
@@ -32,13 +32,10 @@ import org.junit.Test;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.net.URI;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -48,6 +45,7 @@ import java.util.Map;
 import java.util.Random;
 import java.util.UUID;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static org.apache.jackrabbit.oak.plugins.index.elastic.util.ElasticIndexUtils.toByteArray;
 import static org.apache.jackrabbit.oak.plugins.index.elastic.util.ElasticIndexUtils.toDoubles;
@@ -56,79 +54,6 @@ import static org.junit.Assert.assertNotEquals;
 
 public class ElasticSimilarQueryTest extends ElasticAbstractQueryTest {
 
-    /*
-    This test mirror the test org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexQueryTest#testRepSimilarAsNativeQuery
-    Exact same test data, to test out for feature parity
-    The only difference is the same query in lucene returns the doc itself (the one that we need similar docs of) as part of search results
-    whereas in elastic, it doesn't.
-     */
-    @Test
-    public void repSimilarAsNativeQuery() throws Exception {
-
-        createIndex(true);
-
-        String nativeQueryString = "select [jcr:path] from [nt:base] where " +
-                "native('elastic-sim', 'mlt?stream.body=/test/c&mlt.fl=:path&mlt.mindf=0&mlt.mintf=0')";
-        Tree test = root.getTree("/").addChild("test");
-        test.addChild("a").setProperty("text", "Hello World");
-        test.addChild("b").setProperty("text", "He said Hello and then the world said Hello as well.");
-        test.addChild("c").setProperty("text", "He said Hi.");
-        root.commit();
-
-        assertEventually(() -> assertQuery(nativeQueryString, Arrays.asList("/test/c", "/test/b")));
-    }
-
-    /*
-    This test mirror the test org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexQueryTest#testRepSimilarQuery
-    Exact same test data, to test out for feature parity
-    The only difference is the same query in lucene returns the doc itself (the one that we need similar docs of) as part of search results
-    whereas in elastic, it doesn't.
-     */
-    @Test
-    public void repSimilarQuery() throws Exception {
-        createIndex(false);
-
-        String query = "select [jcr:path] from [nt:base] where similar(., '/test/a')";
-        Tree test = root.getTree("/").addChild("test");
-        test.addChild("a").setProperty("text", "Hello World Hello World");
-        test.addChild("b").setProperty("text", "Hello World");
-        test.addChild("c").setProperty("text", "World");
-        test.addChild("d").setProperty("text", "Hello");
-        test.addChild("e").setProperty("text", "Bye Bye");
-        test.addChild("f").setProperty("text", "Hello");
-        test.addChild("g").setProperty("text", "World");
-        test.addChild("h").setProperty("text", "Hello");
-        root.commit();
-
-        assertEventually(() -> assertQuery(query,
-                Arrays.asList("/test/a", "/test/b", "/test/c", "/test/d", "/test/f", "/test/g", "/test/h")));
-    }
-
-    /*
-    This test mirror the test org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexQueryTest#testRepSimilarXPathQuery
-    Exact same test data, to test out for feature parity
-    The only difference is the same query in lucene returns the doc itself (the one that we need similar docs of) as part of search results
-    whereas in elastic, it doesn't.
-     */
-    @Test
-    public void repSimilarXPathQuery() throws Exception {
-        createIndex(false);
-
-        String query = "//element(*, nt:base)[rep:similar(., '/test/a')]";
-        Tree test = root.getTree("/").addChild("test");
-        test.addChild("a").setProperty("text", "Hello World Hello World");
-        test.addChild("b").setProperty("text", "Hello World");
-        test.addChild("c").setProperty("text", "World");
-        test.addChild("d").setProperty("text", "Hello");
-        test.addChild("e").setProperty("text", "Bye Bye");
-        test.addChild("f").setProperty("text", "Hello");
-        test.addChild("g").setProperty("text", "World");
-        test.addChild("h").setProperty("text", "Hello");
-        root.commit();
-        assertEventually(() -> assertQuery(query, XPATH,
-                Arrays.asList("/test/a", "/test/b", "/test/c", "/test/d", "/test/f", "/test/g", "/test/h")));
-    }
-
     @Test
     public void repSimilarWithStopWords() throws Exception {
         createIndex(true);
@@ -150,11 +75,10 @@ public class ElasticSimilarQueryTest extends ElasticAbstractQueryTest {
         root.commit();
 
         // Matches due to terms Hello or bye should be ignored
-        assertEventually(() -> assertQuery(nativeQueryStringWithStopWords,
-                Arrays.asList("/test/a", "/test/e", "/test/f")));
+        assertEventually(() -> assertQuery(nativeQueryStringWithStopWords, List.of("/test/a", "/test/e", "/test/f")));
 
         assertEventually(() -> assertQuery(nativeQueryStringWithoutStopWords,
-                Arrays.asList("/test/a", "/test/b", "/test/c", "/test/d", "/test/e", "/test/f")));
+                List.of("/test/a", "/test/b", "/test/c", "/test/d", "/test/e", "/test/f")));
     }
 
     @Test
@@ -175,11 +99,10 @@ public class ElasticSimilarQueryTest extends ElasticAbstractQueryTest {
 
         // Matches because of term Hello should be ignored since wl <6 (so /test/ should NOT be in the match list)
         // /test/d should be in match list (because of Worlds term)
-        assertEventually(() -> assertQuery(nativeQueryStringWithMinWordLength,
-                Arrays.asList("/test/a", "/test/c", "/test/d")));
+        assertEventually(() -> assertQuery(nativeQueryStringWithMinWordLength, List.of("/test/a", "/test/c", "/test/d")));
 
         assertEventually(() -> assertQuery(nativeQueryStringWithoutMinWordLength,
-                Arrays.asList("/test/a", "/test/b", "/test/c", "/test/d")));
+                List.of("/test/a", "/test/b", "/test/c", "/test/d")));
     }
 
     @Test
@@ -204,7 +127,25 @@ public class ElasticSimilarQueryTest extends ElasticAbstractQueryTest {
         String query = "select [jcr:path] from [nt:base] where similar(., '" + p + "')";
 
         assertEventually(() -> assertQuery(query,
-                Arrays.asList(p, "/test/b", "/test/c", "/test/d", "/test/f", "/test/g", "/test/h")));
+                List.of(p, "/test/b", "/test/c", "/test/d", "/test/f", "/test/g", "/test/h")));
+    }
+
+    /**
+     * Validates the workaround for <a href="https://github.com/elastic/elasticsearch/pull/94518">94518</a> produces the
+     * expected results
+     */
+    @Test
+    public void repSimilarQueryWithIgnoredMetadataField() throws Exception {
+        createIndex(false);
+        Tree test = root.getTree("/").addChild("test");
+
+        // the max keyword length is 256, this field will be then listed as _ignored
+        test.addChild("a").setProperty("text", ElasticTestUtils.randomString(1000));
+        root.commit();
+
+        String query = "select [jcr:path] from [nt:base] where similar(., '/test/a')";
+
+        assertEventually(() -> assertQuery(query, List.of("/test/a")));
     }
 
     @Test
@@ -278,7 +219,7 @@ public class ElasticSimilarQueryTest extends ElasticAbstractQueryTest {
 
         for (String line : IOUtils.readLines(Files.newInputStream(file.toPath()), Charset.defaultCharset())) {
             String[] split = line.split(",");
-            List<Double> values = Arrays.stream(split).skip(1).map(Double::parseDouble).collect(Collectors.toList());
+            List<Double> values = Stream.of(split).skip(1).map(Double::parseDouble).collect(Collectors.toList());
             byte[] bytes = toByteArray(values);
             List<Double> actual = toDoubles(bytes);
             assertEquals(values, actual);
@@ -305,10 +246,10 @@ public class ElasticSimilarQueryTest extends ElasticAbstractQueryTest {
         URI uri = getClass().getResource("/org/apache/jackrabbit/oak/query/fvs.csv").toURI();
         File file = new File(uri);
 
-        Collection<String> children = new LinkedList<>();
+        List<String> children = new LinkedList<>();
         for (String line : IOUtils.readLines(Files.newInputStream(file.toPath()), Charset.defaultCharset())) {
             String[] split = line.split(",");
-            List<Double> values = Arrays.stream(split).skip(1).map(Double::parseDouble).collect(Collectors.toList());
+            List<Double> values = Stream.of(split).skip(1).map(Double::parseDouble).collect(Collectors.toList());
             byte[] bytes = toByteArray(values);
             List<Double> actual = toDoubles(bytes);
             assertEquals(values, actual);
diff --git a/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticTestServer.java b/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticTestServer.java
index dcfc39abae..baf65a33bd 100644
--- a/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticTestServer.java
+++ b/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elastic/ElasticTestServer.java
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.plugins.index.elastic;
 
 import co.elastic.clients.transport.Version;
 import com.github.dockerjava.api.DockerClient;
-import com.google.common.collect.ImmutableMap;
 import org.apache.jackrabbit.oak.commons.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,15 +41,15 @@ import static org.junit.Assume.assumeNotNull;
 
 public class ElasticTestServer implements AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(ElasticTestServer.class);
-    private static final Map<String, String> PLUGIN_OFFICIAL_RELEASES_DIGEST_MAP = ImmutableMap.<String, String>builder()
-            .put("7.17.3.0", "5e3b40bb72b2813f927be9bf6ecdf88668d89d2ef20c7ebafaa51ab8407fd179")
-            .put("7.17.6.0", "326893bb98ef1a0c569d9f4c4a9a073e53361924f990b17e87077985ce8a7478")
-            .put("7.17.7.0", "4252eb55cc7775f1b889d624ac335abfa2e357931c40d0accb4d520144246b8b")
-            .put("8.3.3.0", "14d3223456f4b9f00f86628ec8400cb46513935e618ae0f5d0d1088739ccc233")
-            .put("8.4.1.0", "56797a1bac6ceeaa36d2358f818b14633124d79c5e04630fa3544603d82eaa01")
-            .put("8.4.2.0", "5ce81ad043816900a496ad5b3cce7de1d99547ebf92aa1f9856343e48580c71c")
-            .put("8.4.3.0", "5c00d43cdd56c5c5d8e9032ad507acea482fb5ca9445861c5cc12ad63af66425")
-            .build();
+    private static final Map<String, String> PLUGIN_OFFICIAL_RELEASES_DIGEST_MAP = Map.of(
+            "7.17.3.0", "5e3b40bb72b2813f927be9bf6ecdf88668d89d2ef20c7ebafaa51ab8407fd179",
+            "7.17.6.0", "326893bb98ef1a0c569d9f4c4a9a073e53361924f990b17e87077985ce8a7478",
+            "7.17.7.0", "4252eb55cc7775f1b889d624ac335abfa2e357931c40d0accb4d520144246b8b",
+            "8.3.3.0", "14d3223456f4b9f00f86628ec8400cb46513935e618ae0f5d0d1088739ccc233",
+            "8.4.1.0", "56797a1bac6ceeaa36d2358f818b14633124d79c5e04630fa3544603d82eaa01",
+            "8.4.2.0", "5ce81ad043816900a496ad5b3cce7de1d99547ebf92aa1f9856343e48580c71c",
+            "8.4.3.0", "5c00d43cdd56c5c5d8e9032ad507acea482fb5ca9445861c5cc12ad63af66425",
+            "8.5.3.0", "d4c13f68650f9df5ff8c74ec83abc2e416de9c45f991d459326e0e2baf7b0e3f");
 
     private static final ElasticTestServer SERVER = new ElasticTestServer();
     private static volatile ElasticsearchContainer CONTAINER;
diff --git a/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexQueryCommonTest.java b/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexQueryCommonTest.java
index 413e51db91..ec9009fa46 100644
--- a/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexQueryCommonTest.java
+++ b/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexQueryCommonTest.java
@@ -26,19 +26,18 @@ import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
 import org.apache.jackrabbit.oak.query.AbstractQueryTest;
 import org.apache.jackrabbit.oak.query.SQL2Parser;
 import org.junit.After;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.slf4j.event.Level;
 
 import java.text.ParseException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
 import javax.jcr.query.Query;
 
-import static java.util.Collections.singletonList;
-import static java.util.Arrays.asList;
 import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
 import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
 import static org.apache.jackrabbit.oak.api.QueryEngine.NO_BINDINGS;
@@ -48,6 +47,7 @@ import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PRO
 import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.PROP_VALUE_REGEX;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -222,7 +222,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
     @Test
     public void descendantTest2() throws Exception {
         Tree test = root.getTree("/").addChild("test");
-        test.addChild("a").setProperty("name", asList("Hello", "World"), STRINGS);
+        test.addChild("a").setProperty("name", List.of("Hello", "World"), STRINGS);
         test.addChild("b").setProperty("name", "Hello");
         root.commit();
 
@@ -269,18 +269,18 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         String w = "World" + System.currentTimeMillis();
 
         Tree test = root.getTree("/").addChild("test");
-        test.addChild("a").setProperty("name", asList(h, w), STRINGS);
+        test.addChild("a").setProperty("name", List.of(h, w), STRINGS);
         test.addChild("b").setProperty("name", h);
         root.commit();
 
         // query 'hello'
         assertEventually(() ->
-                assertQuery("/jcr:root//*[jcr:contains(., '" + h + "')]", "xpath", asList("/test/a", "/test/b"))
+                assertQuery("/jcr:root//*[jcr:contains(., '" + h + "')]", "xpath", List.of("/test/a", "/test/b"))
         );
 
         // query 'world'
         assertEventually(() ->
-                assertQuery("/jcr:root//*[jcr:contains(., '" + w + "')]", "xpath", singletonList("/test/a"))
+                assertQuery("/jcr:root//*[jcr:contains(., '" + w + "')]", "xpath", List.of("/test/a"))
         );
     }
 
@@ -293,8 +293,8 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         test.addChild("c").setProperty("name", "hello");
         root.commit();
 
-        assertQuery("/jcr:root//*[jcr:contains(., 'hello-wor*')]", "xpath", asList("/test/a", "/test/b"));
-        assertQuery("/jcr:root//*[jcr:contains(., '*hello-wor*')]", "xpath", asList("/test/a", "/test/b"));
+        assertQuery("/jcr:root//*[jcr:contains(., 'hello-wor*')]", "xpath", List.of("/test/a", "/test/b"));
+        assertQuery("/jcr:root//*[jcr:contains(., '*hello-wor*')]", "xpath", List.of("/test/a", "/test/b"));
     }
 
     @Ignore("OAK-2424")
@@ -305,8 +305,8 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         test.addChild("b").setProperty("dc:format", "progress");
         root.commit();
 
-        assertQuery("/jcr:root//*[jcr:contains(@dc:format, 'pro*')]", "xpath", singletonList("/test/b"));
-        assertQuery("/jcr:root//*[jcr:contains(@dc:format, 'type:appli*')]", "xpath", singletonList("/test/a"));
+        assertQuery("/jcr:root//*[jcr:contains(@dc:format, 'pro*')]", "xpath", List.of("/test/b"));
+        assertQuery("/jcr:root//*[jcr:contains(@dc:format, 'type:appli*')]", "xpath", List.of("/test/a"));
     }
 
     @Test
@@ -316,7 +316,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         root.commit();
 
         String stmt = "//*[jcr:contains(., '/parent/child')]";
-        assertEventually(() -> assertQuery(stmt, "xpath", singletonList("/test/a")));
+        assertEventually(() -> assertQuery(stmt, "xpath", List.of("/test/a")));
     }
 
     @Test
@@ -327,7 +327,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         root.commit();
 
         String stmt = "//*[jcr:contains(., '/segment1/segment2')]";
-        assertEventually(() -> assertQuery(stmt, "xpath", singletonList("/test/a")));
+        assertEventually(() -> assertQuery(stmt, "xpath", List.of("/test/a")));
     }
 
     @Test
@@ -337,7 +337,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         root.commit();
 
         String stmt = "//*[jcr:contains(., 'match')]";
-        assertEventually(() -> assertQuery(stmt, "xpath", singletonList("/match_on_path")));
+        assertEventually(() -> assertQuery(stmt, "xpath", List.of("/match_on_path")));
     }
 
     @Test
@@ -347,7 +347,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         root.commit();
 
         String stmt = "//*[jcr:contains(., 'match')]";
-        assertEventually(() -> assertQuery(stmt, "xpath", singletonList("/match_on_path1234")));
+        assertEventually(() -> assertQuery(stmt, "xpath", List.of("/match_on_path1234")));
     }
 
     /**
@@ -371,7 +371,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         root.commit();
 
         String stmt = "//*[jcr:contains(., 'media') and (@p = 'dam/smartcollection' or @p = 'dam/collection') ]";
-        assertEventually(() -> assertQuery(stmt, "xpath", asList(one.getPath(), two.getPath())));
+        assertEventually(() -> assertQuery(stmt, "xpath", List.of(one.getPath(), two.getPath())));
     }
 
     @Test
@@ -388,13 +388,13 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
             assertEquals("/test/a", result.next());
             assertFalse(result.hasNext());
         });
-        Assert.assertNotEquals(0, logCustomizer.getLogs().size());
-        Assert.assertTrue("native query WARN message is not present, message in Logger is "
+        assertNotEquals(0, logCustomizer.getLogs().size());
+        assertTrue("native query WARN message is not present, message in Logger is "
                 +  logCustomizer.getLogs(), logCustomizer.getLogs().get(0).contains(nativeQueryString));
     }
 
     @Test
-    public void testRepSimilarAsNativeQuery() throws Exception {
+    public void repSimilarAsNativeQuery() throws Exception {
         String nativeQueryString = "select [jcr:path] from [nt:base] where " +
                 "native('lucene', 'mlt?stream.body=/test/a&mlt.fl=:path&mlt.mindf=0&mlt.mintf=0')";
         Tree test = root.getTree("/").addChild("test");
@@ -410,20 +410,20 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
             assertEquals("/test/b", result.next());
             assertFalse(result.hasNext());
         });
-        Assert.assertNotEquals(0, logCustomizer.getLogs().size());
-        Assert.assertTrue("native query WARN message is not present, message in Logger is "
+        assertNotEquals(0, logCustomizer.getLogs().size());
+        assertTrue("native query WARN message is not present, message in Logger is "
                 +  logCustomizer.getLogs(), logCustomizer.getLogs().get(0).contains(nativeWarnLog));
     }
 
     @Test
-    public void testRepSimilarQuery() throws Exception {
+    public void repSimilarQuery() throws Exception {
         String query = "select [jcr:path] from [nt:base] where similar(., '/test/a')";
         Tree test = root.getTree("/").addChild("test");
         test.addChild("a").setProperty("text", "Hello World Hello World");
         test.addChild("b").setProperty("text", "Hello World");
         test.addChild("c").setProperty("text", "World");
         test.addChild("d").setProperty("text", "Hello");
-        test.addChild("e").setProperty("text", "World");
+        test.addChild("e").setProperty("text", "Bye Bye");
         test.addChild("f").setProperty("text", "Hello");
         test.addChild("g").setProperty("text", "World");
         test.addChild("h").setProperty("text", "Hello");
@@ -435,18 +435,19 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
             assertTrue(result.hasNext());
             assertEquals("/test/b", result.next());
             assertTrue(result.hasNext());
+            assertQuery(query, List.of("/test/a", "/test/b", "/test/c", "/test/d", "/test/f", "/test/g", "/test/h"));
         });
     }
 
     @Test
-    public void testRepSimilarXPathQuery() throws Exception {
+    public void repSimilarXPathQuery() throws Exception {
         String query = "//element(*, nt:base)[rep:similar(., '/test/a')]";
         Tree test = root.getTree("/").addChild("test");
         test.addChild("a").setProperty("text", "Hello World Hello World");
         test.addChild("b").setProperty("text", "Hello World");
         test.addChild("c").setProperty("text", "World");
         test.addChild("d").setProperty("text", "Hello");
-        test.addChild("e").setProperty("text", "World");
+        test.addChild("e").setProperty("text", "Bye Bye");
         test.addChild("f").setProperty("text", "Hello");
         test.addChild("g").setProperty("text", "World");
         test.addChild("h").setProperty("text", "Hello");
@@ -457,6 +458,8 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
             assertEquals("/test/a", result.next());
             assertTrue(result.hasNext());
             assertEquals("/test/b", result.next());
+            assertQuery(query, "xpath",
+                    List.of("/test/a", "/test/b", "/test/c", "/test/d", "/test/f", "/test/g", "/test/h"));
         });
     }
 
@@ -466,7 +469,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         Tree one = t.addChild("one");
         one.setProperty("t", "美女衬衫");
         root.commit();
-        assertEventually(() -> assertQuery("//*[jcr:contains(., '美女')]", "xpath", singletonList(one.getPath())));
+        assertEventually(() -> assertQuery("//*[jcr:contains(., '美女')]", "xpath", List.of(one.getPath())));
     }
 
     @Test
@@ -474,15 +477,15 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         Tree test = root.getTree("/").addChild("test");
         String child = "child";
         String mulValuedProp = "prop";
-        test.addChild(child).setProperty(mulValuedProp, asList("foo", "bar"), STRINGS);
+        test.addChild(child).setProperty(mulValuedProp, List.of("foo", "bar"), STRINGS);
         root.commit();
-        assertEventually(() -> assertQuery("/jcr:root//*[jcr:contains(@" + mulValuedProp + ", 'foo')]", "xpath", singletonList("/test/" + child)));
+        assertEventually(() -> assertQuery("/jcr:root//*[jcr:contains(@" + mulValuedProp + ", 'foo')]", "xpath", List.of("/test/" + child)));
 
-        test.getChild(child).setProperty(mulValuedProp, new ArrayList<>(), STRINGS);
+        test.getChild(child).setProperty(mulValuedProp, List.of(), STRINGS);
         root.commit();
         assertEventually(() -> assertQuery("/jcr:root//*[jcr:contains(@" + mulValuedProp + ", 'foo')]", "xpath", new ArrayList<>()));
 
-        test.getChild(child).setProperty(mulValuedProp, singletonList("bar"), STRINGS);
+        test.getChild(child).setProperty(mulValuedProp, List.of("bar"), STRINGS);
         root.commit();
         assertEventually(() -> assertQuery("/jcr:root//*[jcr:contains(@" + mulValuedProp + ", 'foo')]", "xpath", new ArrayList<>()));
 
@@ -522,19 +525,19 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         assertEventually(() -> {
             assertQuery(
                     "SELECT * FROM [nt:unstructured] WHERE ISDESCENDANTNODE('/test') AND CONTAINS(foo, 'bar')",
-                    asList("/test/a", "/test/d"));
+                    List.of("/test/a", "/test/d"));
 
             assertQuery(
                     "SELECT * FROM [nt:unstructured] WHERE ISDESCENDANTNODE('/test') AND NOT CONTAINS(foo, 'bar')",
-                    asList("/test/b", "/test/c"));
+                    List.of("/test/b", "/test/c"));
 
             assertQuery(
                     "SELECT * FROM [nt:unstructured] WHERE ISDESCENDANTNODE('/test') AND CONTAINS(foo, 'bar cat')",
-                    singletonList("/test/d"));
+                    List.of("/test/d"));
 
             assertQuery(
                     "SELECT * FROM [nt:unstructured] WHERE ISDESCENDANTNODE('/test') AND NOT CONTAINS(foo, 'bar cat')",
-                    singletonList("/test/c"));
+                    List.of("/test/c"));
         });
         setTraversalEnabled(true);
     }
@@ -554,7 +557,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         root.commit();
 
         String query = "//*[jcr:contains(@propa, 'Hello *ship')] ";
-        assertEventually(() -> assertQuery(query, XPATH, Arrays.asList("/test/e")));
+        assertEventually(() -> assertQuery(query, XPATH, List.of("/test/e")));
     }
 
 
@@ -572,7 +575,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         root.commit();
 
         String query = "//*[jcr:contains(@propa, '*ship to can*')] ";
-        assertEventually(() -> assertQuery(query, XPATH, Arrays.asList("/test/a", "/test/b", "/test/c")));
+        assertEventually(() -> assertQuery(query, XPATH, List.of("/test/a", "/test/b", "/test/c")));
     }
 
     @Test
@@ -594,24 +597,24 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
 
         assertEventually(() -> {
             // case insensitive
-            assertQuery("//*[jcr:contains(., 'WORLD')] ", XPATH, Arrays.asList("/test/nodeb", "/test/nodec"));
+            assertQuery("//*[jcr:contains(., 'WORLD')] ", XPATH, List.of("/test/nodeb", "/test/nodec"));
 
             // wild card
-            assertQuery("//*[jcr:contains(., 'Hell*')] ", XPATH, Arrays.asList("/test/nodea", "/test/nodeb", "/test/nodec"));
-            assertQuery("//*[jcr:contains(., 'He*o')] ", XPATH, Arrays.asList("/test/nodea", "/test/nodeb", "/test/nodec"));
-            assertQuery("//*[jcr:contains(., '*llo')] ", XPATH, Arrays.asList("/test/nodea", "/test/nodeb", "/test/nodec"));
-            assertQuery("//*[jcr:contains(., '?orld')] ", XPATH, Arrays.asList("/test/nodeb", "/test/nodec"));
-            assertQuery("//*[jcr:contains(., 'wo?ld')] ", XPATH, Arrays.asList("/test/nodeb", "/test/nodec"));
-            assertQuery("//*[jcr:contains(., 'worl?')] ", XPATH, Arrays.asList("/test/nodeb", "/test/nodec"));
+            assertQuery("//*[jcr:contains(., 'Hell*')] ", XPATH, List.of("/test/nodea", "/test/nodeb", "/test/nodec"));
+            assertQuery("//*[jcr:contains(., 'He*o')] ", XPATH, List.of("/test/nodea", "/test/nodeb", "/test/nodec"));
+            assertQuery("//*[jcr:contains(., '*llo')] ", XPATH, List.of("/test/nodea", "/test/nodeb", "/test/nodec"));
+            assertQuery("//*[jcr:contains(., '?orld')] ", XPATH, List.of("/test/nodeb", "/test/nodec"));
+            assertQuery("//*[jcr:contains(., 'wo?ld')] ", XPATH, List.of("/test/nodeb", "/test/nodec"));
+            assertQuery("//*[jcr:contains(., 'worl?')] ", XPATH, List.of("/test/nodeb", "/test/nodec"));
 
             // space explained as AND
-            assertQuery("//*[jcr:contains(., 'hello world')] ", XPATH, Arrays.asList("/test/nodeb", "/test/nodec"));
+            assertQuery("//*[jcr:contains(., 'hello world')] ", XPATH, List.of("/test/nodeb", "/test/nodec"));
 
             // exclude
-            assertQuery("//*[jcr:contains(., 'hello -world')] ", XPATH, Arrays.asList("/test/nodea"));
+            assertQuery("//*[jcr:contains(., 'hello -world')] ", XPATH, List.of("/test/nodea"));
 
             // explicit OR
-            assertQuery("//*[jcr:contains(., 'ocean OR world')] ", XPATH, Arrays.asList("/test/nodea", "/test/nodeb", "/test/nodec"));
+            assertQuery("//*[jcr:contains(., 'ocean OR world')] ", XPATH, List.of("/test/nodea", "/test/nodeb", "/test/nodec"));
         });
     }
 
@@ -633,7 +636,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
 
         String query2 = "/jcr:root/test//*[propa!='bar']";
 
-        assertEventually(() -> assertQuery(query2, XPATH, Arrays.asList("/test/test1", "/test/test2", "/test/test3")));
+        assertEventually(() -> assertQuery(query2, XPATH, List.of("/test/test1", "/test/test2", "/test/test3")));
     }
 
     @Test
@@ -652,7 +655,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
 
         String query2 = "select * from [nt:base] as s where propa is not null and ISDESCENDANTNODE(s, '/test')";
 
-        assertEventually(() -> assertQuery(query2, SQL2, Arrays.asList("/test/test1", "/test/test2", "/test/test3")));
+        assertEventually(() -> assertQuery(query2, SQL2, List.of("/test/test1", "/test/test2", "/test/test3")));
     }
 
     @Test
@@ -672,7 +675,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
 
         String query2 = "//*[propa!='bar']";
 
-        assertEventually(() -> assertQuery(query2, XPATH, Arrays.asList("/test1", "/test2", "/test3")));
+        assertEventually(() -> assertQuery(query2, XPATH, List.of("/test1", "/test2", "/test3")));
     }
 
     @Test
@@ -693,7 +696,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         String query2 = "/jcr:root/test//*[propa!='bar' and propb='world']";
         // Expected - nodes with both properties defined and propb with value 'world' and propa with value not equal to bar should be returned
         // /test/test6 should NOT be returned because for it propa = null
-        assertEventually(() -> assertQuery(query2, XPATH, Arrays.asList("/test/test1")));
+        assertEventually(() -> assertQuery(query2, XPATH, List.of("/test/test1")));
     }
 
 
@@ -713,7 +716,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
 
         String query2 = "/jcr:root/test//*[propa='bar']";
 
-        assertEventually(() -> assertQuery(query2, XPATH, Arrays.asList("/test/test4")));
+        assertEventually(() -> assertQuery(query2, XPATH, List.of("/test/test4")));
     }
 
     @Test
@@ -730,12 +733,12 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
         // It should return both /test/test1 -> where content for propDate is of incorrect data type
         // and /test/test2 -> where content for propDate is of correct data type.
         String query = "/jcr:root/test//*[propa='bar']";
-        assertEventually(() -> assertQuery(query, XPATH, Arrays.asList("/test/test2", "/test/test1")));
+        assertEventually(() -> assertQuery(query, XPATH, List.of("/test/test2", "/test/test1")));
 
         // Check inequality query on propDate - this should not return /test/test1 -> since that node should not have been indexed for propDate
         // due to incorrect data type in the content for this property.
         String query2 = "/jcr:root/test//*[propDate!='2021-01-22T01:02:03.000Z']";
-        assertEventually(() -> assertQuery(query2, XPATH, Arrays.asList("/test/test3")));
+        assertEventually(() -> assertQuery(query2, XPATH, List.of("/test/test3")));
     }
 
     @Test
@@ -750,13 +753,13 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
 
         // Below queries will ensure propa is searchable with different data types as content and behaviour is similar for lucene and elastic.
         String query = "/jcr:root/test//*[propa='bar']";
-        assertEventually(() -> assertQuery(query, XPATH, Arrays.asList("/test/test1")));
+        assertEventually(() -> assertQuery(query, XPATH, List.of("/test/test1")));
 
         String query2 = "/jcr:root/test//*[propa=true]";
-        assertEventually(() -> assertQuery(query2, XPATH, Arrays.asList("/test/test4")));
+        assertEventually(() -> assertQuery(query2, XPATH, List.of("/test/test4")));
 
         String query3 = "/jcr:root/test//*[propa=10]";
-        assertEventually(() -> assertQuery(query3, XPATH, Arrays.asList("/test/test2", "/test/test3")));
+        assertEventually(() -> assertQuery(query3, XPATH, List.of("/test/test2", "/test/test3")));
     }
 
     @Test
@@ -769,11 +772,11 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
 
         // Test query returns correct node on querying on dateProp
         String query = "/jcr:root/test//*[propDate='2021-01-22T01:02:03.000Z']";
-        assertEventually(() -> assertQuery(query, XPATH, Arrays.asList("/test/test1")));
+        assertEventually(() -> assertQuery(query, XPATH, List.of("/test/test1")));
 
         // Test query returns correct node on querying on String type property
         String query2 = "/jcr:root/test//*[propa='foo']";
-        assertEventually(() -> assertQuery(query2, XPATH, Arrays.asList("/test/test1", "/test/test2")));
+        assertEventually(() -> assertQuery(query2, XPATH, List.of("/test/test1", "/test/test2")));
     }
 
     @Test
@@ -789,7 +792,7 @@ public abstract class IndexQueryCommonTest extends AbstractQueryTest {
 
         // Test query returns correct node on querying on dateProp
         String query = "/jcr:root/test//*[propa='foo'] order by @propDate descending";
-        assertEventually(() -> assertQuery(query, XPATH, Arrays.asList("/test/test1", "/test/test3", "/test/test2"), true, true));
+        assertEventually(() -> assertQuery(query, XPATH, List.of("/test/test1", "/test/test3", "/test/test2"), true, true));
     }
 
     private static Tree child(Tree t, String n, String type) {