From c2a2f127309356e1218e5b0794ca7cc87a82b6f3 Mon Sep 17 00:00:00 2001 From: ZMai <zmai@slb.com> Date: Wed, 25 Jan 2023 13:32:08 -0600 Subject: [PATCH] Use alias instead of index name if the given index name list is too large (> 3840 bytes) --- pom.xml | 2 +- search-core/pom.xml | 1 - .../osdu/search/cache/IndexAliasCache.java | 25 ++++ .../search/service/IndexAliasService.java | 20 +++ .../search/service/IndexAliasServiceImpl.java | 140 ++++++++++++++++++ .../osdu/search/util/CrossTenantUtils.java | 29 +++- 6 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 search-core/src/main/java/org/opengroup/osdu/search/cache/IndexAliasCache.java create mode 100644 search-core/src/main/java/org/opengroup/osdu/search/service/IndexAliasService.java create mode 100644 search-core/src/main/java/org/opengroup/osdu/search/service/IndexAliasServiceImpl.java diff --git a/pom.xml b/pom.xml index 0fd44516f..07dd7ac01 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ <log4j-core.version>2.17.1</log4j-core.version> <google-oauth-client.version>1.34.1</google-oauth-client.version> <commons-compress.version>1.21</commons-compress.version> - <osdu.oscorecommon.version>0.18.0</osdu.oscorecommon.version> + <osdu.oscorecommon.version>0.19.0-SNAPSHOT-ALIAS</osdu.oscorecommon.version> <tomcat-embed-core.version>9.0.67</tomcat-embed-core.version> <openapi.version>1.6.9</openapi.version> <json-smart.version>2.4.7</json-smart.version> diff --git a/search-core/pom.xml b/search-core/pom.xml index dc6453dbb..c74e09ec5 100644 --- a/search-core/pom.xml +++ b/search-core/pom.xml @@ -38,7 +38,6 @@ <project.main.basedir>${project.basedir}</project.main.basedir> <nimbus-jose-jwt.version>9.1.2</nimbus-jose-jwt.version> <elasticsearch.version>7.8.1</elasticsearch.version> - <osdu.oscorecommon.version>0.17.0</osdu.oscorecommon.version> <netty.version>4.1.70.Final</netty.version> <spring-security-web.version>5.7.3</spring-security-web.version> <spring-webmvc.version>5.3.22</spring-webmvc.version> diff --git a/search-core/src/main/java/org/opengroup/osdu/search/cache/IndexAliasCache.java b/search-core/src/main/java/org/opengroup/osdu/search/cache/IndexAliasCache.java new file mode 100644 index 000000000..9861d743f --- /dev/null +++ b/search-core/src/main/java/org/opengroup/osdu/search/cache/IndexAliasCache.java @@ -0,0 +1,25 @@ +// Copyright © Schlumberger +// +// Licensed 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.opengroup.osdu.search.cache; + +import org.opengroup.osdu.core.common.cache.VmCache; +import org.springframework.stereotype.Component; + +@Component +public class IndexAliasCache extends VmCache<String, String> { + public IndexAliasCache() { + super(7 * 24 * 3600, 2000); + } +} diff --git a/search-core/src/main/java/org/opengroup/osdu/search/service/IndexAliasService.java b/search-core/src/main/java/org/opengroup/osdu/search/service/IndexAliasService.java new file mode 100644 index 000000000..16ebc6e82 --- /dev/null +++ b/search-core/src/main/java/org/opengroup/osdu/search/service/IndexAliasService.java @@ -0,0 +1,20 @@ +// Copyright © Schlumberger +// +// Licensed 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.opengroup.osdu.search.service; + +public interface IndexAliasService { + boolean hasIndexAlias(String kind); + String getIndexAlias(String kind); +} diff --git a/search-core/src/main/java/org/opengroup/osdu/search/service/IndexAliasServiceImpl.java b/search-core/src/main/java/org/opengroup/osdu/search/service/IndexAliasServiceImpl.java new file mode 100644 index 000000000..be57189e7 --- /dev/null +++ b/search-core/src/main/java/org/opengroup/osdu/search/service/IndexAliasServiceImpl.java @@ -0,0 +1,140 @@ +// Copyright © Schlumberger +// +// Licensed 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.opengroup.osdu.search.service; + +import com.google.api.client.util.Strings; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; +import org.elasticsearch.action.support.master.AcknowledgedResponse; +import org.elasticsearch.client.GetAliasesResponse; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.cluster.metadata.AliasMetadata; +import org.elasticsearch.rest.RestStatus; +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import org.opengroup.osdu.core.common.search.ElasticIndexNameResolver; +import org.opengroup.osdu.search.cache.IndexAliasCache; +import org.opengroup.osdu.search.util.ElasticClientHandler; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Component +public class IndexAliasServiceImpl implements IndexAliasService { + @Inject + private ElasticClientHandler elasticClientHandler; + @Inject + private ElasticIndexNameResolver elasticIndexNameResolver; + @Inject + private IndexAliasCache indexAliasCache; + @Inject + private JaxRsDpsLog log; + + @Override + public boolean hasIndexAlias(String kind) { + if(!elasticIndexNameResolver.isIndexAliasSupported(kind)) + return false; + + String alias = indexAliasCache.get(kind); + if(Strings.isNullOrEmpty(alias)) { + try { + alias = getOrCreateIndexAliases(kind); + if(!Strings.isNullOrEmpty(alias)) { + indexAliasCache.put(kind, alias); + } + } catch (Exception e) { + log.error(String.format("Fail to get or create index alias for kind '%s'", kind), e); + } + } + + return (!Strings.isNullOrEmpty(alias)); + } + + public String getIndexAlias(String kind) { + if(hasIndexAlias(kind)) { + return indexAliasCache.get(kind); + } + return null; + } + + private String getOrCreateIndexAliases(String kind) throws IOException { + String alias = elasticIndexNameResolver.getIndexAliasFromKind(kind); + try (RestHighLevelClient restClient = this.elasticClientHandler.createRestClient()) { + GetAliasesRequest request = new GetAliasesRequest(alias); + if(restClient.indices().existsAlias(request, RequestOptions.DEFAULT)) { + return alias; + } + + String index = elasticIndexNameResolver.getIndexNameFromKind(kind); + // To create an alias for an index, the index name must the concrete index name, not alias + index = resolveConcreteIndexName(restClient, index); + if(!Strings.isNullOrEmpty(index)) { + IndicesAliasesRequest addRequest = new IndicesAliasesRequest(); + IndicesAliasesRequest.AliasActions aliasActions = new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.ADD) + .index(index) + .alias(alias); + addRequest.addAliasAction(aliasActions); + AcknowledgedResponse response = restClient.indices().updateAliases(addRequest, RequestOptions.DEFAULT); + if(response.isAcknowledged()) { + return alias; + } + } + } + + return null; + } + + private String resolveConcreteIndexName(RestHighLevelClient restClient, String index) throws IOException { + GetAliasesRequest request = new GetAliasesRequest(index); + GetAliasesResponse response = restClient.indices().getAlias(request, RequestOptions.DEFAULT); + if(response.status() == RestStatus.NOT_FOUND) { + /* index resolved from kind is actual concrete index + * Example: + * { + * "opendes-wke-well-1.0.7": { + * "aliases": {} + * } + * } + */ + return index; + } + if(response.status() == RestStatus.OK) { + /* index resolved from kind is NOT actual create index. It is just an alias + * The concrete index name in this example is "opendes-osdudemo-wellbore-1.0.0_1649167113090" + * Example: + * { + * "opendes-osdudemo-wellbore-1.0.0_1649167113090": { + * "aliases": { + * "opendes-osdudemo-wellbore-1.0.0": {} + * } + * } + * } + */ + Map<String, Set<AliasMetadata>> aliases = response.getAliases(); + for (Map.Entry<String, Set<AliasMetadata>> entry: aliases.entrySet()) { + String actualIndex = entry.getKey(); + List<String> aliaseNames = entry.getValue().stream().map(a -> a.getAlias()).collect(Collectors.toList()); + if(aliaseNames.contains(index)) + return actualIndex; + } + } + return null; + } +} diff --git a/search-core/src/main/java/org/opengroup/osdu/search/util/CrossTenantUtils.java b/search-core/src/main/java/org/opengroup/osdu/search/util/CrossTenantUtils.java index a21c0b1f6..ba2b7a439 100644 --- a/search-core/src/main/java/org/opengroup/osdu/search/util/CrossTenantUtils.java +++ b/search-core/src/main/java/org/opengroup/osdu/search/util/CrossTenantUtils.java @@ -14,9 +14,11 @@ package org.opengroup.osdu.search.util; +import com.google.api.client.util.Strings; import org.opengroup.osdu.core.common.search.ElasticIndexNameResolver; import org.opengroup.osdu.core.common.model.search.Query; import org.opengroup.osdu.core.common.util.KindParser; +import org.opengroup.osdu.search.service.IndexAliasService; import org.springframework.stereotype.Component; import javax.inject.Inject; @@ -24,16 +26,37 @@ import java.util.List; @Component public class CrossTenantUtils { + // For details, please refer to implementation of class + // org.opengroup.osdu.core.common.model.search.validation.MultiKindValidator + private static final int MAX_INDEX_NAME_LENGTH = 3840; @Inject private ElasticIndexNameResolver elasticIndexNameResolver; + @Inject + private IndexAliasService indexAliasService; public String getIndexName(Query searchRequest) { - StringBuilder builder = new StringBuilder(); List<String> kinds = KindParser.parse(searchRequest.getKind()); + String indexNames = buildIndexNames(kinds, false); + if(indexNames.length() > MAX_INDEX_NAME_LENGTH) { + indexNames = buildIndexNames(kinds, true); + } + + return indexNames; + } + + private String buildIndexNames(List<String> kinds, boolean useAlias) { + StringBuilder builder = new StringBuilder(); for(String kind : kinds) { - String index = this.elasticIndexNameResolver.getIndexNameFromKind(kind); - builder.append(index + ","); + String index = null; + if(useAlias) { + index = this.indexAliasService.getIndexAlias(kind); + } + if(Strings.isNullOrEmpty(index)) { + index = this.elasticIndexNameResolver.getIndexNameFromKind(kind); + } + builder.append(index); + builder.append(","); } builder.append("-.*"); // Exclude Lucene/ElasticSearch internal indices return builder.toString(); -- GitLab