Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Projected Views #11957

Merged
merged 63 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
6bf2cf6
Basic view stubs
peternied Dec 8, 2023
3522cc7
Cluster metadat
peternied Dec 14, 2023
4e12632
Basic request handling
peternied Dec 15, 2023
3a15863
Accepting requests
peternied Dec 15, 2023
23632b6
Search rewriting and design dco
peternied Dec 18, 2023
6031347
Functional views
peternied Dec 19, 2023
c66425a
Minor changes
peternied Dec 19, 2023
c191cc8
Resource Requset
peternied Dec 19, 2023
4abefd0
Add FAQ sectino
peternied Dec 19, 2023
dace87a
Tidying up
peternied Dec 22, 2023
c88febe
Read prepare for merge into OpenSearch
peternied Jan 17, 2024
61e8c98
Fix build issue
peternied Jan 17, 2024
ac25c96
Fix build issues
peternied Jan 29, 2024
8e41fbe
Unit tests for view
peternied Jan 29, 2024
cf22a8d
Basic pattern for decoupled views in metadata vs transport requests
peternied Feb 1, 2024
2f615cf
Merge branch 'views-core' into views
peternied Feb 1, 2024
d45fcb9
Integration tests and some unit tests
peternied Feb 3, 2024
2832b24
Spotless and compile issue
peternied Feb 5, 2024
db00415
Clean up license headers
peternied Feb 5, 2024
6a947e4
Fix logger usage miss
peternied Feb 5, 2024
6156eb9
Before adding all action types
peternied Feb 5, 2024
a7dbd93
Expand action types
peternied Feb 5, 2024
f12efaa
wire up all actions
peternied Feb 6, 2024
135acba
Functional integration test
peternied Feb 6, 2024
ac456da
refactor how view names are listed in tests
peternied Feb 6, 2024
327d158
More tests
peternied Feb 6, 2024
b95056a
Following up on PR feedback
peternied Feb 6, 2024
ea78012
Add changelog entry
peternied Feb 6, 2024
242ab85
Merge branch 'main' into views-core
peternied Feb 6, 2024
7810ddf
Merge remote-tracking branch 'origin/main' into views-core
peternied Feb 7, 2024
01655d0
Fix build warning about test annotations
peternied Feb 8, 2024
292a322
Round out integration tests
peternied Feb 9, 2024
07bcfe0
Add test cases
peternied Feb 9, 2024
e7f36b0
Fix compile issue
peternied Feb 9, 2024
65fa8e7
Rename test class
peternied Feb 12, 2024
4327237
PR feedback pass
peternied Feb 12, 2024
5beefbb
Spotless
peternied Feb 12, 2024
16b2b52
Merge remote-tracking branch 'origin/main' into views-core
peternied Feb 13, 2024
edd8902
More logging information
peternied Feb 13, 2024
ba385e4
Fix spotless
peternied Feb 13, 2024
0663818
More detailed logging from checkStaticState
peternied Feb 13, 2024
7f28330
Detact metadataFilesEligibleToDelete from its source collection
peternied Feb 13, 2024
8cb9f55
Fix spotless issue
peternied Feb 13, 2024
9d0e1b0
Breakout exceptions into their own clases
peternied Feb 13, 2024
25e3ca9
Merge remote-tracking branch 'peternied/views-core' into views-core
peternied Feb 13, 2024
e58acdb
Clean up logger output message
peternied Feb 13, 2024
6e9dffb
Revert changes to NamedRoute
peternied Feb 13, 2024
cba189e
Revert changes to SearchRequest and follow pipeline model
peternied Feb 13, 2024
eae9511
Remove unused codepath
peternied Feb 13, 2024
fcacb01
Update exception serialization tests
peternied Feb 14, 2024
db8f049
PR feedback
peternied Feb 15, 2024
4936736
Fix error in RemoteSegmentStoreDirectory when debug logging is enabled
peternied Feb 15, 2024
8c39071
Add changelog entry
peternied Feb 15, 2024
7259789
Use sorted set to store targets for views
peternied Feb 15, 2024
fa913f7
Test compile checks
peternied Feb 15, 2024
a9777be
Fix compile issues related to switch to set
peternied Feb 15, 2024
8796381
Add test to validate debug log statement doesn't have errors
peternied Feb 15, 2024
0dd44f7
Add test to validate debug log statement doesn't have errors
peternied Feb 15, 2024
d77f812
Dial back the level of detail validated for the segments that are del…
peternied Feb 15, 2024
946a691
Merge branch 'RemoteSegmentStoreDirectory' into views-core
peternied Feb 15, 2024
fc600ac
Dial back the level of detail validated for the segments that are del…
peternied Feb 15, 2024
bbf4945
Merge branch 'RemoteSegmentStoreDirectory' into views-core
peternied Feb 15, 2024
2ac6e68
Merge remote-tracking branch 'origin/main' into views-core
peternied Feb 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Enable Fuzzy codec for doc id fields using a bloom filter ([#11022](https://github.com/opensearch-project/OpenSearch/pull/11022))
- [Metrics Framework] Adds support for Histogram metric ([#12062](https://github.com/opensearch-project/OpenSearch/pull/12062))
- Support for returning scores in matched queries ([#11626](https://github.com/opensearch-project/OpenSearch/pull/11626))
- Projected Views ([#11957](https://github.com/opensearch-project/OpenSearch/pull/11957))

### Dependencies
- Bumps jetty version to 9.4.52.v20230823 to fix GMS-2023-1857 ([#9822](https://github.com/opensearch-project/OpenSearch/pull/9822))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.action.admin.indices.view;

import org.opensearch.ResourceNotFoundException;
import org.opensearch.cluster.metadata.View;
import org.opensearch.test.OpenSearchIntegTestCase.ClusterScope;
import org.opensearch.test.OpenSearchIntegTestCase.Scope;
import org.hamcrest.MatcherAssert;

import java.util.List;

import static org.opensearch.test.hamcrest.OpenSearchAssertions.assertHitCount;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;

@ClusterScope(scope = Scope.TEST, numDataNodes = 2)
public class ViewIT extends ViewTestBase {

public void testCreateView() throws Exception {
final String viewName = randomAlphaOfLength(8);
final String indexPattern = randomAlphaOfLength(8);

logger.info("Testing createView with valid parameters");
final View view = createView(viewName, indexPattern).getView();
MatcherAssert.assertThat(view.getName(), is(viewName));
MatcherAssert.assertThat(view.getTargets().size(), is(1));
MatcherAssert.assertThat(view.getTargets().get(0).getIndexPattern(), is(indexPattern));

logger.info("Testing createView with existing view name");
final Exception ex = assertThrows(ResourceNotFoundException.class, () -> createView(viewName, randomAlphaOfLength(8)));
MatcherAssert.assertThat(ex.getMessage(), is("View [" + viewName + "] already exists"));
}

public void testGetView() throws Exception {
final String viewName = randomAlphaOfLength(8);
createView(viewName, randomAlphaOfLength(8));

final View view = getView(viewName).getView();
MatcherAssert.assertThat(view.getName(), is(viewName));

logger.info("Testing getView with non-existent view");
final String nonExistentView = "non-existent-" + randomAlphaOfLength(8);
final Exception whenNeverExistedEx = assertThrows(ResourceNotFoundException.class, () -> getView(nonExistentView));
MatcherAssert.assertThat(whenNeverExistedEx.getMessage(), is("View [" + nonExistentView + "] does not exist"));
}

public void testDeleteView() throws Exception {
final String viewName = randomAlphaOfLength(8);
createView(viewName, randomAlphaOfLength(8));

logger.info("Testing deleteView with existing view");
deleteView(viewName);
final Exception whenDeletedEx = assertThrows(ResourceNotFoundException.class, () -> getView(viewName));
MatcherAssert.assertThat(whenDeletedEx.getMessage(), is("View [" + viewName + "] does not exist"));

logger.info("Testing deleteView with non-existent view");
final String nonExistentView = "non-existent-" + randomAlphaOfLength(8);
final Exception whenNeverExistedEx = assertThrows(ResourceNotFoundException.class, () -> deleteView(nonExistentView));
MatcherAssert.assertThat(whenNeverExistedEx.getMessage(), is("View [" + nonExistentView + "] does not exist"));
}

public void testUpdateView() throws Exception {
final String viewName = randomAlphaOfLength(8);
final String originalIndexPattern = randomAlphaOfLength(8);
final View originalView = createView(viewName, originalIndexPattern).getView();

logger.info("Testing updateView with existing view");
final String newDescription = randomAlphaOfLength(20);
final String newIndexPattern = "newPattern-" + originalIndexPattern;
final View updatedView = updateView(viewName, newDescription, newIndexPattern).getView();

MatcherAssert.assertThat(updatedView, not(is(originalView)));
MatcherAssert.assertThat(updatedView.getDescription(), is(newDescription));
MatcherAssert.assertThat(updatedView.getTargets(), hasSize(1));
MatcherAssert.assertThat(updatedView.getTargets().get(0).getIndexPattern(), is(newIndexPattern));

logger.info("Testing updateView with non-existent view");
final String nonExistentView = "non-existent-" + randomAlphaOfLength(8);
final Exception whenNeverExistedEx = assertThrows(
ResourceNotFoundException.class,
() -> updateView(nonExistentView, null, "index-*")
);
MatcherAssert.assertThat(whenNeverExistedEx.getMessage(), is("View [" + nonExistentView + "] does not exist"));
}

public void testListViewNames() throws Exception {
logger.info("Testing listViewNames when no views have been created");
MatcherAssert.assertThat(listViewNames(), is(List.of()));

final String view1 = "view1";
final String view2 = "view2";
createView(view1, "index-1-*");
createView(view2, "index-2-*");

logger.info("Testing listViewNames");
final List<String> views = listViewNames();
MatcherAssert.assertThat(views, containsInAnyOrder(view1, view2));

logger.info("Testing listViewNames after deleting a view");
deleteView(view1);
final List<String> viewsAfterDeletion = listViewNames();
MatcherAssert.assertThat(viewsAfterDeletion, not(contains(view1)));
MatcherAssert.assertThat(viewsAfterDeletion, contains(view2));
}

public void testSearchOperations() throws Exception {
final String indexInView1 = "index-1";
final String indexInView2 = "index-2";
final String indexNotInView = "another-index-1";

final int indexInView1DocCount = createIndexWithDocs(indexInView1);
final int indexInView2DocCount = createIndexWithDocs(indexInView2);
createIndexWithDocs(indexNotInView);

logger.info("Testing view with no matches");
createView("no-matches", "this-pattern-will-match-nothing");
final Exception ex = assertThrows(ResourceNotFoundException.class, () -> searchView("no-matches"));
MatcherAssert.assertThat(ex.getMessage(), is("no such index [this-pattern-will-match-nothing]"));

logger.info("Testing view with exact index match");
createView("only-index-1", "index-1");
assertHitCount(searchView("only-index-1"), indexInView1DocCount);

logger.info("Testing view with wildcard matches");
createView("both-indices", "index-*");
assertHitCount(searchView("both-indices"), indexInView1DocCount + indexInView2DocCount);

logger.info("Testing searchView with non-existent view");
final String nonExistentView = "non-existent-" + randomAlphaOfLength(8);
final Exception whenNeverExistedEx = assertThrows(ResourceNotFoundException.class, () -> searchView(nonExistentView));
MatcherAssert.assertThat(whenNeverExistedEx.getMessage(), is("View [" + nonExistentView + "] does not exist"));
}
}
peternied marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.action.admin.indices.view;

import org.opensearch.action.search.SearchRequest;
import org.opensearch.action.search.SearchResponse;
import org.opensearch.test.BackgroundIndexer;
import org.opensearch.test.OpenSearchIntegTestCase;

import java.util.List;

import static org.opensearch.test.hamcrest.OpenSearchAssertions.assertHitCount;

public abstract class ViewTestBase extends OpenSearchIntegTestCase {

protected int createIndexWithDocs(final String indexName) throws Exception {
createIndex(indexName);
ensureGreen(indexName);

final int numOfDocs = scaledRandomIntBetween(0, 200);
try (final BackgroundIndexer indexer = new BackgroundIndexer(indexName, "_doc", client(), numOfDocs)) {
waitForDocs(numOfDocs, indexer);
}

refresh(indexName);
assertHitCount(client().prepareSearch(indexName).setSize(0).get(), numOfDocs);
return numOfDocs;
}

protected GetViewAction.Response createView(final String name, final String indexPattern) throws Exception {
final CreateViewAction.Request request = new CreateViewAction.Request(
name,
null,
List.of(new CreateViewAction.Request.Target(indexPattern))
);
return client().admin().indices().createView(request).actionGet();
}

protected GetViewAction.Response getView(final String name) {
return client().admin().indices().getView(new GetViewAction.Request(name)).actionGet();

}

protected void deleteView(final String name) {
client().admin().indices().deleteView(new DeleteViewAction.Request(name)).actionGet();
performRemoteStoreTestAction();
}

protected List<String> listViewNames() {
return client().listViewNames(new ListViewNamesAction.Request()).actionGet().getViewNames();
}

protected SearchResponse searchView(final String viewName) throws Exception {
final SearchViewAction.Request request = SearchViewAction.createRequestWith(viewName, new SearchRequest());
final SearchResponse response = client().searchView(request).actionGet();
return response;
}

protected GetViewAction.Response updateView(final String name, final String description, final String indexPattern) {
final CreateViewAction.Request request = new CreateViewAction.Request(
name,
description,
List.of(new CreateViewAction.Request.Target(indexPattern))
);
final GetViewAction.Response response = client().admin().indices().updateView(request).actionGet();
return response;
}
}
23 changes: 23 additions & 0 deletions server/src/main/java/org/opensearch/action/ActionModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@
import org.opensearch.action.admin.indices.upgrade.post.UpgradeSettingsAction;
import org.opensearch.action.admin.indices.validate.query.TransportValidateQueryAction;
import org.opensearch.action.admin.indices.validate.query.ValidateQueryAction;
import org.opensearch.action.admin.indices.view.CreateViewAction;
import org.opensearch.action.admin.indices.view.DeleteViewAction;
import org.opensearch.action.admin.indices.view.GetViewAction;
import org.opensearch.action.admin.indices.view.ListViewNamesAction;
import org.opensearch.action.admin.indices.view.SearchViewAction;
import org.opensearch.action.admin.indices.view.UpdateViewAction;
import org.opensearch.action.bulk.BulkAction;
import org.opensearch.action.bulk.TransportBulkAction;
import org.opensearch.action.bulk.TransportShardBulkAction;
Expand Down Expand Up @@ -409,6 +415,7 @@
import org.opensearch.rest.action.admin.indices.RestUpgradeAction;
import org.opensearch.rest.action.admin.indices.RestUpgradeStatusAction;
import org.opensearch.rest.action.admin.indices.RestValidateQueryAction;
import org.opensearch.rest.action.admin.indices.RestViewAction;
import org.opensearch.rest.action.cat.AbstractCatAction;
import org.opensearch.rest.action.cat.RestAliasAction;
import org.opensearch.rest.action.cat.RestAllocationAction;
Expand Down Expand Up @@ -721,6 +728,14 @@ public <Request extends ActionRequest, Response extends ActionResponse> void reg
actions.register(ResolveIndexAction.INSTANCE, ResolveIndexAction.TransportAction.class);
actions.register(DataStreamsStatsAction.INSTANCE, DataStreamsStatsAction.TransportAction.class);

// Views:
actions.register(CreateViewAction.INSTANCE, CreateViewAction.TransportAction.class);
actions.register(DeleteViewAction.INSTANCE, DeleteViewAction.TransportAction.class);
actions.register(GetViewAction.INSTANCE, GetViewAction.TransportAction.class);
actions.register(UpdateViewAction.INSTANCE, UpdateViewAction.TransportAction.class);
actions.register(ListViewNamesAction.INSTANCE, ListViewNamesAction.TransportAction.class);
actions.register(SearchViewAction.INSTANCE, SearchViewAction.TransportAction.class);

// Persistent tasks:
actions.register(StartPersistentTaskAction.INSTANCE, StartPersistentTaskAction.TransportAction.class);
actions.register(UpdatePersistentTaskStatusAction.INSTANCE, UpdatePersistentTaskStatusAction.TransportAction.class);
Expand Down Expand Up @@ -915,6 +930,14 @@ public void initRestHandlers(Supplier<DiscoveryNodes> nodesInCluster) {
registerHandler.accept(new RestResolveIndexAction());
registerHandler.accept(new RestDataStreamsStatsAction());

// View API
registerHandler.accept(new RestViewAction.CreateViewHandler());
registerHandler.accept(new RestViewAction.DeleteViewHandler());
registerHandler.accept(new RestViewAction.GetViewHandler());
registerHandler.accept(new RestViewAction.UpdateViewHandler());
registerHandler.accept(new RestViewAction.SearchViewHandler());
registerHandler.accept(new RestViewAction.ListViewNamesHandler());

// CAT API
registerHandler.accept(new RestAllocationAction());
registerHandler.accept(new RestCatSegmentReplicationAction());
Expand Down
Loading
Loading