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

Introduce protobuf serialization for objects - FetchSearchResult, SearchHits, SearchHit #15372

Closed
wants to merge 61 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
0f94bf8
SerDe interfaces
finnegancarroll Aug 21, 2024
1dbe9c1
Nest SerDe interfaces
finnegancarroll Aug 21, 2024
cfd3d7f
Add serialization interface for select serializable classes
finnegancarroll Aug 21, 2024
d457b8d
Port verbatim SearchHit fromstream implementation to SerDe class
finnegancarroll Aug 21, 2024
f3dc35e
Cleanup SearchHit serialization code move
finnegancarroll Aug 22, 2024
992a032
Move SearchHit serialization to SerDe class
finnegancarroll Aug 22, 2024
8a31e75
Swap out old serde in SearchHit - prefer serde done through dedicated…
finnegancarroll Aug 22, 2024
e6be014
Use toStream with serialize
finnegancarroll Aug 22, 2024
61746b6
Decorator + import housekeeping
finnegancarroll Aug 22, 2024
c2d3856
Spotless apply
finnegancarroll Aug 22, 2024
abbefe9
Move SearchHitS serialization to SerDe class
finnegancarroll Aug 22, 2024
127ab38
Move FetchSearchResults serialization to FetchSearchResultsSerDe
finnegancarroll Aug 22, 2024
8e696bc
Spotless apply
finnegancarroll Aug 22, 2024
97f9f03
Fix deserialize - leave null maps null, not empty
finnegancarroll Aug 22, 2024
7c7322f
index & clusterAlias set by helper
finnegancarroll Aug 23, 2024
df7cdb3
Javadoc
finnegancarroll Aug 23, 2024
298182c
Comment
finnegancarroll Aug 23, 2024
fbb1feb
Javadocs
finnegancarroll Aug 23, 2024
7db42cb
Begin proto implementation
finnegancarroll Aug 23, 2024
a183e63
SearchHits to proto initial implementation - Not tested
finnegancarroll Aug 23, 2024
60bdf82
SearchHit from proto impl
finnegancarroll Aug 25, 2024
0fc2b3e
SearchHit from proto impl
finnegancarroll Aug 25, 2024
5595913
Update SearchHits proto def
finnegancarroll Aug 25, 2024
21cc29e
Tentative toProto fromProto implementations for topHits
finnegancarroll Aug 25, 2024
7f1c025
Refactor to inheritance based model
finnegancarroll Aug 26, 2024
76171a8
Break SerDe switch
finnegancarroll Aug 27, 2024
db70801
Add generated protobuf to runAnt accepted licenses
finnegancarroll Aug 27, 2024
2f4903a
Spotless apply
finnegancarroll Aug 27, 2024
2bee1b5
Restore intellij refactor error
finnegancarroll Aug 27, 2024
6ef20c8
Remove strategy wrapper. Just implement protobuf in new object, leave…
finnegancarroll Aug 27, 2024
b7291e1
Passing unit tests for primitive proto objects
finnegancarroll Aug 28, 2024
881f047
Bugfix nullable objects
finnegancarroll Aug 28, 2024
a6f0b90
Handle null explanation
finnegancarroll Aug 28, 2024
daa6ddd
Handle null totHits
finnegancarroll Aug 28, 2024
7ebe020
Explicitely set optional values to null
finnegancarroll Aug 28, 2024
c3efe2a
SearchHit/SearchHits equals() check for instance of class - Not exact…
finnegancarroll Aug 28, 2024
ea8c46f
SearchHitProto fromProto maps never null, only empty
finnegancarroll Aug 28, 2024
21f8b9e
totalHits to optional
finnegancarroll Aug 28, 2024
f86acfe
totalHits to nullable
finnegancarroll Aug 28, 2024
6e57629
Update SearchHits proto def w/ optional fields
finnegancarroll Aug 28, 2024
4a3a463
Spotless apply
finnegancarroll Aug 28, 2024
e4c2277
Collapse field to optional
finnegancarroll Aug 29, 2024
9a2838b
Seperate proto defs a bit
finnegancarroll Aug 30, 2024
bdf5084
SearchHit id to optional - Sort values to proto
finnegancarroll Sep 9, 2024
406bfbc
Decompose SearchHits sortFields to protobuf
finnegancarroll Sep 9, 2024
49c2766
SortValues to proto
finnegancarroll Sep 11, 2024
ff2e8bf
SortValues can be null - Different from optional
finnegancarroll Sep 11, 2024
61676fa
SortValues comment
finnegancarroll Sep 11, 2024
47f076d
Refactor SearchHitsProto tests
finnegancarroll Sep 18, 2024
8bb96c0
No assert not equals for potentially primitive types
finnegancarroll Sep 18, 2024
d7612de
Collapse+Sort arrays to optional
finnegancarroll Sep 18, 2024
b20bddf
Add SearchHitProtobufTests
finnegancarroll Sep 18, 2024
512c574
Mark SearchHit members as nullable where applicable
finnegancarroll Sep 18, 2024
961f035
Decompose toProto/fromProto
finnegancarroll Sep 18, 2024
69450ef
Fix innerHits nullable map
finnegancarroll Sep 18, 2024
faac1ae
Fix SortValue test when null
finnegancarroll Sep 18, 2024
47da14a
Move serde helpers into specific class definitions
finnegancarroll Sep 18, 2024
0255df3
Fix possible switch fall through
finnegancarroll Sep 18, 2024
4021722
Spotless apply
finnegancarroll Sep 18, 2024
7f4e887
Proto folder should mirror project structure
finnegancarroll Sep 23, 2024
9c79d90
Fix import
finnegancarroll Sep 23, 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
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ class LicenseHeadersTask extends AntTask {
licenseFamilyName: "Generated") {
// parsers generated by antlr
pattern(substring: "ANTLR GENERATED CODE")
// Protobuf
pattern(substring: "Generated by the protocol buffer compiler")
}

