All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datastax.oss.driver.api.core.data.CqlVector Maven / Gradle / Ivy

The newest version!
/*
 * Copyright DataStax, Inc.
 *
 * 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 com.datastax.oss.driver.api.core.data;

import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
import com.datastax.oss.driver.shaded.guava.common.base.Preconditions;
import com.datastax.oss.driver.shaded.guava.common.base.Predicates;
import com.datastax.oss.driver.shaded.guava.common.base.Splitter;
import com.datastax.oss.driver.shaded.guava.common.collect.Iterables;
import com.datastax.oss.driver.shaded.guava.common.collect.Streams;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Representation of a vector as defined in CQL.
 *
 * 

A CQL vector is a fixed-length array of non-null numeric values. These properties don't map * cleanly to an existing class in the standard JDK Collections hierarchy so we provide this value * object instead. Like other value object collections returned by the driver instances of this * class are not immutable; think of these value objects as a representation of a vector stored in * the database as an initial step in some additional computation. * *

While we don't implement any Collection APIs we do implement Iterable. We also attempt to play * nice with the Streams API in order to better facilitate integration with data pipelines. Finally, * where possible we've tried to make the API of this class similar to the equivalent methods on * {@link List}. */ public class CqlVector implements Iterable, Serializable { /** * Create a new CqlVector containing the specified values. * * @param vals the collection of values to wrap. * @return a CqlVector wrapping those values */ public static CqlVector newInstance(V... vals) { // Note that Array.asList() guarantees the return of an array which implements RandomAccess return new CqlVector(Arrays.asList(vals)); } /** * Create a new CqlVector that "wraps" an existing ArrayList. Modifications to the passed * ArrayList will also be reflected in the returned CqlVector. * * @param list the collection of values to wrap. * @return a CqlVector wrapping those values */ public static CqlVector newInstance(List list) { Preconditions.checkArgument(list != null, "Input list should not be null"); return new CqlVector(list); } /** * Create a new CqlVector instance from the specified string representation. Note that this method * is intended to mirror {@link #toString()}; passing this method the output from a toString * call on some CqlVector should return a CqlVector that is equal to the origin instance. * * @param str a String representation of a CqlVector * @param subtypeCodec * @return a new CqlVector built from the String representation */ public static CqlVector from( @NonNull String str, @NonNull TypeCodec subtypeCodec) { Preconditions.checkArgument(str != null, "Cannot create CqlVector from null string"); Preconditions.checkArgument(!str.isEmpty(), "Cannot create CqlVector from empty string"); ArrayList vals = Streams.stream(Splitter.on(", ").split(str.substring(1, str.length() - 1))) .map(subtypeCodec::parse) .collect(Collectors.toCollection(ArrayList::new)); return new CqlVector(vals); } private final List list; private CqlVector(@NonNull List list) { Preconditions.checkArgument( Iterables.all(list, Predicates.notNull()), "CqlVectors cannot contain null values"); this.list = list; } /** * Retrieve the value at the specified index. Modelled after {@link List#get(int)} * * @param idx the index to retrieve * @return the value at the specified index */ public T get(int idx) { return list.get(idx); } /** * Update the value at the specified index. Modelled after {@link List#set(int, Object)} * * @param idx the index to set * @param val the new value for the specified index * @return the old value for the specified index */ public T set(int idx, T val) { return list.set(idx, val); } /** * Return the size of this vector. Modelled after {@link List#size()} * * @return the vector size */ public int size() { return this.list.size(); } /** * Return a CqlVector consisting of the contents of a portion of this vector. Modelled after * {@link List#subList(int, int)} * * @param from the index to start from (inclusive) * @param to the index to end on (exclusive) * @return a new CqlVector wrapping the sublist */ public CqlVector subVector(int from, int to) { return new CqlVector(this.list.subList(from, to)); } /** * Return a boolean indicating whether the vector is empty. Modelled after {@link List#isEmpty()} * * @return true if the list is empty, false otherwise */ public boolean isEmpty() { return this.list.isEmpty(); } /** * Create an {@link Iterator} for this vector * * @return the generated iterator */ @Override public Iterator iterator() { return this.list.iterator(); } /** * Create a {@link Stream} of the values in this vector * * @return the Stream instance */ public Stream stream() { return this.list.stream(); } @Override public boolean equals(Object o) { if (o == this) { return true; } else if (o instanceof CqlVector) { CqlVector that = (CqlVector) o; return this.list.equals(that.list); } else { return false; } } @Override public int hashCode() { return Objects.hash(list); } @Override public String toString() { return Iterables.toString(this.list); } /** * Serialization proxy for CqlVector. Allows serialization regardless of implementation of list * field. * * @param inner type of CqlVector, assume Number is always Serializable. */ private static class SerializationProxy implements Serializable { private static final long serialVersionUID = 1; private transient List list; SerializationProxy(CqlVector vector) { this.list = vector.list; } // Reconstruct CqlVector's list of elements. private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); int size = stream.readInt(); list = new ArrayList<>(size); for (int i = 0; i < size; i++) { list.add((T) stream.readObject()); } } // Return deserialized proxy object as CqlVector. private Object readResolve() throws ObjectStreamException { return new CqlVector(list); } // Write size of CqlVector followed by items in order. private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); stream.writeInt(list.size()); for (T item : list) { stream.writeObject(item); } } } /** @serialData The number of elements in the vector, followed by each element in-order. */ private Object writeReplace() { return new SerializationProxy(this); } private void readObject(@SuppressWarnings("unused") ObjectInputStream stream) throws InvalidObjectException { // Should never be called since we serialized a proxy throw new InvalidObjectException("Proxy required"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy