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

[Feature/multi_tenancy] SdkClient interface with local and remote implementations for Connector #2459

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright OpenSearch Contributors
* 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.sdk;

public class DeleteDataObjectRequest {

private final String index;
private final String id;

/**
* Instantiate this request with an index and id.
* <p>
* For data storage implementations other than OpenSearch, an index may be referred to as a table and the id may be referred to as a primary key.
* @param index the index location to delete the object
* @param id the document id
*/
public DeleteDataObjectRequest(String index, String id) {
this.index = index;
this.id = id;
}

/**
* Returns the index
* @return the index
*/
public String index() {
return this.index;
}

/**
* Returns the document id
* @return the id
*/
public String id() {
return this.id;
}

/**
* Class for constructing a Builder for this Request Object
*/
public static class Builder {
private String index = null;
private String id = null;

/**
* Empty Constructor for the Builder object
*/
public Builder() {}

/**
* Add an index to this builder
* @param index the index to put the object
* @return the updated builder
*/
public Builder index(String index) {
this.index = index;
return this;
}

/**
* Add an id to this builder
* @param id the document id
* @return the updated builder
*/
public Builder id(String id) {
this.id = id;
return this;
}

/**
* Builds the object
* @return A {@link DeleteDataObjectRequest}
*/
public DeleteDataObjectRequest build() {
return new DeleteDataObjectRequest(this.index, this.id);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright OpenSearch Contributors
* 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.sdk;

import org.opensearch.action.support.replication.ReplicationResponse.ShardInfo;
import org.opensearch.core.common.Strings;
import org.opensearch.core.index.shard.ShardId;

public class DeleteDataObjectResponse {
private final String id;
private final ShardId shardId;
private final ShardInfo shardInfo;
Comment on lines +17 to +18
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these fields required? Shard details are specific to opensearch which will make it difficult to extend the interface to non-opensearch data stores.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I previously answered that question when you asked it here.

The return value to the end user is created from a DeleteResponse object, which requires a non-null ShardId:

this.shardId = Objects.requireNonNull(shardId);

So I have to have a Shard ID. I can create one, or I can pass along the actual one that is returned from cluster-based OpenSearch. Which do you prefer? I see no good reason to delete information that exists. It can be ignored for other implementations.

Similarly, for ShardInfo, the return value from the Delete Connector API looks like this:

{
    "_index": ".plugins-ml-connector",
    "_id": "qU00aowBH9rhI2IwnrH3",
    "_version": 2,
    "result": "deleted",
    "_shards": {
        "total": 1,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 2,
    "_primary_term": 1
}

I can either pass along those actual statistics or make them up. Which is easier to explain to a customer, that a statistic might be irrelevant for their storage option, or that we're taking away information they used to have?

private final boolean deleted;

/**
* Instantiate this request.
* <p>
* For data storage implementations other than OpenSearch, an index may be referred to as a table and the id may be referred to as a primary key.
* @param id the document id
* @param shardId the shard id
* @param shardInfo the shard info
* @param deleted Whether the object was deleted. Use {@code false} if the object was not found.
*/
public DeleteDataObjectResponse(String id, ShardId shardId, ShardInfo shardInfo, boolean deleted) {
this.id = id;
this.shardId = shardId;
this.shardInfo = shardInfo;
this.deleted = deleted;
}

/**
* Returns the document id
* @return the id
*/
public String id() {
return id;
}

/**
* Returns the shard id.
* @return the shard id, or a generated id if shards are not applicable
*/
public ShardId shardId() {
return shardId;
}

/**
* Returns the shard info.
* @return the shard info, or generated info if shards are not applicable
*/
public ShardInfo shardInfo() {
return shardInfo;
}

/**
* Returns whether deletion was successful
* @return true if deletion was successful, false if the object was not found
*/
public boolean deleted() {
return deleted;
}

/**
* Class for constructing a Builder for this Response Object
*/
public static class Builder {
private String id = null;
private ShardId shardId = null;
private ShardInfo shardInfo = null;
private boolean deleted = false;

/**
* Empty Constructor for the Builder object
*/
public Builder() {}

/**
* Add an id to this builder
* @param id the id to add
* @return the updated builder
*/
public Builder id(String id) {
this.id = id;
return this;
}

/**
* Adds a shard id to this builder
* @param shardId the shard id to add
* @return the updated builder
*/
public Builder shardId(ShardId shardId) {
this.shardId = shardId;
return this;
}

/**
* Adds a generated shard id to this builder
* @param indexName the index name to generate a shard id
* @return the updated builder
*/
public Builder shardId(String indexName) {
this.shardId = new ShardId(indexName, Strings.UNKNOWN_UUID_VALUE, 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to understand this part more. What's the significance of generating a random shard ID here? How this can help end user?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answered above and also here, but I"ll repeat:

The DeleteResponse object requires a non-null ShardId.

this.shardId = Objects.requireNonNull(shardId);

When there isn't one provided (such as DynamoDb) this code creates a simulated one.

Copy link
Collaborator

@dhrubo-os dhrubo-os May 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I saw your answer earlier too. I think for DDB / other non OS cases, if we just share a random shardID, that could be confusing for customers. I would prefer sharing any static String, maybe like Not Applicable or N/A, which can convey the actual meaning rather than causing unnecessary confusion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer sharing any static String, maybe like Not Applicable or N/A, which can convey the actual meaning rather than causing unnecessary confusion.

The Strings.UNKNOWN_UUID_VALUE is _na_.

return this;
}

/**
* Adds shard information (statistics) to this builder
* @param shardInfo the shard info to add
* @return the updated builder
*/
public Builder shardInfo(ShardInfo shardInfo) {
this.shardInfo = shardInfo;
return this;
}

/**
* Add a deleted status to this builder
* @param deleted the deleted status to add
* @return the updated builder
*/
public Builder deleted(boolean deleted) {
this.deleted = deleted;
return this;
}

/**
* Builds the object
* @return A {@link DeleteDataObjectResponse}
*/
public DeleteDataObjectResponse build() {
return new DeleteDataObjectResponse(this.id, this.shardId, this.shardInfo, this.deleted);
}
}
}
108 changes: 108 additions & 0 deletions common/src/main/java/org/opensearch/sdk/GetDataObjectRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright OpenSearch Contributors
* 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.sdk;

import org.opensearch.search.fetch.subphase.FetchSourceContext;

public class GetDataObjectRequest {

private final String index;
private final String id;
private final FetchSourceContext fetchSourceContext;

/**
* Instantiate this request with an index and id
* <p>
* For data storage implementations other than OpenSearch, an index may be referred to as a table and the id may be referred to as a primary key.
* @param index the index location to get the object
* @param id the document id
* @param fetchSourceContext the context to use when fetching _source
*/
public GetDataObjectRequest(String index, String id, FetchSourceContext fetchSourceContext) {
this.index = index;
this.id = id;
this.fetchSourceContext = fetchSourceContext;
}

/**
* Returns the index
* @return the index
*/
public String index() {
return this.index;
}

/**
* Returns the document id
* @return the id
*/
public String id() {
return this.id;
}

/**
* Returns the context for fetching _source
* @return the fetchSourceContext
*/
public FetchSourceContext fetchSourceContext() {
return this.fetchSourceContext;
}

/**
* Class for constructing a Builder for this Request Object
*/
public static class Builder {
private String index = null;
private String id = null;
private FetchSourceContext fetchSourceContext;

/**
* Empty Constructor for the Builder object
*/
public Builder() {}

/**
* Add an index to this builder
* @param index the index to put the object
* @return the updated builder
*/
public Builder index(String index) {
this.index = index;
return this;
}

/**
* Add an id to this builder
* @param id the document id
* @return the updated builder
*/
public Builder id(String id) {
this.id = id;
return this;
}

/**
* Add a fetchSourceContext to this builder
* @param fetchSourceContext the fetchSourceContext
* @return the updated builder
*/
public Builder fetchSourceContext(FetchSourceContext fetchSourceContext) {
this.fetchSourceContext = fetchSourceContext;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if the fetchSourceContext is null?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the default value for the GetRequest if it's not provided. Although I did notice that I didn't pass this on to the GetRequest so I'll fix that.

return this;
}

/**
* Builds the request
* @return A {@link GetDataObjectRequest}
*/
public GetDataObjectRequest build() {
return new GetDataObjectRequest(this.index, this.id, this.fetchSourceContext);
}
}
}
Loading
Loading