Author: catholicon
Date: Fri Jul 19 18:26:56 2019
New Revision: 1863411

URL: http://svn.apache.org/viewvc?rev=1863411&view=rev
Log:
OAK-7981: Implement elastic search support based off of oak-search

Basic index and query is be working.
Little bit of tests shows things (settings, mapping, a couple of docs)
do perist fine on ES instance.
Also, at least simple queries should be working (as is asserted in a
test as well).

TODO (in no specific order):
* currently all string (apart from path, ancestor, etc) get mapped as
string - that means all would get analyzed and need to be searched with
'keyword' sub-field from keyword/equality pov. Maybe mapping (and hence
querying would need improving)
* batch indexing
* batch/scroll searching
* implement faceting, suggestion, spellcheck, more-like-this, excerpt
(anything else??)
* cost estimation
* whether lucene and es client bundles need to be inlined

Added:
    jackrabbit/oak/trunk/oak-search-elastic/
    jackrabbit/oak/trunk/oak-search-elastic/pom.xml   (with props)
    jackrabbit/oak/trunk/oak-search-elastic/src/
    jackrabbit/oak/trunk/oak-search-elastic/src/main/
    jackrabbit/oak/trunk/oak-search-elastic/src/main/java/
    jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/
    jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/
    jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/DefaultElasticsearchIndexCoordinateFactory.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchConnectionFactory.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinate.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinateImpl.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexConstants.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinate.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateFactory.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateImpl.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexDefinition.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexProviderService.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocument.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocumentMaker.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditor.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorContext.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorProvider.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexWriter.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexWriterFactory.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/ElasticsearchIndex.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/ElasticsearchIndexNode.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/ElasticsearchIndexProvider.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/ElasticsearchIndexStatistics.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/ElasticsearchResultRowIterator.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/query/ElasticsearchSearcher.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/util/
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/util/ElasticsearchIndexDefinitionBuilder.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/util/TermQueryBuilderFactory.java
   (with props)
    jackrabbit/oak/trunk/oak-search-elastic/src/test/
    jackrabbit/oak/trunk/oak-search-elastic/src/test/java/
    jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/
    jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/
    jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchDockerRule.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchManagementRule.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchPropertyIndexTest.java
   (with props)
    
jackrabbit/oak/trunk/oak-search-elastic/src/test/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchTestUtils.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorContext.java
    
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexEditorContext.java
    
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionBuilder.java
    jackrabbit/oak/trunk/pom.xml

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorContext.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorContext.java?rev=1863411&r1=1863410&r2=1863411&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorContext.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorContext.java
 Fri Jul 19 18:26:56 2019
@@ -64,7 +64,7 @@ public class LuceneIndexEditorContext ex
     }
 
     @Override
