From ec579df59cf72b1a65d087a23954c4fb659ecac6 Mon Sep 17 00:00:00 2001 From: jinhai Date: Sun, 26 May 2019 15:59:05 +0800 Subject: [PATCH] MS-3 Add SDK interface Former-commit-id: 351fb4356e4318efc85dd7ba9b32873a71faf910 --- cpp/src/sdk/MegaSearch.cpp | 96 +++++++++++ cpp/src/sdk/MegaSearch.h | 339 +++++++++++++++++++++++++++++++++++++ cpp/src/sdk/Status.cpp | 115 +++++++++++++ cpp/src/sdk/Status.h | 325 +++++++++++++++++++++++++++++++++++ 4 files changed, 875 insertions(+) create mode 100644 cpp/src/sdk/MegaSearch.cpp create mode 100644 cpp/src/sdk/MegaSearch.h create mode 100644 cpp/src/sdk/Status.cpp create mode 100644 cpp/src/sdk/Status.h diff --git a/cpp/src/sdk/MegaSearch.cpp b/cpp/src/sdk/MegaSearch.cpp new file mode 100644 index 0000000000..66c7dceb15 --- /dev/null +++ b/cpp/src/sdk/MegaSearch.cpp @@ -0,0 +1,96 @@ +#include "MegaSearch.h" + + +namespace megasearch { +std::shared_ptr +Create() { + return nullptr; +} + +Status +Destroy(std::shared_ptr &connection_ptr) { + return Status::OK(); +} + +/** +Status +Connection::Connect(const ConnectParam ¶m) { + return Status::NotSupported("Connect interface is not supported."); +} + +Status +Connection::Connect(const std::string &uri) { + return Status::NotSupported("Connect interface is not supported."); +} + +Status +Connection::Connected() const { + return Status::NotSupported("Connected interface is not supported."); +} + +Status +Connection::Disconnect() { + return Status::NotSupported("Disconnect interface is not supported."); +} + +std::string +Connection::ClientVersion() const { + return std::string("Current Version"); +} + +Status +Connection::CreateTable(const TableSchema ¶m) { + return Status::NotSupported("Create table interface interface is not supported."); +} + +Status +Connection::CreateTablePartition(const CreateTablePartitionParam ¶m) { + return Status::NotSupported("Create table partition interface is not supported."); +} + +Status +Connection::DeleteTablePartition(const DeleteTablePartitionParam ¶m) { + return Status::NotSupported("Delete table partition interface is not supported."); +} + +Status +Connection::DeleteTable(const std::string &table_name) { + return Status::NotSupported("Create table interface is not supported."); +} + +Status +Connection::AddVector(const std::string &table_name, + const std::vector &record_array, + std::vector &id_array) { + return Status::NotSupported("Add vector array interface is not supported."); +} + +Status +Connection::SearchVector(const std::string &table_name, + const std::vector &query_record_array, + std::vector &topk_query_result_array, + int64_t topk) { + return Status::NotSupported("Query vector array interface is not supported."); +} + +Status +Connection::DescribeTable(const std::string &table_name, TableSchema &table_schema) { + return Status::NotSupported("Show table interface is not supported."); +} + +Status +Connection::ShowTables(std::vector &table_array) { + return Status::NotSupported("List table array interface is not supported."); +} + +std::string +Connection::ServerVersion() const { + return std::string("Server version."); +} + +std::string +Connection::ServerStatus() const { + return std::string("Server status"); +} +**/ +} \ No newline at end of file diff --git a/cpp/src/sdk/MegaSearch.h b/cpp/src/sdk/MegaSearch.h new file mode 100644 index 0000000000..d006927614 --- /dev/null +++ b/cpp/src/sdk/MegaSearch.h @@ -0,0 +1,339 @@ +#pragma once + +#include "Status.h" + +#include +#include +#include +#include + +/** \brief MegaSearch SDK namespace + */ +namespace megasearch { + + +/** + * @brief Column Type + */ +enum class ColumnType { + invalid, + int8, + int16, + int32, + int64, + float32, + float64, + date, + vector +}; + +/** + * @brief Index Type + */ +enum class IndexType { + raw, + ivfflat +}; + +/** + * @brief Connect API parameter + */ +struct ConnectParam { + std::string ip_address; ///< Server IP address + std::string port; ///< Server PORT +}; + +/** + * @brief Table column description + */ +struct Column { + ColumnType type = ColumnType::invalid; ///< Column Type: enum ColumnType + std::string name; ///< Column name +}; + +/** + * @brief Table vector column description + */ +struct VectorColumn : public Column { + VectorColumn() { type = ColumnType::vector; } + int64_t dimension = 0; ///< Vector dimension + IndexType index_type = IndexType::raw; ///< Index type + bool store_raw_vector = false; ///< Is vector self stored in the table +}; + +/** + * @brief Table Schema + */ +struct TableSchema { + std::string table_name; ///< Table name + std::vector vector_column_array; ///< Vector column description + std::vector attribute_column_array; ///< Columns description + std::vector partition_column_name_array; ///< Partition column name +}; + +/** + * @brief Range information + */ +struct Range { + std::string start_value; ///< Range start + std::string end_value; ///< Range stop +}; + +/** + * @brief Create table partition parameters + */ +struct CreateTablePartitionParam { + std::string table_name; ///< Table name, vector/float32/float64 type column is not allowed for partition + std::string partition_name; ///< Partition name, created partition name + std::map range_map; ///< Column name to PartitionRange map +}; + + +/** + * @brief Delete table partition parameters + */ +struct DeleteTablePartitionParam { + std::string table_name; ///< Table name + std::vector partition_name_array; ///< Partition name array +}; + +/** + * @brief Record inserted + */ +struct RowRecord { + std::map> vector_map; ///< Vector columns + std::map attribute_map; ///< Other attribute columns +}; + +/** + * @brief Query record + */ +struct QueryRecord { + std::map> vector_map; ///< Query vectors + std::vector selected_column_array; ///< Output column array + std::map> partition_filter_column_map; ///< Range used to select partitions +}; + +/** + * @brief Query result + */ +struct QueryResult { + int64_t id; ///< Output result + double score; ///< Vector similarity score: 0 ~ 100 + std::map column_map; ///< Other column +}; + +/** + * @brief TopK query result + */ +struct TopKQueryResult { + std::vector query_result_arrays; ///< TopK query result +}; + +/** + * @brief SDK main class + */ +class Connection { + public: + + /** + * @brief CreateConnection + * + * Create a connection instance and return it's shared pointer + * + * @return Connection instance pointer + */ + + static std::shared_ptr + Create(); + + /** + * @brief DestroyConnection + * + * Destroy the connection instance + * + * @param connection, the shared pointer to the instance to be destroyed + * + * @return if destroy is successful + */ + + static Status + Destroy(std::shared_ptr connection_ptr); + + /** + * @brief Connect + * + * Connect function should be called before any operations + * Server will be connected after Connect return OK + * + * @param param, use to provide server information + * + * @return Indicate if connect is successful + */ + + virtual Status Connect(const ConnectParam ¶m) = 0; + + /** + * @brief Connect + * + * Connect function should be called before any operations + * Server will be connected after Connect return OK + * + * @param uri, use to provide server information, example: megasearch://ipaddress:port + * + * @return Indicate if connect is successful + */ + virtual Status Connect(const std::string &uri) = 0; + + /** + * @brief connected + * + * Connection status. + * + * @return Indicate if connection status + */ + virtual Status Connected() const = 0; + + /** + * @brief Disconnect + * + * Server will be disconnected after Disconnect return OK + * + * @return Indicate if disconnect is successful + */ + virtual Status Disconnect() = 0; + + + /** + * @brief Create table method + * + * This method is used to create table + * + * @param param, use to provide table information to be created. + * + * @return Indicate if table is created successfully + */ + virtual Status CreateTable(const TableSchema ¶m) = 0; + + + /** + * @brief Delete table method + * + * This method is used to delete table. + * + * @param table_name, table name is going to be deleted. + * + * @return Indicate if table is delete successfully. + */ + virtual Status DeleteTable(const std::string &table_name) = 0; + + + /** + * @brief Create table partition + * + * This method is used to create table partition. + * + * @param param, use to provide partition information to be created. + * + * @return Indicate if table partition is created successfully. + */ + virtual Status CreateTablePartition(const CreateTablePartitionParam ¶m) = 0; + + + /** + * @brief Delete table partition + * + * This method is used to delete table partition. + * + * @param param, use to provide partition information to be deleted. + * + * @return Indicate if table partition is delete successfully. + */ + virtual Status DeleteTablePartition(const DeleteTablePartitionParam ¶m) = 0; + + + /** + * @brief Add vector to table + * + * This method is used to add vector array to table. + * + * @param table_name, table_name is inserted. + * @param record_array, vector array is inserted. + * @param id_array, after inserted every vector is given a id. + * + * @return Indicate if vector array are inserted successfully + */ + virtual Status AddVector(const std::string &table_name, + const std::vector &record_array, + std::vector &id_array) = 0; + + + /** + * @brief Search vector + * + * This method is used to query vector in table. + * + * @param table_name, table_name is queried. + * @param query_record_array, all vector are going to be queried. + * @param topk_query_result_array, result array. + * @param topk, how many similarity vectors will be searched. + * + * @return Indicate if query is successful. + */ + virtual Status SearchVector(const std::string &table_name, + const std::vector &query_record_array, + std::vector &topk_query_result_array, + int64_t topk) = 0; + + /** + * @brief Show table description + * + * This method is used to show table information. + * + * @param table_name, which table is show. + * @param table_schema, table_schema is given when operation is successful. + * + * @return Indicate if this operation is successful. + */ + virtual Status DescribeTable(const std::string &table_name, TableSchema &table_schema) = 0; + + /** + * @brief Show all tables in database + * + * This method is used to list all tables. + * + * @param table_array, all tables are push into the array. + * + * @return Indicate if this operation is successful. + */ + virtual Status ShowTables(std::vector &table_array) = 0; + + /** + * @brief Give the client version + * + * This method is used to give the client version. + * + * @return Client version. + */ + virtual std::string ClientVersion() const = 0; + + /** + * @brief Give the server version + * + * This method is used to give the server version. + * + * @return Server version. + */ + virtual std::string ServerVersion() const = 0; + + /** + * @brief Give the server status + * + * This method is used to give the server status. + * + * @return Server status. + */ + virtual std::string ServerStatus() const = 0; +}; + +} \ No newline at end of file diff --git a/cpp/src/sdk/Status.cpp b/cpp/src/sdk/Status.cpp new file mode 100644 index 0000000000..8e82affd2a --- /dev/null +++ b/cpp/src/sdk/Status.cpp @@ -0,0 +1,115 @@ +#include "Status.h" + + +namespace megasearch { + +Status::~Status() noexcept { + if (state_ != nullptr) { + delete state_; + state_ = nullptr; + } +} + +static inline std::ostream &operator<<(std::ostream &os, const Status &x) { + os << x.ToString(); + return os; +} + +void Status::MoveFrom(Status &s) { + delete state_; + state_ = s.state_; + s.state_ = nullptr; +} + +Status::Status(const Status &s) + : state_((s.state_ == nullptr) ? nullptr : new State(*s.state_)) {} + +Status &Status::operator=(const Status &s) { + if (state_ != s.state_) { + CopyFrom(s); + } + return *this; +} + +Status &Status::operator=(Status &&s) noexcept { + MoveFrom(s); + return *this; +} + +Status Status::operator&(const Status &status) const noexcept { + if (ok()) { + return status; + } else { + return *this; + } +} + +Status Status::operator&(Status &&s) const noexcept { + if (ok()) { + return std::move(s); + } else { + return *this; + } +} + +Status &Status::operator&=(const Status &s) noexcept { + if (ok() && !s.ok()) { + CopyFrom(s); + } + return *this; +} + +Status &Status::operator&=(Status &&s) noexcept { + if (ok() && !s.ok()) { + MoveFrom(s); + } + return *this; +} + +Status::Status(StatusCode code, const std::string &message) { + state_ = new State; + state_->code = code; + state_->message = message; +} + +void Status::CopyFrom(const Status &status) { + delete state_; + if (status.state_ == nullptr) { + state_ = nullptr; + } else { + state_ = new State(*status.state_); + } +} + +std::string Status::CodeAsString() const { + if (state_ == nullptr) { + return "OK"; + } + + const char *type = nullptr; + switch (code()) { + case StatusCode::OK: type = "OK"; + break; + case StatusCode::Invalid: type = "Invalid"; + break; + case StatusCode::UnknownError: type = "Unknown error"; + break; + case StatusCode::NotSupported: type = "Not Supported"; + break; + default: type = "Unknown"; + break; + } + return std::string(type); +} + +std::string Status::ToString() const { + std::string result(CodeAsString()); + if (state_ == nullptr) { + return result; + } + result += ": "; + result += state_->message; + return result; +} + +} \ No newline at end of file diff --git a/cpp/src/sdk/Status.h b/cpp/src/sdk/Status.h new file mode 100644 index 0000000000..25f9ac8c1d --- /dev/null +++ b/cpp/src/sdk/Status.h @@ -0,0 +1,325 @@ +#pragma once + +#include +#include + +/** \brief MegaSearch SDK namespace + */ +namespace megasearch { + +/** + * @brief Status Code for SDK interface return + */ +enum class StatusCode { + OK = 0, + Invalid = 1, + UnknownError = 2, + NotSupported = 3 +}; + +/** + * @brief Status for SDK interface return + */ +class Status { + public: + /** + * @brief Status + * + * Default constructor. + * + */ + Status() = default; + + /** + * @brief Status + * + * Destructor. + * + */ + ~Status() noexcept; + + /** + * @brief Status + * + * Constructor + * + * @param code, status code. + * @param message, status message. + * + */ + Status(StatusCode code, const std::string &message); + + /** + * @brief Status + * + * Copy constructor + * + * @param status, status to be copied. + * + */ + inline Status(const Status &status); + + /** + * @brief Status + * + * Assignment operator + * + * @param status, status to be copied. + * @return, the status is assigned. + * + */ + inline Status &operator=(const Status &s); + + /** + * @brief Status + * + * Move constructor + * + * @param status, status to be moved. + * + */ + inline Status(Status &&s) noexcept : state_(s.state_) {}; + + /** + * @brief Status + * + * Move assignment operator + * + * @param status, status to be moved. + * @return, the status is moved. + * + */ + inline Status &operator=(Status &&s) noexcept; + + /** + * @brief Status + * + * AND operator + * + * @param status, status to be AND. + * @return, the status after AND operation. + * + */ + inline Status operator&(const Status &s) const noexcept; + + /** + * @brief Status + * + * AND operator + * + * @param status, status to be AND. + * @return, the status after AND operation. + * + */ + inline Status operator&(Status &&s) const noexcept; + + /** + * @brief Status + * + * AND operator + * + * @param status, status to be AND. + * @return, the status after AND operation. + * + */ + inline Status &operator&=(const Status &s) noexcept; + + /** + * @brief Status + * + * AND operator + * + * @param status, status to be AND. + * @return, the status after AND operation. + * + */ + inline Status &operator&=(Status &&s) noexcept; + + /** + * @brief OK + * + * static OK status constructor + * + * @return, the status with OK. + * + */ + static Status OK() { return Status(); } + + /** + * @brief OK + * + * static OK status constructor with a specific message + * + * @param, serveral specific messages + * @return, the status with OK. + * + */ + template + static Status OK(Args &&... args) { + return Status(StatusCode::OK, MessageBuilder(std::forward(args)...)); + } + + /** + * @brief Invalid + * + * static Invalid status constructor with a specific message + * + * @param, serveral specific messages + * @return, the status with Invalid. + * + */ + template + static Status Invalid(Args &&... args) { + return Status(StatusCode::Invalid, + MessageBuilder(std::forward(args)...)); + } + + /** + * @brief Unknown Error + * + * static unknown error status constructor with a specific message + * + * @param, serveral specific messages + * @return, the status with unknown error. + * + */ + template + static Status UnknownError(Args &&... args) { + return Status(StatusCode::UnknownError, MessageBuilder(std::forward(args)...)); + } + + /** + * @brief not supported Error + * + * static not supported status constructor with a specific message + * + * @param, serveral specific messages + * @return, the status with not supported error. + * + */ + template + static Status NotSupported(Args &&... args) { + return Status(StatusCode::NotSupported, MessageBuilder(std::forward(args)...)); + } + + /** + * @brief ok + * + * Return true iff the status indicates success. + * + * @return, if the status indicates success. + * + */ + bool ok() const { return (state_ == nullptr); } + + /** + * @brief IsInvalid + * + * Return true iff the status indicates invalid. + * + * @return, if the status indicates invalid. + * + */ + bool IsInvalid() const { return code() == StatusCode::Invalid; } + + /** + * @brief IsUnknownError + * + * Return true iff the status indicates unknown error. + * + * @return, if the status indicates unknown error. + * + */ + bool IsUnknownError() const { return code() == StatusCode::UnknownError; } + + /** + * @brief IsNotSupported + * + * Return true iff the status indicates not supported. + * + * @return, if the status indicates not supported. + * + */ + bool IsNotSupported() const { return code() == StatusCode::NotSupported; } + + /** + * @brief ToString + * + * Return error message string. + * + * @return, error message string. + * + */ + std::string ToString() const; + + /** + * @brief CodeAsString + * + * Return a string representation of the status code. + * + * @return, a string representation of the status code. + * + */ + std::string CodeAsString() const; + + /** + * @brief code + * + * Return the StatusCode value attached to this status. + * + * @return, the status code value attached to this status. + * + */ + StatusCode code() const { return ok() ? StatusCode::OK : state_->code; } + + /** + * @brief message + * + * Return the specific error message attached to this status. + * + * @return, the specific error message attached to this status. + * + */ + std::string message() const { return ok() ? "" : state_->message; } + + private: + struct State { + StatusCode code; + std::string message; + }; + + // OK status has a `nullptr` state_. Otherwise, `state_` points to + // a `State` structure containing the error code and message. + State *state_ = nullptr; + + void DeleteState() { + delete state_; + state_ = nullptr; + } + + void CopyFrom(const Status &s); + + inline void MoveFrom(Status &s); + + template + static void MessageBuilderRecursive(std::stringstream &stream, Head &&head) { + stream << head; + } + + template + static void MessageBuilderRecursive(std::stringstream &stream, Head &&head, Tail &&... tail) { + MessageBuilderRecursive(stream, std::forward(head)); + MessageBuilderRecursive(stream, std::forward(tail)...); + } + + template + static std::string MessageBuilder(Args &&... args) { + std::stringstream stream; + + MessageBuilderRecursive(stream, std::forward(args)...); + + return stream.str(); + } +}; + +} \ No newline at end of file