// Vendored Code
Expand Down
74 changes: 52 additions & 22 deletions server/src/main/java/org/opensearch/search/SearchHit.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,46 +98,74 @@
* @opensearch.api
*/
@PublicApi(since = "1.0.0")
public final class SearchHit implements Writeable, ToXContentObject, Iterable<DocumentField> {
public class SearchHit implements Writeable, ToXContentObject, Iterable<DocumentField> {

private final transient int docId;
protected transient int docId;

private static final float DEFAULT_SCORE = Float.NaN;
private float score = DEFAULT_SCORE;
protected float score = DEFAULT_SCORE;

private final Text id;
@Nullable
protected Text id;

private final NestedIdentity nestedIdentity;
@Nullable
protected NestedIdentity nestedIdentity;

private long version = -1;
private long seqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
private long primaryTerm = SequenceNumbers.UNASSIGNED_PRIMARY_TERM;
protected long version = -1;
protected long seqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
protected long primaryTerm = SequenceNumbers.UNASSIGNED_PRIMARY_TERM;

private BytesReference source;
@Nullable
protected BytesReference source;

private Map<String, DocumentField> documentFields;
private final Map<String, DocumentField> metaFields;
protected Map<String, DocumentField> documentFields;
protected Map<String, DocumentField> metaFields;

private Map<String, HighlightField> highlightFields = null;
@Nullable
protected Map<String, HighlightField> highlightFields = null;

private SearchSortValues sortValues = SearchSortValues.EMPTY;
protected SearchSortValues sortValues = SearchSortValues.EMPTY;

private Map<String, Float> matchedQueries = new HashMap<>();
protected Map<String, Float> matchedQueries = new HashMap<>();

private Explanation explanation;
@Nullable
protected Explanation explanation;

@Nullable
private SearchShardTarget shard;
protected SearchShardTarget shard;

// These two fields normally get set when setting the shard target, so they hold the same values as the target thus don't get
// serialized over the wire. When parsing hits back from xcontent though, in most of the cases (whenever explanation is disabled)
// we can't rebuild the shard target object so we need to set these manually for users retrieval.
private transient String index;
private transient String clusterAlias;
protected transient String index;
protected transient String clusterAlias;

private Map<String, Object> sourceAsMap;

private Map<String, SearchHits> innerHits;
@Nullable
protected Map<String, SearchHits> innerHits;

public SearchHit(SearchHit hit) {
this.docId = hit.docId;
this.id = hit.id;
this.nestedIdentity = hit.nestedIdentity;
this.version = hit.version;
this.seqNo = hit.seqNo;
this.primaryTerm = hit.primaryTerm;
this.source = hit.source;
this.documentFields = hit.documentFields;
this.metaFields = hit.metaFields;
this.highlightFields = hit.highlightFields;
this.sortValues = hit.sortValues;
this.matchedQueries = hit.matchedQueries;
this.explanation = hit.explanation;
this.shard = hit.shard;
this.index = hit.index;
this.clusterAlias = hit.clusterAlias;
this.innerHits = hit.innerHits;
this.score = hit.score;
this.sourceAsMap = hit.sourceAsMap;
}

// used only in tests
public SearchHit(int docId) {
Expand Down Expand Up @@ -236,7 +264,9 @@ public SearchHit(StreamInput in) throws IOException {
}
}

private static final Text SINGLE_MAPPING_TYPE = new Text(MapperService.SINGLE_MAPPING_NAME);
protected SearchHit() {}

protected static final Text SINGLE_MAPPING_TYPE = new Text(MapperService.SINGLE_MAPPING_NAME);

@Override
public void writeTo(StreamOutput out) throws IOException {
Expand Down Expand Up @@ -993,7 +1023,7 @@ private void buildExplanation(XContentBuilder builder, Explanation explanation)

@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) {
if (!(obj instanceof SearchHit)) {
return false;
}
SearchHit other = (SearchHit) obj;
Expand Down Expand Up @@ -1057,7 +1087,7 @@ public NestedIdentity(String field, int offset, NestedIdentity child) {
this.child = child;
}

NestedIdentity(StreamInput in) throws IOException {
public NestedIdentity(StreamInput in) throws IOException {
field = in.readOptionalText();
offset = in.readInt();
child = in.readOptionalWriteable(NestedIdentity::new);
Expand Down
28 changes: 20 additions & 8 deletions server/src/main/java/org/opensearch/search/SearchHits.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
* @opensearch.api
*/
@PublicApi(since = "1.0.0")
public final class SearchHits implements Writeable, ToXContentFragment, Iterable<SearchHit> {
public class SearchHits implements Writeable, ToXContentFragment, Iterable<SearchHit> {
public static SearchHits empty() {
return empty(true);
}
Expand All @@ -72,15 +72,25 @@ public static SearchHits empty(boolean withTotalHits) {

public static final SearchHit[] EMPTY = new SearchHit[0];

private final SearchHit[] hits;
private final TotalHits totalHits;
private final float maxScore;
protected SearchHit[] hits;
protected float maxScore;
@Nullable
private final SortField[] sortFields;
protected TotalHits totalHits;
@Nullable
private final String collapseField;
protected SortField[] sortFields;
@Nullable
private final Object[] collapseValues;
protected String collapseField;
@Nullable
protected Object[] collapseValues;

public SearchHits(SearchHits sHits) {
this.hits = sHits.hits;
this.totalHits = sHits.totalHits;
this.maxScore = sHits.maxScore;
this.sortFields = sHits.sortFields;
this.collapseField = sHits.collapseField;
this.collapseValues = sHits.collapseValues;
}

public SearchHits(SearchHit[] hits, @Nullable TotalHits totalHits, float maxScore) {
this(hits, totalHits, maxScore, null, null, null);
Expand Down Expand Up @@ -124,6 +134,8 @@ public SearchHits(StreamInput in) throws IOException {
collapseValues = in.readOptionalArray(Lucene::readSortValue, Object[]::new);
}

protected SearchHits() {}

@Override
public void writeTo(StreamOutput out) throws IOException {
final boolean hasTotalHits = totalHits != null;
Expand Down Expand Up @@ -288,7 +300,7 @@ public static SearchHits fromXContent(XContentParser parser) throws IOException

@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) {
if (!(obj instanceof SearchHits)) {
return false;
}
SearchHits other = (SearchHits) obj;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public final class SearchShardTarget implements Writeable, Comparable<SearchShar
// original indices are only needed in the coordinating node throughout the search request execution.
// no need to serialize them as part of SearchShardTarget.
private final transient OriginalIndices originalIndices;

@Nullable
private final String clusterAlias;

public SearchShardTarget(StreamInput in) throws IOException {
Expand All @@ -71,6 +73,13 @@ public SearchShardTarget(StreamInput in) throws IOException {
clusterAlias = in.readOptionalString();
}

public SearchShardTarget(String nodeId, ShardId shardId, String clusterAlias) {
this.nodeId = new Text(nodeId);
this.shardId = shardId;
this.originalIndices = null;
this.clusterAlias = clusterAlias;
}

public SearchShardTarget(String nodeId, ShardId shardId, @Nullable String clusterAlias, OriginalIndices originalIndices) {
this.nodeId = nodeId == null ? null : new Text(nodeId);
this.shardId = shardId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ public class SearchSortValues implements ToXContentFragment, Writeable {
this.rawSortValues = EMPTY_ARRAY;
}

public SearchSortValues(Object[] formattedSortValues, Object[] rawSortValues) {
this.formattedSortValues = formattedSortValues;
this.rawSortValues = rawSortValues;
}

public SearchSortValues(Object[] rawSortValues, DocValueFormat[] sortValueFormats) {
Objects.requireNonNull(rawSortValues);
Objects.requireNonNull(sortValueFormats);
Expand All @@ -89,7 +94,7 @@ public SearchSortValues(Object[] rawSortValues, DocValueFormat[] sortValueFormat
}
}

SearchSortValues(StreamInput in) throws IOException {
public SearchSortValues(StreamInput in) throws IOException {
this.formattedSortValues = in.readArray(Lucene::readSortValue, Object[]::new);
this.rawSortValues = in.readArray(Lucene::readSortValue, Object[]::new);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@
* @opensearch.api
*/
@PublicApi(since = "1.0.0")
public final class FetchSearchResult extends SearchPhaseResult {
public class FetchSearchResult extends SearchPhaseResult {

private SearchHits hits;
protected SearchHits hits;
// client side counter
private transient int counter;
protected transient int counter;

public FetchSearchResult() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

package org.opensearch.search.fetch.subphase.highlight;

import org.opensearch.common.Nullable;
import org.opensearch.common.annotation.PublicApi;
import org.opensearch.core.common.ParsingException;
import org.opensearch.core.common.io.stream.StreamInput;
Expand Down Expand Up @@ -60,6 +61,7 @@ public class HighlightField implements ToXContentFragment, Writeable {

private String name;

@Nullable
private Text[] fragments;

public HighlightField(StreamInput in) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ public TransportSerializationException(StreamInput in) throws IOException {
super(in);
}

public TransportSerializationException(String msg) {
super(msg);
}

public TransportSerializationException(String msg, Throwable cause) {
super(msg, cause);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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.transport.protobuf;

import org.opensearch.core.common.io.stream.StreamInput;
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.search.fetch.FetchSearchResult;
import org.opensearch.proto.search.fetch.FetchSearchResultProtoDef.FetchSearchResultProto;

import java.io.IOException;

/**
* FetchSearchResult which leverages protobuf for transport layer serialization.
* @opensearch.internal
*/
public class FetchSearchResultProtobuf extends FetchSearchResult {
public FetchSearchResultProtobuf(StreamInput in) throws IOException {
fromProtobufStream(in);
}

@Override
public void writeTo(StreamOutput out) throws IOException {
toProtobufStream(out);
}

public void toProtobufStream(StreamOutput out) throws IOException {
toProto().writeTo(out);
}

public void fromProtobufStream(StreamInput in) throws IOException {
FetchSearchResultProto proto = FetchSearchResultProto.parseFrom(in);
fromProto(proto);
}

FetchSearchResultProto toProto() {
FetchSearchResultProto.Builder builder = FetchSearchResultProto.newBuilder()
.setHits(new SearchHitsProtobuf(hits).toProto())
.setCounter(this.counter);
return builder.build();
}

void fromProto(FetchSearchResultProto proto) {
hits = new SearchHitsProtobuf(proto.getHits());
}
}
Loading
Loading