-    public LuceneIndexWriter getWriter() throws IOException {
+    public LuceneIndexWriter getWriter() {
         return (LuceneIndexWriter)super.getWriter();
     }
 

Added: jackrabbit/oak/trunk/oak-search-elastic/pom.xml
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/pom.xml?rev=1863411&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search-elastic/pom.xml (added)
+++ jackrabbit/oak/trunk/oak-search-elastic/pom.xml Fri Jul 19 18:26:56 2019
@@ -0,0 +1,315 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd ">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.jackrabbit</groupId>
+    <artifactId>oak-parent</artifactId>
+    <version>1.16-SNAPSHOT</version>
+    <relativePath>../oak-parent/pom.xml</relativePath>
+  </parent>
+
+  <artifactId>oak-search-elastic</artifactId>
+  <name>Oak Elasticsearch</name>
+  <packaging>bundle</packaging>
+  <description>Oak Lucene integration subproject</description>
+
+  <properties>
+    <elasticsearch.version>7.1.1</elasticsearch.version>
+    <lucene.version>8.0.0</lucene.version>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <!-- TODO: of late not embedding this seems to working for 
locally, BUT it had failed initially. Need to verify-->
+            <!-- We need to embed lucene as it's required by various 
QueryBuilders-->
+            <Embed-Dependency>
+              lucene-core;inline=true
+              elasticsearch-rest-high-level-client;inline=true
+            </Embed-Dependency>
+          </instructions>
+        </configuration>
+        <executions>
+          <execution>
+            <id>baseline</id>
+            <goals>
+              <goal>baseline</goal>
+            </goals>
+            <phase>pre-integration-test</phase>
+            <configuration>
+              <!--
+                TODO: This is required because there's no prior (stable) 
version of oak-search.
+                This should be removed once this module is released
+              -->
+              <skip>true</skip>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/test.rtf</exclude>
+            <exclude>**/test.txt</exclude>
+            <exclude>**/fvs.csv</exclude>
+          </excludes>
+        </configuration>
+       </plugin>
+     </plugins>
+  </build>
+
+  <dependencies>
+    <!-- Optional OSGi dependencies, used only when running within OSGi -->
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.annotation</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.scr.annotations</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-core-spi</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-store-spi</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-query-spi</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-store-document</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-search</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <!-- Logging -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+
+    <!-- Nullability annotations -->
+    <dependency>
+      <groupId>org.jetbrains</groupId>
+      <artifactId>annotations</artifactId>
+    </dependency>
+
+    <!-- Test Dependencies -->
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.elasticsearch.client</groupId>
+      <artifactId>elasticsearch-rest-high-level-client</artifactId>
+      <version>${elasticsearch.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.lucene</groupId>
+      <artifactId>lucene-core</artifactId>
+      <version>${lucene.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-core</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-blob-plugins</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-store-spi</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-segment-tar</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-segment-tar</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-store-document</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-jcr</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-jcr</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-commons</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-jcr-tests</artifactId>
+      <version>${jackrabbit.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-core</artifactId>
+      <version>${jackrabbit.version}</version>
+      <classifier>tests</classifier>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tika</groupId>
+      <artifactId>tika-parsers</artifactId>
+      <version>${tika.version}</version>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>commons-logging</groupId>
+          <artifactId>commons-logging</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-log4j12</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sling</groupId>
+      <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.hamcrest</groupId>
+      <artifactId>hamcrest-all</artifactId>
+      <version>1.3</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>io.dropwizard.metrics</groupId>
+      <artifactId>metrics-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-exec</artifactId>
+      <version>1.3</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+      <version>2.8.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.arakelian</groupId>
+      <artifactId>docker-junit-rule</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-search</artifactId>
+      <classifier>tests</classifier>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+
+  </dependencies>
+</project>

Propchange: jackrabbit/oak/trunk/oak-search-elastic/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/DefaultElasticsearchIndexCoordinateFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/DefaultElasticsearchIndexCoordinateFactory.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/DefaultElasticsearchIndexCoordinateFactory.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/DefaultElasticsearchIndexCoordinateFactory.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch;
+
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import java.util.Map;
+
+public class DefaultElasticsearchIndexCoordinateFactory implements 
ElasticsearchIndexCoordinateFactory {
+    private final Map<String, String> config;
+    private final ElasticsearchConnectionFactory factory;
+
+    DefaultElasticsearchIndexCoordinateFactory(ElasticsearchConnectionFactory 
factory, Map<String, String> config) {
+        this.factory = factory;
+        this.config = config;
+    }
+
+    @Override
+    public ElasticsearchIndexCoordinate 
getElasticsearchIndexCoordinate(IndexDefinition indexDefinition) {
+        ElasticsearchCoordinate esCoord = 
getElasticsearchCoordinate(indexDefinition.getDefinitionNodeState());
+        return new ElasticsearchIndexCoordinateImpl(esCoord, indexDefinition);
+    }
+
+    private ElasticsearchCoordinate getElasticsearchCoordinate(NodeState 
indexDefinition) {
+        return ElasticsearchCoordinateImpl.construct(factory, indexDefinition, 
config);
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/DefaultElasticsearchIndexCoordinateFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchConnectionFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchConnectionFactory.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchConnectionFactory.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchConnectionFactory.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch;
+
+import com.google.common.collect.Maps;
+import org.apache.http.HttpHost;
+import org.elasticsearch.client.RestClient;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+public class ElasticsearchConnectionFactory implements Closeable {
+    private static final Logger LOG = 
LoggerFactory.getLogger(ElasticsearchConnectionFactory.class);
+    private ConcurrentMap<ElasticsearchCoordinate, RestHighLevelClient> 
clientMap = Maps.newConcurrentMap();
+
+    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+    private AtomicBoolean isClosed = new AtomicBoolean();
+
+    public RestHighLevelClient getConnection(ElasticsearchCoordinate esCoord) {
+        lock.readLock().lock();
+        try {
+            if (isClosed.get()) {
+                throw new IllegalStateException("Already closed");
+            }
+
+            return clientMap.computeIfAbsent(esCoord, elasticsearchCoordinate 
-> {
+                LOG.info("Creating client {}", elasticsearchCoordinate);
+                return new RestHighLevelClient(
+                    RestClient.builder(
+                            new HttpHost(elasticsearchCoordinate.getHost(),
+                                    elasticsearchCoordinate.getPort(),
+                                    elasticsearchCoordinate.getScheme())
+                    ));
+            });
+        } finally {
+            lock.readLock().unlock();
+        }
+    }
+
+    @Override
+    public void close() {
+        lock.writeLock().lock();
+        try {
+            isClosed.set(true);
+            clientMap.values().forEach(restHighLevelClient -> {
+                try {
+                    restHighLevelClient.close();
+                } catch (IOException e) {
+                    LOG.error("Error occurred while closing a connection", e);
+                }
+            });
+        } finally {
+            lock.writeLock().unlock();
+        }
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchConnectionFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinate.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinate.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinate.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinate.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch;
+
+import org.elasticsearch.client.RestHighLevelClient;
+
+public interface ElasticsearchCoordinate {
+    String SCHEME_PROP = "elasticsearch.scheme";
+    String DEFAULT_SCHEME = "http";
+    String HOST_PROP = "elasticsearch.host";
+    String DEFAULT_HOST = "127.0.0.1";
+    String PORT_PROP = "elasticsearch.port";
+    int DEFAULT_PORT = 9200;
+
+    RestHighLevelClient getClient();
+    String getScheme();
+    String getHost();
+    int getPort();
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinate.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinateImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinateImpl.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinateImpl.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinateImpl.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch;
+
+import com.google.common.base.Objects;
+import org.apache.jackrabbit.oak.plugins.index.search.util.ConfigUtil;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.elasticsearch.client.RestHighLevelClient;
+
+import java.util.Map;
+
+public class ElasticsearchCoordinateImpl implements ElasticsearchCoordinate {
+    private final ElasticsearchConnectionFactory connectionFactory;
+    private final String scheme;
+    private final String host;
+    private final int port;
+
+    ElasticsearchCoordinateImpl(ElasticsearchConnectionFactory 
connectionFactory,
+                                String scheme, String host, int port) {
+        this.connectionFactory = connectionFactory;
+        this.scheme = scheme;
+        this.host = host;
+        this.port = port;
+    }
+
+    static ElasticsearchCoordinate construct(ElasticsearchConnectionFactory 
connectionFactory,
+                                             NodeState indexDefn, Map<String, 
String> configMap) {
+        ElasticsearchCoordinate esCoord;
+
+        // index defn is at highest prio
+        esCoord = readFrom(connectionFactory, indexDefn);
+        if (esCoord != null) {
+            return esCoord;
+        }
+
+        // command line comes next
+        esCoord = construct(connectionFactory,
+                System.getProperty(SCHEME_PROP), 
System.getProperty(HOST_PROP), Integer.getInteger(PORT_PROP));
+        if (esCoord != null) {
+            return esCoord;
+        }
+
+        // config map
+        if (configMap != null) {
+            Integer port = null;
+            try {
+                port = Integer.parseInt(configMap.get(PORT_PROP));
+            } catch (NumberFormatException nfe) {
+                // ignore
+            }
+            esCoord = construct(connectionFactory, configMap.get(SCHEME_PROP), 
configMap.get(HOST_PROP), port);
+            if (esCoord != null) {
+                return esCoord;
+            }
+        }
+
+        return new ElasticsearchCoordinateImpl(connectionFactory, 
DEFAULT_SCHEME, DEFAULT_HOST, DEFAULT_PORT);
+    }
+
+    @Override
+    public RestHighLevelClient getClient() {
+        return connectionFactory.getConnection(this);
+    }
+
+    @Override
+    public String getScheme() {
+        return scheme;
+    }
+
+    @Override
+    public String getHost() {
+        return host;
+    }
+
+    @Override
+    public int getPort() {
+        return port;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof ElasticsearchCoordinate)) {
+            return false;
+        }
+
+        ElasticsearchCoordinate other = (ElasticsearchCoordinate)o;
+        return hashCode() == other.hashCode() // just to have a quicker 
comparison
+                && getScheme().equals(other.getScheme())
+                && getHost().equals(other.getHost())
+                && getPort() == other.getPort();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(getScheme(), getHost(), getPort());
+    }
+
+    @Override
+    public String toString() {
+        return getScheme() + "://" + getHost() + ":" + getPort();
+    }
+
+    private static ElasticsearchCoordinate 
readFrom(ElasticsearchConnectionFactory factory, NodeState definition) {
+        if (definition == null
+                || !definition.hasProperty(SCHEME_PROP)
+                || !definition.hasProperty(HOST_PROP)
+                || !definition.hasProperty(PORT_PROP)) {
+            return null;
+        }
+
+        String scheme = ConfigUtil.getOptionalValue(definition, SCHEME_PROP, 
DEFAULT_SCHEME);
+        String host = ConfigUtil.getOptionalValue(definition, HOST_PROP, 
DEFAULT_HOST);
+        int port = ConfigUtil.getOptionalValue(definition, PORT_PROP, 
DEFAULT_PORT);
+
+        return new ElasticsearchCoordinateImpl(factory, scheme, host, port);
+    }
+
+    private static ElasticsearchCoordinate 
construct(ElasticsearchConnectionFactory factory,
+                                                     String scheme, String 
host, Integer port) {
+        if (scheme == null || host == null || port == null) {
+            return null;
+        }
+
+        return new ElasticsearchCoordinateImpl(factory, scheme, host, port);
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchCoordinateImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexConstants.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexConstants.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexConstants.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexConstants.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch;
+
+public class ElasticsearchIndexConstants {
+    public static final String TYPE_ELASTICSEARCH = "elasticsearch";
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinate.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinate.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinate.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinate.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch;
+
+import org.elasticsearch.client.RestHighLevelClient;
+
+public interface ElasticsearchIndexCoordinate {
+    RestHighLevelClient getClient();
+    String getEsIndexName();
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinate.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateFactory.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateFactory.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateFactory.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch;
+
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+
+public interface ElasticsearchIndexCoordinateFactory {
+    ElasticsearchIndexCoordinate 
getElasticsearchIndexCoordinate(IndexDefinition indexDefinition);
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateImpl.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateImpl.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateImpl.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static org.elasticsearch.common.Strings.INVALID_FILENAME_CHARS;
+
+public class ElasticsearchIndexCoordinateImpl implements 
ElasticsearchIndexCoordinate {
+
+    private static final int MAX_NAME_LENGTH = 255;
+
+    private final ElasticsearchCoordinate esCoord;
+    private final String esIndexName;
+
+    ElasticsearchIndexCoordinateImpl(@NotNull ElasticsearchCoordinate esCoord, 
IndexDefinition indexDefinition) {
+        this.esCoord = esCoord;
+        esIndexName = getRemoteIndexName(indexDefinition, 
indexDefinition.getIndexPath());
+    }
+
+    @Override
+    public RestHighLevelClient getClient() {
+        return esCoord.getClient();
+    }
+
+    @Override
+    public String getEsIndexName() {
+        return esIndexName;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(esCoord, esIndexName);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (! (o instanceof ElasticsearchIndexCoordinateImpl)) {
+            return false;
+        }
+        ElasticsearchIndexCoordinateImpl other = 
(ElasticsearchIndexCoordinateImpl)o;
+        return hashCode() == other.hashCode()
+                && esCoord.equals(other.esCoord)
+                && esIndexName.equals(other.esIndexName);
+    }
+
+    private String getRemoteIndexName(IndexDefinition definition, String 
indexPath) {
+        String suffix = definition.getUniqueId();
+
+        if (suffix == null) {
+            suffix = String.valueOf(definition.getReindexCount());
+        }
+
+        return getESSafeIndexName(indexPath + "-" + suffix);
+    }
+
+    /**
+     * <ul>
+     *     <li>abc -> abc</li>
+     *     <li>xy:abc -> xyabc</li>
+     *     <li>/oak:index/abc -> abc</li>
+     * </ul>
+     *
+     * The resulting file name would be truncated to MAX_NAME_LENGTH
+     */
+    private static String getESSafeIndexName(String indexPath) {
+        List<String> elements = 
Lists.newArrayList(PathUtils.elements(indexPath));
+        Collections.reverse(elements);
+        List<String> result = Lists.newArrayListWithCapacity(2);
+
+        //Max 3 nodeNames including oak:index which is the immediate parent 
for any indexPath
+        for (String e : Iterables.limit(elements, 3)) {
+            if ("oak:index".equals(e)) {
+                continue;
+            }
+
+            result.add(getESSafeName(e));
+        }
+
+        Collections.reverse(result);
+        String name = Joiner.on('_').join(result);
+        if (name.length() > MAX_NAME_LENGTH){
+            name = name.substring(0, MAX_NAME_LENGTH);
+        }
+        return name;
+    }
+
+    /**
+     * Convert {@code e} to Elasticsearch safe index name.
+     * Ref: 
https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html
+     */
+    private static String getESSafeName(String suggestedIndexName) {
+        String invalidCharsRegex = Pattern.quote(String.join("", 
INVALID_FILENAME_CHARS
+                .stream()
+                .map(Object::toString)
+                .collect(Collectors.toList())));
+        return suggestedIndexName.replaceAll(invalidCharsRegex, 
"").toLowerCase();
+    }
+
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexCoordinateImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexDefinition.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexDefinition.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexDefinition.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexDefinition.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch;
+
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+public class ElasticsearchIndexDefinition extends IndexDefinition {
+    public ElasticsearchIndexDefinition(NodeState root, NodeState defn, String 
indexPath) {
+        super(root, getIndexDefinitionState(defn), 
determineIndexFormatVersion(defn), determineUniqueId(defn), indexPath);
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexDefinition.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexProviderService.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexProviderService.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexProviderService.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexProviderService.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.felix.scr.annotations.*;
+import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean;
+import org.apache.jackrabbit.oak.cache.CacheStats;
+import org.apache.jackrabbit.oak.commons.IOUtils;
+import org.apache.jackrabbit.oak.commons.PropertiesUtil;
+import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard;
+import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
+import 
org.apache.jackrabbit.oak.plugins.index.elasticsearch.index.ElasticsearchIndexEditorProvider;
+import 
org.apache.jackrabbit.oak.plugins.index.elasticsearch.query.ElasticsearchIndexProvider;
+import 
org.apache.jackrabbit.oak.plugins.index.fulltext.PreExtractedTextProvider;
+import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.plugins.index.search.TextExtractionStatsMBean;
+import org.apache.jackrabbit.oak.spi.whiteboard.Registration;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.commons.io.FileUtils.ONE_MB;
+import static 
org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean;
+
+@Component(metatype = true, label = "Apache Jackrabbit Oak 
ElasticsearchIndexProvider")
+public class ElasticsearchIndexProviderService {
+
+    private static Logger LOG = 
LoggerFactory.getLogger(ElasticsearchIndexProviderService.class);
+
+    private static final int PROP_EXTRACTED_TEXT_CACHE_SIZE_DEFAULT = 20;
+    @Property(
+            intValue = PROP_EXTRACTED_TEXT_CACHE_SIZE_DEFAULT,
+            label = "Extracted text cache size (MB)",
+            description = "Cache size in MB for caching extracted text for 
some time. When set to 0 then " +
+                    "cache would be disabled"
+    )
+    private static final String PROP_EXTRACTED_TEXT_CACHE_SIZE = 
"extractedTextCacheSizeInMB";
+
+    private static final int PROP_EXTRACTED_TEXT_CACHE_EXPIRY_DEFAULT = 300;
+    @Property(
+            intValue = PROP_EXTRACTED_TEXT_CACHE_EXPIRY_DEFAULT,
+            label = "Extracted text cache expiry (secs)",
+            description = "Time in seconds for which the extracted text would 
be cached in memory"
+    )
+    private static final String PROP_EXTRACTED_TEXT_CACHE_EXPIRY = 
"extractedTextCacheExpiryInSecs";
+
+    private static final boolean PROP_PRE_EXTRACTED_TEXT_ALWAYS_USE_DEFAULT = 
false;
+    @Property(
+            boolValue = PROP_PRE_EXTRACTED_TEXT_ALWAYS_USE_DEFAULT,
+            label = "Always use pre-extracted text cache",
+            description = "By default pre extracted text cache would only be 
used for reindex case. If this setting " +
+                    "is enabled then it would also be used in normal 
incremental indexing"
+    )
+    private static final String PROP_PRE_EXTRACTED_TEXT_ALWAYS_USE = 
"alwaysUsePreExtractedCache";
+
+    private static final String PROP_ELASTICSEARCH_SCHEME_DEFAULT = "http";
+//    @Property(
+//            value = PROP_ELASTICSEARCH_SCHEME_DEFAULT,
+//            label = "Elasticsearch connection scheme"
+//    )
+    private static final String PROP_ELASTICSEARCH_SCHEME = 
"elasticsearch.scheme";
+
+    private static final String PROP_ELASTICSEARCH_HOST_DEFAULT = "localhost";
+//    @Property(
+//            value = PROP_ELASTICSEARCH_HOST_DEFAULT,
+//            label = "Elasticsearch connection host"
+//    )
+    private static final String PROP_ELASTICSEARCH_HOST = "elasticsearch.host";
+
+    private static final int PROP_ELASTICSEARCH_PORT_DEFAULT = 9200;
+//    @Property(
+//            intValue = PROP_ELASTICSEARCH_PORT_DEFAULT,
+//            label = "Elasticsearch connection port"
+//    )
+    private static final String PROP_ELASTICSEARCH_PORT = "elasticsearch.port";
+
+    @Reference
+    private StatisticsProvider statisticsProvider;
+
+    @Reference(policy = ReferencePolicy.DYNAMIC,
+            cardinality = ReferenceCardinality.OPTIONAL_UNARY,
+            policyOption = ReferencePolicyOption.GREEDY
+    )
+    private volatile PreExtractedTextProvider extractedTextProvider;
+
+    private ExtractedTextCache extractedTextCache;
+
+    private ElasticsearchConnectionFactory connectionFactory = null;
+
+    private final List<ServiceRegistration> regs = Lists.newArrayList();
+    private final List<Registration> oakRegs = Lists.newArrayList();
+
+    private Whiteboard whiteboard;
+
+    @Activate
+    private void activate(BundleContext bundleContext, Map<String, ?> config) {
+        whiteboard = new OsgiWhiteboard(bundleContext);
+
+        initializeExtractedTextCache(config, statisticsProvider);
+
+        connectionFactory = new ElasticsearchConnectionFactory();
+        ElasticsearchIndexCoordinateFactory esIndexCoordFactory = 
getElasticsearchIndexCoordinateFactory(config);
+
+        registerIndexProvider(bundleContext, esIndexCoordFactory);
+        registerIndexEditor(bundleContext, esIndexCoordFactory);
+    }
+
+    @Deactivate
+    private void deactivate() {
+        for (ServiceRegistration reg : regs) {
+            reg.unregister();
+        }
+
+        for (Registration reg : oakRegs) {
+            reg.unregister();
+        }
+
+        IOUtils.closeQuietly(connectionFactory);
+        connectionFactory = null;
+
+        if (extractedTextCache != null) {
+            extractedTextCache.close();
+        }
+    }
+
+    private void registerIndexProvider(BundleContext bundleContext, 
ElasticsearchIndexCoordinateFactory esIndexCoordFactory) {
+        ElasticsearchIndexProvider indexProvider = new 
ElasticsearchIndexProvider(esIndexCoordFactory);
+
+        Dictionary<String, Object> props = new Hashtable<>();
+        props.put("type", ElasticsearchIndexConstants.TYPE_ELASTICSEARCH);
+        
regs.add(bundleContext.registerService(IndexEditorProvider.class.getName(), 
indexProvider, props));
+    }
+
+    private void registerIndexEditor(BundleContext bundleContext, 
ElasticsearchIndexCoordinateFactory esIndexCoordFactory) {
+        ElasticsearchIndexEditorProvider editorProvider = new 
ElasticsearchIndexEditorProvider(esIndexCoordFactory, extractedTextCache);
+
+        Dictionary<String, Object> props = new Hashtable<>();
+        props.put("type", ElasticsearchIndexConstants.TYPE_ELASTICSEARCH);
+        
regs.add(bundleContext.registerService(IndexEditorProvider.class.getName(), 
editorProvider, props));
+        oakRegs.add(registerMBean(whiteboard,
+                TextExtractionStatsMBean.class,
+                editorProvider.getExtractedTextCache().getStatsMBean(),
+                TextExtractionStatsMBean.TYPE,
+                "TextExtraction statistics"));
+    }
+
+    private void initializeExtractedTextCache(Map<String, ?> config, 
StatisticsProvider statisticsProvider) {
+        int cacheSizeInMB = 
PropertiesUtil.toInteger(config.get(PROP_EXTRACTED_TEXT_CACHE_SIZE),
+                PROP_EXTRACTED_TEXT_CACHE_SIZE_DEFAULT);
+        int cacheExpiryInSecs = 
PropertiesUtil.toInteger(config.get(PROP_EXTRACTED_TEXT_CACHE_EXPIRY),
+                PROP_EXTRACTED_TEXT_CACHE_EXPIRY_DEFAULT);
+        boolean alwaysUsePreExtractedCache = 
PropertiesUtil.toBoolean(config.get(PROP_PRE_EXTRACTED_TEXT_ALWAYS_USE),
+                PROP_PRE_EXTRACTED_TEXT_ALWAYS_USE_DEFAULT);
+
+        extractedTextCache = new ExtractedTextCache(
+                cacheSizeInMB * ONE_MB,
+                cacheExpiryInSecs,
+                alwaysUsePreExtractedCache,
+                null /* TODO: have a temp dir to enable tracking timed out 
binary extraction */,
+                statisticsProvider);
+        if (extractedTextProvider != null){
+            registerExtractedTextProvider(extractedTextProvider);
+        }
+        CacheStats stats = extractedTextCache.getCacheStats();
+        if (stats != null){
+            oakRegs.add(registerMBean(whiteboard,
+                    CacheStatsMBean.class, stats,
+                    CacheStatsMBean.TYPE, stats.getName()));
+            LOG.info("Extracted text caching enabled with maxSize {} MB, 
expiry time {} secs",
+                    cacheSizeInMB, cacheExpiryInSecs);
+        }
+    }
+
+    private void registerExtractedTextProvider(PreExtractedTextProvider 
provider){
+        if (extractedTextCache != null){
+            if (provider != null){
+                String usage = 
extractedTextCache.isAlwaysUsePreExtractedCache() ?
+                        "always" : "only during reindexing phase";
+                LOG.info("Registering PreExtractedTextProvider {} with 
extracted text cache. " +
+                        "It would be used {}",  provider, usage);
+            } else {
+                LOG.info("Unregistering PreExtractedTextProvider with 
extracted text cache");
+            }
+            extractedTextCache.setExtractedTextProvider(provider);
+        }
+    }
+
+    private ElasticsearchIndexCoordinateFactory 
getElasticsearchIndexCoordinateFactory(Map<String, ?> config) {
+        ElasticsearchIndexCoordinateFactory esIndexCoordFactory;
+        Map<String, String> esCfg = Maps.newHashMap();
+        esCfg.put(ElasticsearchCoordinate.SCHEME_PROP,
+                PropertiesUtil.toString(config.get(PROP_ELASTICSEARCH_SCHEME), 
PROP_ELASTICSEARCH_SCHEME_DEFAULT));
+        esCfg.put(ElasticsearchCoordinate.HOST_PROP,
+                PropertiesUtil.toString(config.get(PROP_ELASTICSEARCH_HOST), 
PROP_ELASTICSEARCH_HOST_DEFAULT));
+        esCfg.put(ElasticsearchCoordinate.PORT_PROP, String.valueOf(
+                PropertiesUtil.toInteger(config.get(PROP_ELASTICSEARCH_PORT), 
PROP_ELASTICSEARCH_PORT_DEFAULT)));
+        esIndexCoordFactory = new 
DefaultElasticsearchIndexCoordinateFactory(connectionFactory, esCfg);
+        return esIndexCoordFactory;
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/ElasticsearchIndexProviderService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocument.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocument.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocument.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocument.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch.index;
+
+import com.google.common.collect.Maps;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.search.FieldNames;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class ElasticsearchDocument {
+    private static Logger LOG = 
LoggerFactory.getLogger(ElasticsearchDocument.class);
+
+    // id should only be useful for logging (at least as of now)
+    private final String path;
+
+    private final String id;
+    private final List<String> fulltext;
+    private final List<String> suggest;
+    private final List<String> notNullProps;
+    private final List<String> nullProps;
+    private final Map<String, Object> properties;
+
+    ElasticsearchDocument(String path) {
+        this.path = path;
+        String id = null;
+        try {
+            id = pathToId(path);
+        } catch (UnsupportedEncodingException e) {
+            LOG.warn("Couldn't encode {} as ES id", path);
+        }
+        this.id = id;
+        this.fulltext = newArrayList();
+        this.suggest = newArrayList();
+        this.notNullProps = newArrayList();
+        this.nullProps = newArrayList();
+        this.properties = Maps.newHashMap();
+    }
+
+    void addFulltext(String value) {
+        fulltext.add(value);
+    }
+
+    void addFulltextRelative(String path, String value) {
+        addProperty(FieldNames.createFulltextFieldName(path), value);
+    }
+
+    void addSuggest(String value) {
+        suggest.add(value);
+    }
+
+    void notNullProp(String propName) {
+        notNullProps.add(propName);
+    }
+
+    void nullProp(String propName) {
+        nullProps.add(propName);
+    }
+
+    // ES for String values (that are not interpreted as date or numbers etc) 
would analyze in the same
+    // field and would index a sub-field "keyword" for non-analyzed value.
+    // ref: https://www.elastic.co/blog/strings-are-dead-long-live-strings
+    // (interpretation of date etc: 
https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic-field-mapping.html)
+    void addProperty(String fieldName, Object value) {
+        properties.put(fieldName, value);
+    }
+
+    void indexAncestors(String path) {
+        String parPath = PathUtils.getParentPath(path);
+        int depth = PathUtils.getDepth(path);
+
+        // TODO: remember that mapping must be configured with
+        // 
https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-pathhierarchy-tokenizer.html
+        addProperty(FieldNames.ANCESTORS, parPath);
+        addProperty(FieldNames.PATH_DEPTH, depth);
+    }
+
+    String getId() {
+        return id;
+    }
+
+    public String build() {
+        String ret = null;
+        try {
+            XContentBuilder builder = XContentFactory.jsonBuilder();
+            builder.startObject();
+            if (fulltext.size() > 0) {
+                builder.field(FieldNames.FULLTEXT, fulltext);
+            }
+            if (suggest.size() > 0) {
+                builder.startObject(FieldNames.SUGGEST).field("input", 
suggest).endObject();
+            }
+            if (notNullProps.size() > 0) {
+                builder.field(FieldNames.NOT_NULL_PROPS, notNullProps);
+            }
+            if (nullProps.size() > 0) {
+                builder.field(FieldNames.NULL_PROPS, nullProps);
+            }
+            for (Map.Entry<String, Object> prop : properties.entrySet()) {
+                builder.field(prop.getKey(), prop.getValue());
+            }
+            builder.endObject();
+
+            ret = Strings.toString(builder);
+        } catch (IOException e) {
+            LOG.error("Error serializing document - id: {}, properties: {}, 
fulltext: {}, suggest: {}, " +
+                            "notNullProps: {}, nullProps: {}",
+                    path, properties, fulltext, suggest, notNullProps, 
nullProps,
+                    e);
+        }
+
+        return ret;
+    }
+
+    @Override
+    public String toString() {
+        return build();
+    }
+
+    public static String pathToId(String path) throws 
UnsupportedEncodingException {
+        return URLEncoder.encode(path, "UTF-8");
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocument.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocumentMaker.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocumentMaker.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocumentMaker.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocumentMaker.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch.index;
+
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.index.search.Aggregate;
+import org.apache.jackrabbit.oak.plugins.index.search.FieldNames;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.apache.jackrabbit.oak.plugins.index.search.PropertyDefinition;
+import 
org.apache.jackrabbit.oak.plugins.index.search.spi.binary.FulltextBinaryTextExtractor;
+import 
org.apache.jackrabbit.oak.plugins.index.search.spi.editor.FulltextDocumentMaker;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.util.List;
+
+public class ElasticsearchDocumentMaker extends 
FulltextDocumentMaker<ElasticsearchDocument> {
+
+    ElasticsearchDocumentMaker(@Nullable FulltextBinaryTextExtractor 
textExtractor,
+                               @NotNull IndexDefinition definition,
+                               IndexDefinition.IndexingRule indexingRule, 
@NotNull String path) {
+        super(textExtractor, definition, indexingRule, path);
+    }
+
+    @Override
+    protected ElasticsearchDocument initDoc() {
+        return new ElasticsearchDocument(path);
+    }
+
+    @Override
+    protected ElasticsearchDocument finalizeDoc(ElasticsearchDocument doc, 
boolean dirty, boolean facet) throws IOException {
+        if (doc.getId() == null) {
+            throw new IOException("Couldn't generate id for doc - (More 
details during initDoc)" + doc);
+        }
+        return doc;
+    }
+
+    // TODO: needed only for oak-lucene. Should be removed from oak-search
+    @Override
+    protected boolean isFacetingEnabled() {
+        return false;
+    }
+
+    @Override
+    protected boolean indexTypeOrderedFields(ElasticsearchDocument doc, String 
pname, int tag, PropertyState property, PropertyDefinition pd) {
+        // TODO: check the conjecture below
+        // ES doesn't seem to require special mapping to sort so we don't need 
to add anything
+        return false;
+    }
+
+    @Override
+    protected boolean addBinary(ElasticsearchDocument doc, String path, 
List<String> binaryValues) {
+        boolean added = false;
+        for (String binaryValue : binaryValues) {
+            if (path != null) {
+                doc.addFulltextRelative(path, binaryValue);
+            } else {
+                doc.addFulltext(binaryValue);
+            }
+
+            added = true;
+        }
+
+        return added;
+    }
+
+    @Override
+    protected boolean indexFacetProperty(ElasticsearchDocument doc, int tag, 
PropertyState property, String pname) {
+        // faceting on ES works automatically for keyword (propertyIndex) and 
subsequently query params.
+        // We we don't need to add anything.
+        // 
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html
+        return false;
+    }
+
+    @Override
+    protected void indexAnalyzedProperty(ElasticsearchDocument doc, String 
pname, String value, PropertyDefinition pd) {
+        doc.addProperty(FieldNames.createAnalyzedFieldName(pname), value);
+    }
+
+    @Override
+    protected void indexSuggestValue(ElasticsearchDocument doc, String value) {
+        doc.addSuggest(value);
+    }
+
+    @Override
+    protected void indexSpellcheckValue(ElasticsearchDocument doc, String 
value) {
+        // TODO: Figure out how to do spellcheck with ES (interwebs seems to 
say that it should be simple
+        // and don't need anything extra in indexed document
+    }
+
+    @Override
+    protected void indexFulltextValue(ElasticsearchDocument doc, String value) 
{
+        // Note: diversion from lucene impl - here we are storing even these 
cases and not just binary
+        doc.addFulltext(value);
+    }
+
+    @Override
+    protected boolean indexTypedProperty(ElasticsearchDocument doc, 
PropertyState property, String pname, PropertyDefinition pd) {
+        int tag = property.getType().tag();
+        boolean fieldAdded = false;
+        for (int i = 0; i < property.count(); i++) {
+            Object f;
+            if (tag == Type.LONG.tag()) {
+                f = property.getValue(Type.LONG, i);
+            } else if (tag == Type.DATE.tag()) {
+                f = property.getValue(Type.DATE, i);
+            } else if (tag == Type.DOUBLE.tag()) {
+                f = property.getValue(Type.DOUBLE, i);
+            } else if (tag == Type.BOOLEAN.tag()) {
+                f = property.getValue(Type.BOOLEAN, i).toString();
+            } else {
+                f = property.getValue(Type.STRING, i);
+            }
+
+            if (includePropertyValue(property, i, pd)){
+                doc.addProperty(pname, f);
+                fieldAdded = true;
+            }
+        }
+        return fieldAdded;
+    }
+
+    @Override
+    protected void indexAncestors(ElasticsearchDocument doc, String path) {
+        doc.indexAncestors(path);
+    }
+
+    @Override
+    protected void indexNotNullProperty(ElasticsearchDocument doc, 
PropertyDefinition pd) {
+        doc.notNullProp(pd.name);
+    }
+
+    @Override
+    protected void indexNullProperty(ElasticsearchDocument doc, 
PropertyDefinition pd) {
+        doc.nullProp(pd.name);
+    }
+
+    @Override
+    protected void indexAggregateValue(ElasticsearchDocument doc, 
Aggregate.NodeIncludeResult result, String value, PropertyDefinition pd) {
+        if (result.isRelativeNode()) {
+            doc.addFulltextRelative(result.rootIncludePath, value);
+        } else {
+            doc.addFulltext(value);
+        }
+    }
+
+    @Override
+    protected void indexNodeName(ElasticsearchDocument doc, String value) {
+        doc.addProperty(FieldNames.NODE_NAME, value);
+    }
+
+    @Override
+    protected boolean indexSimilarityTag(ElasticsearchDocument doc, 
PropertyState property) {
+        // TODO : not implemented
+        return false;
+    }
+
+    @Override
+    protected void indexSimilarityBinaries(ElasticsearchDocument doc, 
PropertyDefinition pd, Blob blob) throws IOException {
+        // TODO : not implemented
+    }
+
+    @Override
+    protected void indexSimilarityStrings(ElasticsearchDocument doc, 
PropertyDefinition pd, String value) throws IOException {
+        // TODO : not implemented
+    }
+
+    @Override
+    protected boolean augmentCustomFields(String path, ElasticsearchDocument 
doc, NodeState document) {
+        // TODO : not implemented
+        return false;
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchDocumentMaker.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditor.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditor.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditor.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditor.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch.index;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.plugins.index.IndexEditor;
+import 
org.apache.jackrabbit.oak.plugins.index.search.spi.editor.FulltextIndexEditor;
+import 
org.apache.jackrabbit.oak.plugins.index.search.spi.editor.FulltextIndexEditorContext;
+
+/**
+ * {@link IndexEditor} implementation that is responsible for keeping the
+ * corresponding Elasticsearch index up to date
+ */
+public class ElasticsearchIndexEditor extends 
FulltextIndexEditor<ElasticsearchDocument> {
+    ElasticsearchIndexEditor(FulltextIndexEditorContext<ElasticsearchDocument> 
context) throws CommitFailedException {
+        super(context);
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorContext.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorContext.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorContext.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorContext.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch.index;
+
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
+import org.apache.jackrabbit.oak.plugins.index.IndexingContext;
+import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.apache.jackrabbit.oak.plugins.index.search.spi.editor.DocumentMaker;
+import 
org.apache.jackrabbit.oak.plugins.index.search.spi.editor.FulltextIndexEditorContext;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.jetbrains.annotations.Nullable;
+
+public class ElasticsearchIndexEditorContext extends 
FulltextIndexEditorContext<ElasticsearchDocument> {
+    ElasticsearchIndexEditorContext(NodeState root,
+                                    NodeBuilder definition, @Nullable 
IndexDefinition indexDefinition,
+                                    IndexUpdateCallback updateCallback,
+                                    ElasticsearchIndexWriterFactory 
indexWriterFactory,
+                                    ExtractedTextCache extractedTextCache,
+                                    IndexingContext indexingContext,
+                                    boolean asyncIndexing) {
+        super(root, definition, indexDefinition, updateCallback, 
indexWriterFactory, extractedTextCache, indexingContext, asyncIndexing);
+    }
+
+    @Override
+    public IndexDefinition.Builder newDefinitionBuilder() {
+        return new IndexDefinition.Builder();
+    }
+
+    @Override
+    public DocumentMaker<ElasticsearchDocument> 
newDocumentMaker(IndexDefinition.IndexingRule rule, String path) {
+        return new ElasticsearchDocumentMaker(getTextExtractor(), 
getDefinition(), rule, path);
+    }
+
+    @Override
+    public void enableReindexMode() {
+        super.enableReindexMode();
+
+        // Now, that index definition _might_ have been migrated by super 
call, it would be ok to
+        // get writer and provision index settings and mappings
+        getWriter().setProvisioningRequired();
+    }
+
+    @Override
+    public ElasticsearchIndexWriter getWriter() {
+        return (ElasticsearchIndexWriter)super.getWriter();
+    }
+}
\ No newline at end of file

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorProvider.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorProvider.java?rev=1863411&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorProvider.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorProvider.java
 Fri Jul 19 18:26:56 2019
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.elasticsearch.index;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.plugins.index.ContextAwareCallback;
+import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
+import org.apache.jackrabbit.oak.plugins.index.IndexingContext;
+import 
org.apache.jackrabbit.oak.plugins.index.elasticsearch.ElasticsearchIndexCoordinateFactory;
+import 
org.apache.jackrabbit.oak.plugins.index.elasticsearch.ElasticsearchIndexDefinition;
+import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static 
org.apache.jackrabbit.oak.plugins.index.elasticsearch.ElasticsearchIndexConstants.TYPE_ELASTICSEARCH;
+
+public class ElasticsearchIndexEditorProvider implements IndexEditorProvider {
+
+    private final ElasticsearchIndexCoordinateFactory esIndexCoordFactory;
+    private final ExtractedTextCache extractedTextCache;
+
+    public ElasticsearchIndexEditorProvider(@NotNull 
ElasticsearchIndexCoordinateFactory esIndexCoordFactory,
+                                            ExtractedTextCache 
extractedTextCache) {
+        this.esIndexCoordFactory = esIndexCoordFactory;
+        this.extractedTextCache = extractedTextCache != null ? 
extractedTextCache : new ExtractedTextCache(0, 0);
+    }
+
+    @Override
+    public @Nullable Editor getIndexEditor(@NotNull String type,
+                                           @NotNull NodeBuilder definition, 
@NotNull NodeState root,
+                                           @NotNull IndexUpdateCallback 
callback) throws CommitFailedException {
+        if (TYPE_ELASTICSEARCH.equals(type)) {
+            checkArgument(callback instanceof ContextAwareCallback, "callback 
instance not of type " +
+                    "ContextAwareCallback [%s]", callback);
+            IndexingContext indexingContext = 
((ContextAwareCallback)callback).getIndexingContext();
+
+            String indexPath = indexingContext.getIndexPath();
+            ElasticsearchIndexDefinition indexDefinition =
+                    new ElasticsearchIndexDefinition(root, 
definition.getNodeState(), indexPath);
+
+            ElasticsearchIndexWriterFactory writerFactory = new 
ElasticsearchIndexWriterFactory(esIndexCoordFactory);
+
+            ElasticsearchIndexEditorContext context = new 
ElasticsearchIndexEditorContext(root,
+                    definition, indexDefinition,
+                    callback,
+                    writerFactory,
+                    extractedTextCache,
+                    indexingContext,
+                    true);
+
+            return new ElasticsearchIndexEditor(context);
+        }
+        return null;
+    }
+
+    public ExtractedTextCache getExtractedTextCache() {
+        return extractedTextCache;
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-search-elastic/src/main/java/org/apache/jackrabbit/oak/plugins/index/elasticsearch/index/ElasticsearchIndexEditorProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to