1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.appsearch.app;
18 
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 
22 import androidx.annotation.NonNull;
23 import androidx.annotation.Nullable;
24 import androidx.annotation.RequiresFeature;
25 import androidx.annotation.RestrictTo;
26 import androidx.appsearch.flags.FlaggedApi;
27 import androidx.appsearch.flags.Flags;
28 import androidx.appsearch.safeparcel.AbstractSafeParcelable;
29 import androidx.appsearch.safeparcel.SafeParcelable;
30 import androidx.appsearch.safeparcel.stub.StubCreators.EmbeddingVectorCreator;
31 import androidx.core.util.Preconditions;
32 
33 import java.util.Arrays;
34 import java.util.Objects;
35 
36 /**
37  * Embeddings are vector representations of data, such as text, images, and audio, which can be
38  * generated by machine learning models and used for semantic search. This class represents an
39  * embedding vector, which wraps a float array for the values of the embedding vector and a model
40  * signature that can be any string to distinguish between embedding vectors generated by
41  * different models.
42  *
43  * <p>For more details on how embedding search works, check {@link AppSearchSession#search} and
44  * {@link SearchSpec.Builder#setRankingStrategy(String)}.
45  *
46  * @see SearchSpec.Builder#addEmbeddingParameters
47  * @see GenericDocument.Builder#setPropertyEmbedding
48  */
49 @RequiresFeature(
50         enforcement = "androidx.appsearch.app.Features#isFeatureSupported",
51         name = Features.SCHEMA_EMBEDDING_PROPERTY_CONFIG)
52 @FlaggedApi(Flags.FLAG_ENABLE_SCHEMA_EMBEDDING_PROPERTY_CONFIG)
53 @SafeParcelable.Class(creator = "EmbeddingVectorCreator")
54 // TODO(b/384721898): Switch to JSpecify annotations
55 @SuppressWarnings({"HiddenSuperclass", "JSpecifyNullness"})
56 public final class EmbeddingVector extends AbstractSafeParcelable {
57     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
58     public static final @NonNull Parcelable.Creator<EmbeddingVector> CREATOR =
59             new EmbeddingVectorCreator();
60     @Field(id = 1, getter = "getValues")
61     private final @NonNull float[] mValues;
62     @Field(id = 2, getter = "getModelSignature")
63     private final @NonNull String mModelSignature;
64     private @Nullable Integer mHashCode;
65 
66     /**
67      * Creates a new {@link EmbeddingVector}.
68      *
69      * @throws IllegalArgumentException if {@code values} is empty.
70      */
71     @Constructor
EmbeddingVector( @aramid = 1) @onNull float[] values, @Param(id = 2) @NonNull String modelSignature)72     public EmbeddingVector(
73             @Param(id = 1) @NonNull float[] values,
74             @Param(id = 2) @NonNull String modelSignature) {
75         mValues = Preconditions.checkNotNull(values);
76         if (mValues.length == 0) {
77             throw new IllegalArgumentException("Embedding values cannot be empty.");
78         }
79         mModelSignature = Preconditions.checkNotNull(modelSignature);
80     }
81 
82     /**
83      * Returns the values of this embedding vector.
84      */
getValues()85     public @NonNull float[] getValues() {
86         return mValues;
87     }
88 
89     /**
90      * Returns the model signature of this embedding vector, which is an arbitrary string to
91      * distinguish between embedding vectors generated by different models.
92      */
getModelSignature()93     public @NonNull String getModelSignature() {
94         return mModelSignature;
95     }
96 
97     @Override
equals(Object o)98     public boolean equals(Object o) {
99         if (this == o) return true;
100         if (o == null) return false;
101         if (!(o instanceof EmbeddingVector)) return false;
102         EmbeddingVector that = (EmbeddingVector) o;
103         return Arrays.equals(mValues, that.mValues)
104                 && mModelSignature.equals(that.mModelSignature);
105     }
106 
107     @Override
hashCode()108     public int hashCode() {
109         if (mHashCode == null) {
110             mHashCode = Objects.hash(Arrays.hashCode(mValues), mModelSignature);
111         }
112         return mHashCode;
113     }
114 
115     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
116     @Override
writeToParcel(@onNull Parcel dest, int flags)117     public void writeToParcel(@NonNull Parcel dest, int flags) {
118         EmbeddingVectorCreator.writeToParcel(this, dest, flags);
119     }
120 }
121