SDK 手册
- 1: Python SDK
 - 2: C++ SDK
 - 3: Java SDK
 - 4: Golang SDK
 
1 - Python SDK
目前只支持python 3.6及以上的版本。
1. 创建客户端
可以创建同步客户端或者异步客户端。
- 同步客户端
 
from pyproximabe import *
client = Client('127.0.0.1', 16000)
Proxima BE服务支持 GRPC 和 HTTP 两种协议,监听在不同的端口上。同步客户端同时支持这两种协议,默认使用GRPC协议。如果有需求,可以用下面的方式来指定协议。
client = Client('127.0.0.1', 16001, 'http')
- 异步客户端
 
from pyproximabe import *
client = AsyncClient(HOST, GRPC_PORT)
异步客户端基于asyncio实现,除了需要await结果外,和同步客户端的使用方式完全一致。 异步客户端只支持GRPC协议。
同步或异步客户端支持的参数如下
def __init__(self, host, port=16000, handler='grpc', timeout=10):
| 参数 | 说明 | 
|---|---|
| host | 服务器地址,str类型 | 
| port | 服务器端口,int类型 | 
| handler | 协议类型,str类型,一般不需要指定。 同步客户端支持grpc/http,异步客户端只支持grpc。  | 
| timeout | 超时时间,单位秒,float类型,默认为10。指定为None则不超时。 | 
使用完毕后,可以调用close()关闭客户端,其参数为空,返回值为None。
client.close()
2. 集合管理
2.1. 集合创建
创建直写集合
collection_name = 'iris'
index_column = IndexColumnParam('length', 4, IndexType.PROXIMA_GRAPH_INDEX)
collection_config = CollectionConfig(collection_name, [index_column], ['iris_type'])
status = client.create_collection(collection_config)
if not status.ok():
    # error handling
    logging.error('create collection failed, status=%s', status)
首先,创建一个或多个索引列
index_column = IndexColumnParam('length', 4, IndexType.PROXIMA_GRAPH_INDEX)
参数如下
def __init__(self,
             name,
             dimension,
             index_type=IndexType.PROXIMA_GRAPH_INDEX,
             data_type=DataType.VECTOR_FP32,
             extra_params=None):
| 参数 | 说明 | 
|---|---|
| name | 索引列名称,str类型。 | 
| dimension | 向量维度,int类型。 | 
| index_type | 索引类型,IndexType 类型,默认为PROXIMA_GRAPH_INDEX。 | 
| data_type | 数据类型,DataType 类型,默认为VECTOR_FP32。 | 
| extra_params | 扩展参数,dict类型,默认为空。 | 
然后,创建CollectionConfig。
collection_config = CollectionConfig(collection_name, [index_column], ['iris_type'])
(python_collection_config)= 参数如下
def __init__(self,
                collection_name,
                index_column_params,
                forward_column_names=None,
                repository_config=None,
                max_docs_per_segment=0):
| 参数 | 说明 | 
|---|---|
| collection_name | 集合名称,str类型。 | 
| index_column_params | 索引列列表,List[IndexColumnParam]类型。 | 
| forward_column_names | 正排列列表,List[str]类型。默认为空。 | 
| repository_config | 仓库配置,DatabaseRepository类型。默认为None。 | 
| max_docs_per_segment | 每个segment的最大文档数,long类型。默认为0,文档数不限。 | 
最后,调用client接口。
status = client.create_collection(collection_config)
if not status.ok():
    # error handling
    logging.error('create collection failed, status=%s', status)
create_collection()接收CollectionConfig参数,返回ProximaBeStatus。
def create_collection(self, collection_config):
创建数据库旁路集合
MYSQL_PORT = 3306
MYSQL_HOST = HOST
mysql_table_name = 'iris_table'
mysql_database_name = 'test_db'
mysql_user='root'
mysql_password='root'
index_column = IndexColumnParam('length', 4, IndexType.PROXIMA_GRAPH_INDEX)
database_repository = DatabaseRepository('test_repository',
                                         f'mysql://{MYSQL_HOST}:{MYSQL_PORT}/{mysql_database_name}',
                                         mysql_table_name, mysql_user, mysql_password)
collection_config = CollectionConfig(collection_name, [index_column], ['iris_type'], database_repository)
status = client.create_collection(collection_config)
除了需要创建DatabaseRepository外,其他参数和直写集合完全相同。目前只支持mysql。
database_repository = DatabaseRepository('test_repository',
                                         f'mysql://{MYSQL_HOST}:{MYSQL_PORT}/{mysql_database_name}',
                                         mysql_table_name, mysql_user, mysql_password)
参数列表如下
def __init__(self, repository_name, connection_uri, table_name, user, password):
| 参数 | 说明 | 
|---|---|
| repository_name | 仓库名称,str类型。 | 
| connection_uri | 数据库连接串,str类型,如"mysql://localhost/database",不包含用户名和密码。 | 
| table_name | 表名,str类型。 | 
| user | 用户名,str类型。 | 
| password | 数据库密码,str类型。 | 
2.2. 描述集合
status, collection_info = client.describe_collection(collection_name)
if not status.ok():
    pass  # error handling
print(collection_info)
describe_collection()接收str类型的collection_name
def describe_collection(self, collection_name):
返回值有两个
2.3. 获取集合统计信息
status, collection_stats = client.stats_collection(collection_name)
if not status.ok():
    pass  # error handling
print(collection_stats)
stats_collection()接收str类型的collection_name
def stats_collection(self, collection_name):
返回值有两个
2.4. 删除集合
status = client.drop_collection(collection_name)
drop_collection()接收str类型的collection_name,返回ProximaBeStatus。
def drop_collection(self, collection_name):
2.5. 获取集合列表
status, collections_data = client.list_collections()
list_collections()参数列表如下
def list_collections(self, repository_name=None):
| 参数 | 说明 | 
|---|---|
| repository_name | 仓库名称,str类型,默认为空。参数为空时,返回所有的集合列表,否则返回指定仓库下的集合列表。 | 
| 返回值有两个 | 
3. 文档管理
3.1. 通用接口
import struct
row_meta = WriteRequest.RowMeta([WriteRequest.IndexColumnMeta('length', 'VECTOR_FP32', 4)],
                                ['iris_type'],
                                [DataType.STRING])
rows = [
    WriteRequest.Row(100001,
                     WriteRequest.OperationType.INSERT,
                     [[5.9,3.0,5.1,1.8]],
                     ['Iris-virginica']),
    WriteRequest.Row(100002,
                     WriteRequest.OperationType.INSERT,
                     ['[5.9,3.0,5.1,1.8]'],
                     ['Iris-virginica']),
    WriteRequest.Row(10002,
                     WriteRequest.OperationType.UPDATE,
                     [struct.pack('<4f', 5.9, 3.0, 5.1, 1.8)],
                     ['Iris-virginica']),
    WriteRequest.Row(10003, WriteRequest.OperationType.DELETE),
]
write_request = WriteRequest(collection_name, rows, row_meta)
status = client.write(write_request)
首先,创建WriteRequest.RowMeta,描述插入行的数据类型等信息。
row_meta = WriteRequest.RowMeta([WriteRequest.IndexColumnMeta('length', 'VECTOR_FP32', 4)],
                                ['iris_type'],
                                [DataType.STRING])
WriteRequest.IndexColumnMeta的参数如下
def __init__(self, name, data_type, dimension):
| 参数 | 说明 | 
|---|---|
| name | 索引列名称,str类型。 | 
| data_type | 数据类型,DataType 类型。 | 
| dimension | 向量维度,int类型。 | 
WriteRequest.RowMeta的参数如下 | 
def __init__(self,
             index_column_metas,
             forward_column_names=None,
             forward_column_types=None):
| 参数 | 说明 | 
|---|---|
| index_column_metas | 索引列列表,List[WriteRequest.IndexColumnMeta]类型。 | 
| forward_column_names | 正排列名称列表,List[str]。默认为空。 | 
| forward_column_types | 正排列类型列表,List[DataType]。默认为空。 | 
然后创建WriteRequest.Row。
    WriteRequest.Row(100001,
                     WriteRequest.OperationType.INSERT,
                     [[5.9,3.0,5.1,1.8]],
                     ['Iris-virginica']),
WriteRequest.Row的参数如下
 def __init__(self,
              primary_key,
              operation_type,
              index_column_values=None,
              forward_column_values=None,
              lsn_context=None):
| 参数 | 说明 | 
|---|---|
| primary_key | 主键,long类型。 | 
| operation_type | 操作类型, WriteRequest.OperationType 类型。 | 
| index_column_values | 索引列的值列表,list类型,operation_type为删除时不需要指定。支持三种类型
  | 
| forward_column_values | 正排列的值列表,list类型。 | 
| lsn_context | 日志序列号上下文,LsnContext类型,默认为空。一般不需要设置。 | 
然后创建WriteRequest | 
write_request = WriteRequest(collection_name, rows, row_meta)
WriteRequest参数如下
def __init__(self,
             collection_name,
             rows,
             row_meta=None,
             request_id=None,
             magic_number=None):
| 参数 | 说明 | 
|---|---|
| collection_name | 集合名称,str类型。 | 
| rows | 文档列表,List[WriteRequest.Row]类型。 | 
| row_meta | 文档元数据,WriteRequest.RowMeta类型。如果所有的operation_type都为DELETE,不需要指定。 | 
| request_id | 请求id,str类型,默认为空。一般不需要设置。 | 
| magic_number | 服务端魔数,long类型,默认为0。一般不需要设置。 | 
最后调用client接口。
status = client.write(write_request)
write()接收WriteRequest参数,返回ProximaBeStatus。
def write(self, write_request):
3.2. 删除接口
status = client.delete_document_by_keys(collection_name, [10001, 10002])
在只需要删除时,python sdk提供了简化接口,只需要指定集合名称和主键列表。 参数如下
def delete_document_by_keys(self, collection_name, primary_keys):
| 参数 | 说明 | 
|---|---|
| collection_name | 集合名称,str类型。 | 
| primary_keys | 主键列表,List[long]类型。 | 
delete_document_by_keys()返回值为ProximaBeStatus。 | 
4. 文档查询
4.1. 向量查询
status, knn_res = client.query(collection_name,
                               'length',
                               [[5.1, 3.5, 1.4, 0.2],
                                         [5.5, 2.3, 4.0, 1.3]],
                               'VECTOR_FP32',
                               topk=2)
for i, result in enumerate(knn_res.results):
    print(f'Query: {i}')
    for doc in result:
        forward_values = ','.join(
            f'{k}={v}' for k, v in doc.forward_column_values.items())
        print(
            f'    primary_key={doc.primary_key}, score={doc.score}, forward_column_values=[{forward_values}]'
        )
query()的参数如下
def query(self,
          collection_name,
          column_name,
          features,
          data_type=None,
          dimension=None,
          batch_count=None,
          topk=100,
          is_linear=False,
          radius=None,
          extra_params=None):
| 参数 | 说明 | 
|---|---|
| collection_name | 集合名称,str类型。 | 
| column_name | 索引列名称,str类型。 | 
| features | 特征,支持三种类型
  | 
| data_type | 数据类型,DataType 类型。默认为空。
  | 
| dimension | 向量维度,int类型。默认为空。
  | 
| batch_count | batch大小,int类型。默认为空。
  | 
| topk | 单条查询向量返回的结果数,int类型。默认为100。 | 
| is_linear | 是否做线性查找,bool类型。默认为False,基于索引做查找。 | 
| radius | 搜索半径,只返回以搜索向量为球心的球体内的向量,float类型。默认为0.0,搜索半径不限。 | 
| extra_params | 扩展参数,dict类型。 | 
| 返回值有两个 | 
4.2. 主键查询
status, res = client.get_document_by_key(collection_name, primary_key=100001)
get_document_by_key()的参数如下
def get_document_by_key(self, collection_name, primary_key):
| 参数 | 说明 | 
|---|---|
| collection_name | 集合名称,str类型。 | 
| primary_key | 主键,long类型。 | 
| 返回值有两个 | 
- ProximaBeStatus。主键不存在时,status.ok() == True.
 - Document。主键不存在时,返回None。
 
5. 错误处理
错误处理
python sdk接口一般会返回ProximaBeStatus类型,其包含两个属性
| 属性 | 说明 | 
|---|---|
| code | 错误码,int类型。 | 
| reason | 错误详情,str类型。 | 
可以通过ok()接口来判断是否成功。
def ok(self):
    return self.code == 0
:class: warning
请求服务端成功时才会返回ProximaBeStatus,如果客户端参数检查失败或者网络有问题,会抛出ProximaSeException异常。
class ProximaSeException(Exception):
    pass
6. 类型定义
IndexType
class IndexType(IntEnum):
    UNDEFINED = 0
    PROXIMA_GRAPH_INDEX = 1
DataType
class DataType(IntEnum):
    UNDEFINED = 0
    BINARY = 1
    STRING = 2
    BOOL = 3
    INT32 = 4
    INT64 = 5
    UINT32 = 6
    UINT64 = 7
    FLOAT = 8
    DOUBLE = 9
    VECTOR_BINARY32 = 20
    VECTOR_BINARY64 = 21
    VECTOR_FP16 = 22
    VECTOR_FP32 = 23
    VECTOR_FP64 = 24
    VECTOR_INT4 = 25
    VECTOR_INT8 = 26
    VECTOR_INT16 = 27
WriteRequest.OperationType
class OperationType(IntEnum):
    INSERT = 0
    UPDATE = 1
    DELETE = 2
Document
Document 包含以下属性
| 属性 | 说明 | 
|---|---|
| primary_key | 主键,long类型。 | 
| score | 分值,即距离查询向量的距离,float类型。 | 
| forward_column_values | 正排名称到值的映射,dict类型。 | 
QueryResponse
QueryResponse包含以下属性
| 属性 | 说明 | 
|---|---|
| results | 结果列表,List[List[Document]]类型。第一重list表示多个查询向量的结果,第二重list表示每个向量的Document列表 | 
| debug_info | 服务端调试信息,str类型。 | 
| latency_us | 服务端统计的耗时,单位为微秒。 | 
CollectionInfo
CollectionInfo包含以下属性
| 属性 | 说明 | 
|---|---|
| collection_config | 集合配置, CollectionConfig类型。 | 
| status | 集合状态,CollectionInfo.Status 类型。 | 
| uuid | 集合唯一标识,str类型。 | 
| latest_lsn_context | 最新日志序列号上下文, LsnContext 类型。 | 
| magic_number | 服务端魔数,long类型。 | 
{ref}CollectionConfig定义见这里<python_collection_config>
CollectionInfo.Status定义
class Status(IntEnum):
    """Collection Status"""
    INITIALIZED = 0
    SERVING = 1
    DROPPED = 2
CollectionStats
CollectionStats包含以下属性
| 属性 | 说明 | 
|---|---|
| collection_name | 集合名称,str类型。 | 
| collection_path | 集合路径,str类型。 | 
| total_doc_count | 文档总数,long类型。 | 
| total_segment_count | 分段总个数,long类型。 | 
| total_index_file_count | 索引文件总个数,long类型。 | 
| total_index_file_size | 索引文件总大小,long类型。 | 
| segment_stats | 分段统计信息,List[CollectionStats.SegmentStats]类型。 | 
CollectionStats.SegmentStats包含以下属性
| 属性 | 说明 | 
|---|---|
| segment_id | 段id,int类型。 | 
| state | 段状态,CollectionStats.SegmentState类型。 | 
| doc_count | 文档数,long类型。 | 
| index_file_count | 索引文件个数,long类型。 | 
| index_file_size | 索引文件大小,long类型。 | 
| min_doc_id | 当前分段的最小文档id,long类型。 | 
| max_doc_id | 当前分段的最大文档id,long类型。 | 
| min_primary_key | 当前分段的最小主键,long类型。 | 
| max_primary_key | 当前分段的最大主键,long类型。 | 
| min_timestamp | 当前分段的最小时间戳,long类型。 | 
| max_timestamp | 当前分段的最大时间戳,long类型。 | 
| min_lsn | 当前分段的最小日志序列号,long类型。 | 
| max_lsn | 当前分段的最大日志序列号,long类型。 | 
| segment_path | 段文件路径,str类型。 | 
CollectionStats.SegmentState定义如下
class SegmentState(IntEnum):
    CREATED = 0
    WRITING = 1
    DUMPING = 2
    COMPACTING = 3
    PERSIST = 4
LsnContext
LsnContext 包含以下属性
| 属性 | 说明 | 
|---|---|
| lsn | 序列号,long类型。 | 
| context | 上下文,str类型。 | 
7. 其他示例
8. Python API Reference
2 - C++ SDK
ProximaBE的C++ SDK主要是针对用户上游C/C++模块的集成,其具备高吞吐和低负载的特点,功能上主要是包含集合管理、文档读写等能力,可以节省用户的编码成本。
这篇文章中,我们将介绍C++ SDK核心接口的用法以及代码示例,以协助用户更快接入。
1. 创建客户端
第一步,需要创建客户端,默认客户端采用grpc协议,且为同步调用。
#include <iostream>
#include "proxima_searcher_client.h"
using proxima::be;
// 默认类型客户端
auto client = ProximaSearchClient::Create();
第二步,创建完客户端之后,我们需要显示连接ProximaBE服务:
// 设置连接参数,注意这里需要填写grpc协议监听端口
ChannelOptions options("127.0.0.1:16000");
// 连接服务端
Status status = client->connect(options);
if (status.code != 0) {
  std::cerr << "Connect server failed." << std::endl;
  return status.code;
}
我们在连接过程中,除了简单的测试rpc连通性之外,还会与server校验版本信息,确保兼容性。
客户端所有接口,都会返回Status,用户需要检查status.code是否正常,其结构如下:
struct Status {
  /// 错误码,0代表成功,其它非0代表调用错误
  int code;
  
  /// 错误原因, 默认为"Success",否则是错误描述
  std::string reason;
}
代码中涉及到其它结构以及字段,可以参见ChannelOptions
2. 集合管理
我们提供了Collection的创建、删除、查询、统计等接口,供用户方便的管理集合。
2.1. 创建Collection
创建一个名为Plants的集合,其中正排列为价格"price"以及描述"description",索引列为向量列,存储4维float类型
/// 描述Collection的具体格式
CollectionConfig config;
config.collection_name = "Plants";
config.forward_columns = {"Price", "Description"};
config.index_columns = {IndexColumnParam("ImageVector", DataType::VECTOR_FP32, 8)}
/// 创建Collection
Status status = client->create_collection(config);
if (status.code != 0) {
  std::cerr << "Create collection failed." << std::endl;
  return status.code;
}
集合配置详细信息请参考: CollectionConfig
2.2. 查询Collection
创建完集合之后,我们可以使用查询接口查看其状态。
/// 获取CollectionInfo
CollectionInfo collection_info;
Status status = client->describe_collection("Plants", &collection_info);
if (status.code != 0) {
  std::cerr << "Get collection info failed." << std::endl;
  return status.code;
}
/// 打印CollectionInfo
std::cout << collection_info.collection_name << std::endl;
std::cout << collection_info.collection_status << std::endl;
std::cout << collection_info.uuid << std::endl;
......
除此之外,我们还可以将所有Collection信息一次性列出来
/// 获取所有的Collection信息
std::vector<CollectionInfo> collection_infos;
Status status = client->list_collections(&collection_infos);
if (status.code != 0) {
	std::cerr << "List collection infos failed." << std::endl;
  return status.code;
}
返回的集合信息详细字段请参考: CollectionInfo
2.3. 统计Collection
Collection经过一段时间的读写之后,我们可以通过统计接口观察其装载的文档数据。
/// 获取CollectionStats
CollectionStats collection_stats;
Status status = client->stats_collection("Plants", &collection_stats);
if (status.code != 0) {
  std::cerr << "Get collection statistics failed." << std::endl;
  return status.code;
}
/// 打印CollectionStats
std::cout << collection_stats.collection_name << std::endl;
std::cout << collection_stats.total_doc_count << std::endl;
std::cout << collection_stats.total_segment_cout << std::endl;
.....
集合统计详细字段信息请参考: CollectionStats
2.4. 删除Collection
Collection完成其历史使命后,我们可以彻底删除掉某个collection。
/// 删除集合
Status status = client->drop_collection("Plants");
if (status.code != 0) {
  std::cerr << "Drop collection failed." << std::endl;
  return status.code;
}
3. 文档管理
对于某一个集合而言,我们提供增加、更新、删除文档的接口,同时支持批量模式。
3.1. 插入文档
我们在之前已经创建完成的名为"Plants"的集合中,插入100条数据
/// 创建一个写入请求
auto write_request = WriteRequest::Create();
/// 设置集合以及文档数据格式
write_request->set_collection_name("Plants");
write_request->add_forward_columns({"Price", "Description"});
write_request->add_index_column("ImageVector", DataType::VECTOR_FP32, 8);
/// 批量填充100条文档数据
for (int i = 0; i < 100; i++) {
	auto row = write_request->add_row();
  row->set_primary_key(i);
  /// 设置为插入操作
  row->set_operation_type(OperationType::INSERT);
  row->add_forward_value((float)i + 0.1f);
  row->add_forward_value("iris with number " + std::to_string(i));
  row->add_index_value({i, i, i, i, i, i, i, i});
}
/// 写入到服务端
Status status = client->write(*write_request);
if (status.code != 0) {
  std::cerr << "Write records failed." << std::endl;
  return status.code;
}
在上述参考代码中,有几点值得注意:
- 
设置文档数据格式。 这里最早其实在创建Collection时候,我们填写过一次,这里需要再次设置的主要原因有两个。 第一个是由于我们未来会支持实时量化的能力,可能用户配置的类型与输入类型不一致,使用我们动态转换的能力。第二个则是我们可以基于这个信息做二次校验,防止插入数据格式错误。
 - 
批量模式。 理论上在一个WriteRequest中我们可以组合任意多的文档,但由于会增大单个网络请求包大小,一般还是建议用户根据实际情况进行限制。
 
3.2. 更新文档
更新过程基本与插入过程一致,仅改变文档的操作类型即可。
.....
/// 批量更新100条文档数据
for (int i = 0; i < 100; i++) {
	auto row = write_request->add_row();
  row->set_primary_key(i);
  /// 设置为更新操作
  row->set_operation_type(OperationType::UPDATE);
  row->add_forward_value((float)i + 0.2f);
  row->add_forward_value("iris with number " + std::to_string(i));
  row->add_index_value({i, i, i, i, i, i, i, i});
}
......
NOTE: 值得注意的是,目前我们实际实现中采取的是标记删除的模式,更新=删除+新增,而删除占比过高会极大影响查询性能,这一点用户务必注意。
写入请求的详细信息可以参考: WriteRequest
3.3. 删除文档
删除过程依然可以复用上述的代码结构,如果批量请求中没有插入、更新请求,那么代码可以极大简化。
/// 创建一个写入请求
auto write_request = WriteRequest::Create();
/// 设置集合以及文档数据格式
write_request->set_collection_name("Plants");
/// 批量删除100条文档数据
for (int i = 0; i < 100; i++) {
	auto row = write_request->add_row();
  /// 设置为删除操作,仅需要填写primary key即可
  row->set_primary_key(i);
  row->set_operation_type(OperationType::DELETE);
}
/// 发送到服务端
Status status = client->write(*write_request);
if (status.code != 0) {
  std::cerr << "Write records failed." << std::endl;
  return status.code;
}
NOTE: 值得注意的是,由于我们内部采用图索引结构,删除目前采取标记删除方式,删除比例过高会带来连通性问题,影响召回和性能。我们一般不建议用户删除超过50%的文档,否则查询性能将会弱化很多。
4. 文档查询
最后我们希望能够在创建的"Plants"集合中查询这100条数据,相似度召回10条结果。
auto query_request = QueryRequest::Create();
auto query_response = QueryResponse::Create();
/// 填充请求参数
query_request->set_collection_name("Plants");
auto knn_param = query_request->add_knn_query_param();
knn_param->set_column_name("ImageVector");
knn_param->set_topk(10);
knn_param->set_features({0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8});
/// Knn查询
Status status = client->query(*query_request, query_response.get());
if (status.code != 0) {
  std::cerr << "Query records failed." << std::endl;
  return status.code;
}
/// 打印结果
for (size_t i = 0; i < query_response->result_count(); i++) {
  auto result = query_response->result(i);
  for (size_t j = 0; j < result->document_count(); j++){
    auto doc = result->document(j);
    /// 获取文档的primary key和相似度距离
    std::cout << doc->primary_key() << std::endl;
    std::cout << doc->score() << std::endl;
    
    /// 按顺序取正排字段
    float price;
    std::string desc;
    doc->get_forward_value("Price", &price);
    doc->get_forward_value("Description", &desc);
    std::cout << price << std::endl;
    std::cout << desc << std::endl;
  }
}
我们query同样也可以支持批量模式
const *vector_bytes;
size_t vector_size;
......
auto knn_param = query_request->add_knn_query_param();
knn_param->set_column_name("ImageVector");
knn_param->set_topk(10);
knn_param->set_features(vector_bytes, vector_size, 100);
knn_param->set_data_type(DataType::VECTOR_FP32);
knn_param->set_dimension(8);
上述代码中描述了设置一段连续的bytes作为查询向量,包含100个连续的查询向量,其中每个为8维float类型。
NOTE: 还有一点值得注意的是,最终的正排数据的获取,必须按照CollectionConfig定义的顺序逐一获取,顺序不对或者类型不对,均会导致获取到空结果
上述参考代码中查询请求和查询结果的详细信息请参考: QueryRequest
5. 错误码
| 错误码 | 错误原因 | 备注 | 
|---|---|---|
| 0~9999 | 服务端错误 | |
| 10000 | 初始化客户端失败 | |
| 10001 | RPC连接出错 | |
| 10002 | 客户端与服务端版本不匹配 | |
| 10003 | 客户端还未连接 | |
| 10004 | 请求校验失败 | 
6. 接口&类型
ProximaSearchClient
/**
 * ProximaSearchClient wrappers the operations used to call proxima search
 * engine's service. Server may be running on another machines. It shields
 * implementation of communication protocol and rpc details, and provide
 * extremely high bench performance.
 *
 * Usage exp:
 *     auto client = ProximaSearchClient::Create();
 *     if (client != nullptr) {
 *       client->connect(ChannelOptions("127.0.0.1:16000"));
 *       ...
 *       client->create_collection();
 *       client->close();
 *     }
 *
 * Please read the examples/client_example.cc for more details.
 *
 * Note: the functions of this class are sync call.
 */
class ProximaSearchClient {
 public:
  /// @brief Create a client instance and return its shared ptr.
  ///
  /// @param type Client type, only support "GrpcClient" now.
  /// @return Shared ptr pointed to client impl.
  ///
  /// @note If input type is wrong, it may return nullptr
  static ProximaSearchClientPtr Create(const std::string &type);
  //! Create a shared ptr of client with default type
  static ProximaSearchClientPtr Create();
  /// @brief Try to connect remote server and establish connection.
  ///
  /// @param options Socket connection relative configs.
  /// @return Status.code 0 means success, other means fail
  ///
  /// @note This function will try to send a list collections command
  ///       to test if the server alive.
  virtual Status connect(const ChannelOptions &options) = 0;
  //! Close connection to remote server and cleanup self
  virtual Status close() = 0;
  /// @brief Create a collection with specific config.
  ///
  /// @param config Collection config
  /// @return       Status.code 0 means success, other means fail
  virtual Status create_collection(const CollectionConfig &config) = 0;
  /// @brief Drop a collection with specific name.
  ///
  /// @param collection_name Collection name
  /// @return Status.code 0 means success, other means fail
  virtual Status drop_collection(const std::string &collection_name) = 0;
  /// @brief Show the detailed information of collection.
  ///
  /// @param[in]  collection_name Collection name
  /// @param[out] collection_info Collection information
  /// @return Status.code 0 means success, other means fail
  virtual Status describe_collection(const std::string &collection_name,
                                     CollectionInfo *collection_info) = 0;
  /// @brief Get collection statics.
  ///
  /// @param[in]  collection_name Collection name
  /// @param[out] stats           Collection statistics struct
  /// @return Status.code 0 means success, other means fail.
  virtual Status stats_collection(const std::string &collection_name,
                                  CollectionStats *stats) = 0;
  /// @brief List all collections.
  ///
  /// @param[out] collections Collection infomations
  /// @return Status.code 0 means success, other means fail
  virtual Status list_collections(std::vector<CollectionInfo> *collections) = 0;
  /// @brief Insert/Update/Delete records.
  ///
  /// @param request Write request
  /// @return Status.code means success, other means fail
  virtual Status write(const WriteRequest &request) = 0;
  /// @brief Knn query similar results
  ///
  /// @param[in]  request  Query request
  /// @param[out] respnose Query response
  /// @return Status.code means success, other means fail
  virtual Status query(const QueryRequest &request,
                       QueryResponse *response) = 0;
  /// @brief Get document by primary key
  ///
  /// @param[in]  request  Get document request
  /// @param[out] response Get document response
  /// @return Status.code means success, other means fail
  virtual Status get_document_by_key(const GetDocumentRequest &request,
                                     GetDocumentResponse *response) = 0;
};
ChannelOptions
/**
 * ChannelOptions represents the  connection config.
 */
struct ChannelOptions {
  /// Host name of proximabe server
  /// For exapmle: "127.0.0.1:16000"
  /// Required field
  std::string host{};
  /// Max rpc duration out over server
  /// Optional field, default 1000
  uint32_t timeout_ms{1000U};
  /// Max retry times when rpc failed
  /// Optional filed, default 3
  uint32_t max_retry{3U};
  /// Connection pool count
  /// Optional filed, default 1
  uint32_t connection_count{1};
  ChannelOptions(const std::string &val) : host(val) {}
};
CollectionConfig
/**
 * CollectionConfig describes the config options of collection.
 * It includes description of index columns and forward columns.
 * Index columns means that this column data is for knn searching.
 * Forward columns means that this column data is just for display,
 * which is not anticipating in search process.
 */
struct CollectionConfig {
  /// Collection name, it should be unique
  /// Required field
  std::string collection_name{};
  /// Collection will split into serveral segments
  /// This param means max doc limits in one segment
  /// Optional field, default 0, means no limit
  uint32_t max_docs_per_segment{0U};
  /// Forward column names
  /// Optional field
  std::vector<std::string> forward_columns{};
  /// Index column infos
  /// Required filed
  std::vector<IndexColumnParam> index_columns{};
  /// Database repository config
  /// Optional field, default empty
  DatabaseRepository database_repository{};
};
/**
 * IndexColumnParam represents the index config of index column.
 */
struct IndexColumnParam {
  /// Column name
  /// Required field
  std::string column_name{};
  /// Column index type
  /// Optional field, default IndexType::PROXIMA_GRAPH_INDEX
  IndexType index_type{IndexType::PROXIMA_GRAPH_INDEX};
  /// Stored data type
  /// Optional filed, default DataType::VECTOR_FP32
  DataType data_type{DataType::VECTOR_FP32};
  /// Stored data dimension
  /// Optional filed, default 0
  uint32_t dimension{0U};
  /// Extra params for column index
  /// Optional field
  /// For example:
  ///   {"ef_construction": "400", "ef_search": "300"}
  std::vector<KVPair> extra_params{};
  IndexColumnParam() = default;
  IndexColumnParam(const std::string &val1, DataType val2, uint32_t val3)
      : column_name(val1), data_type(val2), dimension(val3) {}
};
CollectionInfo
/**
 * CollectionInfo describes the detailed information of collection,
 * which is ProximaSE server returned.
 */
struct CollectionInfo {
  enum class CollectionStatus : uint32_t {
    INITIALIZED = 0,
    SERVING = 1,
    DRPPED = 2
  };
  //! Collection name
  std::string collection_name{};
  //! Collection status
  CollectionStatus collection_status{CollectionStatus::INITIALIZED};
  //! Unique uuid to a collection
  std::string collection_uuid{};
  //! Latest record's log sequence number
  uint64_t latest_lsn{0U};
  //! Latest record's lsn context
  std::string latest_lsn_context{};
  //! Server magic number, generally is server started timestamp
  uint64_t magic_number{0U};
  //! Collection's config max doc number per segment
  uint32_t max_docs_per_segment{0U};
  //! Collection's forward column names
  std::vector<std::string> forward_columns{};
  //! Collection's index column params
  std::vector<IndexColumnParam> index_columns{};
  //! Collection's database repository information
  DatabaseRepository database_repository{};
};
CollectionStats
/**
 * CollectionStats describes the detailed stastistics of collection
 */
struct CollectionStats {
  /**
   * Segment state
   */
  enum class SegmentState : uint32_t {
    CREATED = 0,
    WRITING = 1,
    DUMPING = 2,
    COMPACTING = 3,
    PERSIST = 4
  };
  /*
   * SegmentStats describes the detailed stastistics of segment
   */
  struct SegmentStats {
    //! Segment unique id
    uint64_t segment_id{0U};
    //! Segment state
    SegmentState segment_state{SegmentState::CREATED};
    //! Document count in this segment
    uint64_t doc_count{0U};
    //! Index file count of this segment
    uint64_t index_file_count{0U};
    //! Totaol index file size
    uint64_t index_file_size{0U};
    //! Min document id
    uint64_t min_doc_id{0U};
    //! Max document id
    uint64_t max_doc_id{0U};
    //! Min primary key value of the segment
    uint64_t min_primary_key{0U};
    //! Min primary key value of the segment
    uint64_t max_primary_key{0U};
    //! Earliest record timestamp
    uint64_t min_timestamp{0U};
    //! Last record timestamp
    uint64_t max_timestamp{0U};
    //! Minimal log sequence number
    uint64_t min_lsn{0U};
    //! Maximum log sequence number
    uint64_t max_lsn{0U};
  };
  //! Collection name
  std::string collection_name{};
  //! Total document count of this collection
  uint64_t total_doc_count{0U};
  //! Total segment count of this collectoin
  uint64_t total_segment_count{0U};
  //! Total index file count
  uint64_t total_index_file_count{0U};
  //! Total index file size
  uint64_t total_index_file_size{0U};
  //! Detailed segment stastistics
  std::vector<SegmentStats> segment_stats{};
};
WriteRequest
/**
 * WriteRequest shows how to wrapper write request data fields.
 *
 * Usage exp:
 *   WriteRequestPtr request = WriteRequest::Create();
 *   request->set_collection_name("test_collection");
 *   request->set_row_meta({"test_column"}, {});
 *   auto row = request->add_row();
 *   row->set_primary_key = 123;
 *   row->set_operation_type(OperationType::OP_INSERT);
 *   row->add_index_value({0.1, 0.2, 0.3});
 *   ...
 *   client->write(*request);
 */
class WriteRequest {
 public:
  /**
   * A row describes the format of one record
   */
  class Row {
   public:
    //! Set primary key, required
    virtual void set_primary_key(uint64_t val) = 0;
    //! Set operation type, optional, default DataType::INSERT
    virtual void set_operation_type(OperationType op_type) = 0;
    //! Set lsn, optional, default 0
    virtual void set_lsn(uint64_t lsn) = 0;
    //! Set lsn context, optional, default ""
    virtual void set_lsn_context(const std::string &lsn_context) = 0;
    /// @brief Add forward value with string type
    ///
    /// @note  Add forward value sort must match configured
    ///        forward columns in CollectionConfig
    virtual void add_forward_value(const std::string &val) = 0;
    //! Add forward value with bool type
    virtual void add_forward_value(bool val) = 0;
    //! Add forward value with int32 type
    virtual void add_forward_value(int32_t val) = 0;
    //! Add forward value with int64 type
    virtual void add_forward_value(int64_t val) = 0;
    //! Add forward value with uint32 type
    virtual void add_forward_value(uint32_t val) = 0;
    //! Add forward value with uint64 type
    virtual void add_forward_value(uint64_t val) = 0;
    //! Add forward value with float type
    virtual void add_forward_value(float val) = 0;
    //! Add forward value with double type
    virtual void add_forward_value(double val) = 0;
    /// @brief Add index value, vector bytes type
    ///
    /// @note Add index value sort must match configured
    ///       index columns in CollectionConfig
    virtual void add_index_value(const void *val, size_t val_len) = 0;
    //! Add index value, vector array type
    virtual void add_index_value(const std::vector<float> &val) = 0;
    /// Add index value by json format
    /// Two json format:
    ///   "[0.1, 0.2, 0.3, 0.4]"
    ///   "[[0.1, 0.2, 0.3, 0.4], [0.5, 0.6, 0.7, 0.8]]"
    virtual void add_index_value_by_json(const std::string &json_val) = 0;
  };
  using RowPtr = std::shared_ptr<Row>;
 public:
  //! Constructor
  static WriteRequestPtr Create();
  //! Set collection name, required, must be unique
  virtual void set_collection_name(const std::string &val) = 0;
  /// @brief Add forward column in row meta
  /// @note Forward column names' sort must match configured
  ///       forward columns in CollectionConfig
  virtual void add_forward_column(const std::string &column_name) = 0;
  /// @brief Add forward columns in row meta
  /// @note Forward column names' sort must match configured
  ///       forward columns in CollectionConfig
  virtual void add_forward_columns(
      const std::vector<std::string> &column_names) = 0;
  /// @brief Add index column in row meta
  ///
  /// @param column_name Column name
  /// @param data_type   Send data type
  /// @param dimension   Send data dimension
  ///
  /// @note Index column names' sort must match configured
  ///       index columns in CollectionConfig
  virtual void add_index_column(const std::string &column_name,
                                DataType data_type, uint32_t dimension) = 0;
  //! Add row data, required, can't send empty request
  virtual WriteRequest::RowPtr add_row() = 0;
  //! Set request id for tracelog, optional
  virtual void set_request_id(const std::string &request_id) = 0;
  //! Set magic number for validation, optional
  virtual void set_magic_number(uint64_t magic_number) = 0;
};
QueryRequest
/**
 * QueryRequest shows how to wrapper query data fields.
 *
 * Usage exp:
 *   QueryRequestPtr request = QueryRequest::Create();
 *   request->set_collection_name("test_colletion");
 *   auto knn_param = request->add_knn_query_param();
 *   knn_param->set_column_name("test_column");
 *   knn_param->set_features({0.1, 0.2, 0.3, 0.4});
 *   knn_param->set_batch_count(1);
 *   knn_param->set_dimension(4);
 *   knn_param->set_data_type(DT_VECTOR_FP32);
 *   ...
 *
 */
class QueryRequest {
 public:
  /**
   * KnnQueryParam describes the options of knn query
   */
  class KnnQueryParam {
   public:
    //! Set column name, required
    virtual void set_column_name(const std::string &val) = 0;
    //! Set topk, required
    virtual void set_topk(uint32_t val) = 0;
    /// Set query vector with bytes format by single
    /// Required set
    virtual void set_features(const void *val, size_t val_len) = 0;
    //! Set features with vector array format by single
    virtual void set_features(const std::vector<float> &val) = 0;
    //! Set query vector with bytes format by batch
    virtual void set_features(const void *val, size_t val_len,
                              uint32_t batch) = 0;
    /// Set features by json format
    /// Two json format:
    ///   "[0.1, 0.2, 0.3, 0.4]"
    ///   "[[0.1, 0.2, 0.3, 0.4], [0.5, 0.6, 0.7, 0.8]]"
    virtual void set_features_by_json(const std::string &json_val) = 0;
    //! Set features by json format and by batch
    virtual void set_features_by_json(const std::string &json_val,
                                      uint32_t batch) = 0;
    //! Set vector data dimension, required
    virtual void set_dimension(uint32_t val) = 0;
    //! Set vector data type, required
    virtual void set_data_type(DataType val) = 0;
    //! Set search radius, optional, default 0.0f not open
    virtual void set_radius(float val) = 0;
    //! Set if use linear search, optional, default false
    virtual void set_linear(bool val) = 0;
    //! Add extra params, like ef_search ..etc, optional
    virtual void add_extra_param(const std::string &key,
                                 const std::string &val) = 0;
  };
  using KnnQueryParamPtr = std::shared_ptr<KnnQueryParam>;
 public:
  //! Constructor
  static QueryRequestPtr Create();
  //! Set collection name, required
  virtual void set_collection_name(const std::string &val) = 0;
  //! Set knn query param, required
  virtual QueryRequest::KnnQueryParamPtr add_knn_query_param() = 0;
  //! Set debug mode, optional, default false
  virtual void set_debug_mode(bool val) = 0;
};
QueryResponse
/**
 * QueryResponse shows the format of query response.
 */
class QueryResponse {
 public:
  /**
   * Result represents a knn query's result
   */
  class Result {
   public:
    //! Return document count
    virtual size_t document_count() const = 0;
    //! Return document pointer of specific pos
    virtual DocumentPtr document(int index) const = 0;
  };
 public:
  //! Constructor
  static QueryResponsePtr Create();
  //! Return debug info
  virtual const std::string &debug_info() const = 0;
  //! Return query latency, microseconds
  virtual uint64_t latency_us() const = 0;
  //! Return batch result count
  virtual size_t result_count() const = 0;
  //! Return result pointer of specific batch pos
  virtual QueryResponse::ResultPtr result(int index) const = 0;
};
/**
 * Document shows the format of knn query response
 */
class Document {
 public:
  //! Return document primary key
  virtual uint64_t primary_key() const = 0;
  //! Return calculated knn distance score
  virtual float score() const = 0;
  //! Return forward values count
  virtual size_t forward_count() const = 0;
  //! Get forward names
  virtual void get_forward_names(
      std::vector<std::string> *forward_names) const = 0;
  //! Get forward value with string type
  virtual void get_forward_value(const std::string &key,
                                 std::string *val) const = 0;
  //! Get forward value with bool type
  virtual void get_forward_value(const std::string &key, bool *val) const = 0;
  //! Get forward value with int32 type
  virtual void get_forward_value(const std::string &key,
                                 int32_t *val) const = 0;
  //! Get forward value with int64 type
  virtual void get_forward_value(const std::string &key,
                                 int64_t *val) const = 0;
  //! Get forward value with uint32 type
  virtual void get_forward_value(const std::string &key,
                                 uint32_t *val) const = 0;
  //! Get forward value with uint64 type
  virtual void get_forward_value(const std::string &key,
                                 uint64_t *val) const = 0;
  //! Get forward value with float type
  virtual void get_forward_value(const std::string &key, float *val) const = 0;
  //! Get forward value with double type
  virtual void get_forward_value(const std::string &key, double *val) const = 0;
};
3 - Java SDK
本文主要介绍用户如何使用 Java SDK,来进行集合管理、文档的增删改查等功能。
1. 前提条件
使用 ProximaBE 的 Java SDK,必须满足以下两点:
-  JDK 1.8 或者以上版本
-  使用 Apache Maven
2. 安装 Java SDK
可以通过Apache Maven二方库依赖的方式,将 SDK 下载到自己的项目中。
<dependency>
<groupId>com.alibaba.proxima</groupId>
<artifactId>proxima-be-java-sdk</artifactId>
<version>0.1.2-SNAPSHOT</version>
</dependency>
3. 客户端创建
ProximaSearchClient 是ProximaBE 对外的所有接口的代理层,用户通过传入连接参数,创建该客户端对象,就可以对 ProximaBE 中的集合进行相关的操作。
3.1. 初始化连接参数
构建类:ConnectParam.Builder
首先通过调用 ConnectParam 的 newBuilder 接口,创建出 ConnectParam 的 Builder 对象,然后依次通过Builder对象设置 ProximaBE 的 host 地址,以及 grpc 端口等信息,最终调用 Builder的 build 接口,即可构建出 ConnectParam 对象。
Builder 参数说明:
| 参数 | 说明 | 
|---|---|
| host | ProximaBE对应的服务地址,String类型默认为 localhost | 
| port | ProximaBE对应的GRPC服务端口,int类型,默认16000 | 
| IdleTimeout | GRPC链接空闲的超时时间,long类型,默认12小时 | 
3.2. 创建客户端对象
接口:ProximaGrpcSearchClient(ConnectParam connectParam)
通过传入的 connectParam 对象创建 ProximaBE 客户端,目前支持 Grpc 协议,创建成功后返回 ProximaSearchClient 对象,目前 Client 中的接口均为同步接口。
参数说明:
- ConnectParam:表示连接 ProximaBE 所需要的相关连接参数信息
 
3.3. 示例
创建 ProximaSearchClient 对象
import com.alibaba.proxima.se.client.*;
// init connect params
ConnectParam connectParam = ConnectParam.newBuilder()
                .withHost("127.0.0.1")
                .withPort(16000)
                .build();
// create client
ProximaSearchClient client = new ProximaGrpcSearchClient(connectParam);
4. 集合管理
集合管理主要包括集合的创建、集合的查询和集合的删除等操作。
4.1. 创建集合
4.1.1 创建 CollectionConfig
构造类:CollectionConfig.Builder
首先通过调用 CollectionConfig 的 newBuilder 接口,创建出 CollectionConfig 的 Builder 对象,然后通过 Builder 对象设置集合名称、索引列信息、正排列信息等,最终调用 Builder 的 build 接口,即可构建出 CollectionConfig 对象。
Builder 参数说明:
| 参数 | 说明 | 
|---|---|
| collectionName | 集合的名称,String类型 | 
| indexColumnParams | 索引列参数列表,List | 
| forwardColumnNames | 正排列的名称列表,List | 
| maxDocsPerSegment | 分片最大文档数,long类型,默认值为0,表示不限制单片文档数 | 
| databaseRepository | 数据库源相关配置,如果是数据库旁路集合,需要配置该选项,目前只支持 mysql 数据库 | 
IndexColumnParam 参数:
| 参数 | 说明 | 
|---|---|
| columnName | 索引列名称,String 类型 | 
| indexType | 索引类型,IndexType 类型,目前支持 PROXIMA_GRAPH_INDEX 类型索引 | 
| dataType | 索引列数据类型,DataType 类型 | 
| dimension | 索引的维度,int 类型 | 
| extraParams | 其它的参数,Map类型 | 
4.1.2 调用创建接口
接口: Status createCollection(CollectionConfig collectionConfig)
根据参数 CollectionConfig 对象创建集合,返回值为 Status 对象,表示集合创建成功与否,如果传入的 CollectionConfig 对象非法,会抛出 ProximaBEException 异常。
参数说明:
- collectionConfig:其中包含了集合的基础配置信息,主要有集合名称、索引列信息、正排列名称列表等。
 
返回值:
- Status:表示创建成功与否,其中包含错误码和错误描述
 
4.1.3 示例
示例 1:创建一个带有两个正排列,以及单个向量索引列的集合
public boolean createCollection(ProximaSearchClient client) {
        String collectionName = "collection1";
        int dimension = 8;
        // create collection builder
        CollectionConfig config = CollectionConfig.newBuilder()
                .withCollectionName(collectionName)                            // set collection name
                .withForwardColumnNames(Arrays.asList("forward1", "forward2")) // set forward column names
                .addIndexColumnParam("index1", DataType.VECTOR_FP32, dimension)// add one index column param
                .build();                                                      // build the CollectionConfig
        // call create collection interface
        try {
            Status status = client.createCollection(config);
            if (status.ok()) {
                System.out.println("============== Create collection success. ================");
                return true;
            } else {
                System.out.println("Create collection failed." + status.toString());
                return false;
            }
        } catch (ProximaBEException e) {
            e.printStackTrace();
            return false;
        }
    }
示例 2:创建一个带有两个正排列、单个向量索引列、以及作为Mysql 数据旁路的集合
public boolean createCollectionWithRepo(ProximaSearchClient client) {
    String collectionName = "collection2";
    int dimension = 8;
    // create database repository
    DatabaseRepository repo = DatabaseRepository.newBuilder()
            .withConnectionUri("mysql://host.com:8080/mysql_database")  // set connection uri
            .withTableName("mysql_table1")                              // set table name
            .withRepositoryName("mysql_repo")                           // set repository name
            .withUser("root")                                           // set user name
            .withPassword("root")                                       // set password
            .build();
    // create collection builder
    CollectionConfig config = CollectionConfig.newBuilder()
            .withCollectionName(collectionName)                            // set collection name
            .withForwardColumnNames(Arrays.asList("forward1", "forward2")) // set forward column name list
            .addIndexColumnParam("index1", DataType.VECTOR_FP32, dimension)// add one index column param
            .withDatabaseRepository(repo)                                  // set database repoistory
            .build();
    // call create collection interface
    try {
        Status status = client.createCollection(config);
        if (status.ok()) {
            System.out.println("============== Create collection success. ================");
            return true;
        } else {
            System.out.println("Create collection failed." + status.toString());
            return false;
        }
    } catch (ProximaBEException e) {
        e.printStackTrace();
        return false;
    }
}
4.2. 查询集合配置信息
接口: DescribeCollectionResponse describeCollection(String collectionName)
根据传入的集合名称,获取当前集合对应的相关配置信息。
参数说明:
- collectionName:集合名称
 
返回值:
- DescribeCollectionResponse:其中包含 Status 以及 CollectionInfo 两部分,Status 描述当前请求成功与否,CollectionInfo 描述集合的配置信息
 
示例:
查询 collection 的配置信息
public boolean describeCollection(ProximaSearchClient client) {
    String collectionName = "collection1";
    // describe collection
    DescribeCollectionResponse descResponse = client.describeCollection(collectionName);
    if (descResponse.ok()) {
        System.out.println("================ Describe collection success. ===================");
        CollectionInfo info = descResponse.getCollectionInfo();
        CollectionConfig collectionConfig = info.getCollectionConfig();
        System.out.println("CollectionName: " + collectionConfig.getCollectionName());
        System.out.println("CollectionStatus: " + info.getCollectionStatus());
        System.out.println("Uuid: " + info.getUuid());
        System.out.println("Forward columns: " + collectionConfig.getForwardColumnNames());
        List<IndexColumnParam> indexColumnParamList = collectionConfig.getIndexColumnParams();
        for (int i = 0; i < indexColumnParamList.size(); ++i) {
            IndexColumnParam indexParam = indexColumnParamList.get(i);
            System.out.println("IndexColumn: " + indexParam.getColumnName());
            System.out.println("IndexType: " + indexParam.getDataType());
            System.out.println("DataType: " + indexParam.getDataType());
            System.out.println("Dimension: " + indexParam.getDimension());
        }
        return true;
    } else {
        System.out.println("Describe collection failed " + descResponse.toString());
        return false;
    }
}
4.3. 查询集合统计信息
接口: StatsCollectionResponse statsCollection(String collectionName)
根据传入的集合名称,获取当前集合对应的相关统计信息。
参数说明:
- collectionName:集合名称
 
返回值:
- StatsCollectionResponse:其中包含 Status 以及 CollectionStats 两部分,Status 描述当前请求成功与否,CollectionStats 描述集合的相关统计信息,包含的信息如下:
 
| 字段名称 | 说明 | 
|---|---|
| collectionPath | collection 的索引路径 | 
| totalDocCount | 总的文档数量 | 
| totalSegmentCount | 总的segment数量 | 
| totalIndexFileCount | 总的索引文件数量 | 
| totalIndexFileSize | 总的索引文件大小 | 
| segmentStatsList | 每个 segment 相应的统计信息,包括 segment 的总文档数量、索 引文件数量和大小,以及最大/小 doc id等  | 
示例 :
查询指定集合的统计信息
public boolean statsCollection(ProximaSearchClient client) {
    String collectionName = "collection1";
    // call stats collection interface
    StatsCollectionResponse statsResponse = client.statsCollection(collectionName);
    if (statsResponse.ok()) {
        System.out.println("==================== Stats collection success. ======================");
        CollectionStats stats = statsResponse.getCollectionStats();
        System.out.println("CollectionName: " + stats.getCollectionName());
        System.out.println("TotalDocCount: " + stats.getTotalDocCount());
        System.out.println("TotalSegmentCount: " + stats.getTotalSegmentCount());
        for (int i = 0; i < stats.getSegmentStatsCount(); ++i) {
            System.out.println("Segment: " + i);
            System.out.println("SegmentDocCount: " + stats.getSegmentStats(i).getDocDount());
            System.out.println("SegmentIndexFileCount: " + stats.getSegmentStats(i).getIndexFileCount());
            System.out.println("SegmentMaxDocId: " + stats.getSegmentStats(i).getMaxDocId());
        }
        return true;
    } else {
        System.out.println("Stats collection failed " + statsResponse.getStatus().toString());
        return false;
    }
}
4.4. 删除集合
接口: Status dropCollection(String collectionName)
删除指定集合,集合名由参数 collectionName 指定
参数说明:
- collectionName:删除的集合名称
 
返回值:
- Status:表示删除成功与否,其中包含错误码和错误描述
 
示例 :
删除指定集合
public boolean dropCollection(ProximaSearchClient client) {
    String collectionName = "collection1";
    // call drop collection interface
    Status status = client.dropCollection(collectionName);
    if (status.ok()) {
        System.out.println("==================== Dorp collection success. ========================");
        return true;
    } else {
        System.out.println("Drop collection failed " + status.toString());
        return false;
    }
}
4.5. 获取集合列表
接口: ListCollectionsResponse listCollections(ListCondition listCondition)
根据传入的 ListCondition 条件获取满足条件的集合列表
参数说明:
- listCondition:集合需要满足的条件,目前只包含了一个 Repository 名称字段,仅用在Mysql 同步数据时,如果该字段为空或者 listCondition 为空时,返回所有的集合
 
返回值:
- ListCollectionsResponse:包含 Status 和 CollectionInfo List 两部分,前者描述请求是否成功,后者描述所有集合的配置信息。
 
示例 :
获取 repository name 为 mysql_repo 的所有集合
public boolean listCollections(ProximaSearchClient client) {
    // build list condition object
    ListCondition listCondition = ListCondition.newBuilder()
            .withRepositoryName("mysql_repo")  // set repository name
            .build();
    // call list collections interface
    ListCollectionsResponse listResponse = client.listCollections(listCondition);
    if (listResponse.ok()) {
        System.out.println("List collections success.");
        for (int i = 0; i < listResponse.getCollectionCount(); ++i) {
            System.out.println("Collection " + i);
            CollectionInfo info = listResponse.getCollection(i);
            CollectionConfig collectionConfig = info.getCollectionConfig();
            System.out.println("CollectionName: " + collectionConfig.getCollectionName());
            System.out.println("CollectionStatus: " + info.getCollectionStatus());
            System.out.println("Uuid: " + info.getUuid());
            System.out.println("Forward columns: " + collectionConfig.getForwardColumnNames());
            List<IndexColumnParam> indexColumnParamList = collectionConfig.getIndexColumnParams();
            for (int j = 0; j < indexColumnParamList.size(); ++j) {
                IndexColumnParam indexParam = indexColumnParamList.get(j);
                System.out.println("IndexColumn: " + indexParam.getColumnName());
                System.out.println("IndexType: " + indexParam.getDataType());
                System.out.println("DataType: " + indexParam.getDataType());
                System.out.println("Dimension: " + indexParam.getDimension());
            }
        }
        return true;
    } else {
        System.out.println("List collections failed " + listResponse.toString());
        return false;
    }
}
5. 文档管理
文档管理主要包括文档的插入、更新和删除操作,ProximaBE 中将文档的这三种操作,整合为一个通用的 Write 接口,通过一个 WriteRequest 结构来描述相关的操作,WriteRequest 中既可以描述单条记录的操作,也可以描述批量记录的操作。
5.1. 创建 WriteRequest
构造类:WriteRequest.Builder
首先通过 WriteRequest 的 newBuilder() 接口创建出 WriteRequest 的 Builder 对象,然后通过 Builder 对象设置相关参数,包括集合名称、正排列和索引列,以及 Rows等信息,最终调用 Builder 的 build 接口创建出 WriteRequest 对象。
参数说明:
| 参数 | 说明 | 
|---|---|
| collectionName | 集合名称,String类型 | 
| forwardColumnList | 正排列的名称列表,List类型,插入和更新时必须要设置,删除时不需要设置 | 
| indexColumnMetaList | 索引列的 Meta 列表,插入和更新时必须要设置,删除时不需要设置 | 
| rows | 请求中包含的文档操作列表,List类型,每一个 row 表示一个文档操作,具体内容见 Rows 参数说明 | 
| requestId | 请求的 id,String类型,默认为空 | 
| magicNumber | 请求中的魔数,long类型,仅在通过 Mysql 作为数据源时需要设置 | 
Row 参数说明
| 参数 | 说明 | 
|---|---|
| primaryKey | row的主键,long类型 | 
| operationType | row的操作类型,候选值为 INSERT、UPDATE、DELETE三种 | 
| indexValues | 对应索引列的值列表,List类型,operationType为DELETE操作时,不需要指定,支持三种格式:
  | 
| forwardValues | 对应正排列的值列表,List类型,operationType为DELETE时,不需要指定 | 
| lsnContext | mysql 的 lsn 信息,仅当用 mysql 做数据同步时需要 | 
5.2. 执行写入
接口: Status write(WriteRequest request)
向 ProximaBE 中写入文档操作请求,执行完成后返回 Status,表示执行成功与否,如果传入的 WriteRequest 请求非法,会抛出 ProximaBEException 异常。
参数说明:
- request:包含某个集合的插入、更新和删除等文档操作
 
返回值:
- Status:表示写入请求的成功与否
 
5.3. 示例
示例1:向集合 collection1 中分别插入和更新一条记录
public boolean write1(ProximaSearchClient client) {
    String collectionName = "collection1";
    float[] vectors1 = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f};
    float[] vectors2 = {1.5f, 2.5f, 3.5f, 4.5f, 5.5f, 6.5f, 7.5f, 8.5f};
    int dimension = 8;
    long primaryKey = 123456;
    int forward1Value = 123;
    float forward2Value = 100.123f;
    // build insert row
    WriteRequest.Row insertRow = WriteRequest.Row.newBuilder()
            .withPrimaryKey(primaryKey)                           // set primary key
            .withOperationType(WriteRequest.OperationType.INSERT) // set operation type
            .addIndexValue(vectors1)                        // add one index value
            .addForwardValue(forward1Value)                 // add one forard value
            .addForwardValue(forward2Value)                 // add one forward value
            .build();
    // build update row
    WriteRequest.Row updateRow = WriteRequest.Row.newBuilder()
            .withPrimaryKey(primaryKey)                           // set primary key
            .withOperationType(WriteRequest.OperationType.UPDATE) // set operation type
            .addIndexValue(vectors2)                        // add index value
            .addForwardValue(forward1Value)                 // add forward value
            .addForwardValue(forward2Value)                 // add forward value
            .build();
    // build delete row
    long deleteKey = 10000;
    WriteRequest.Row deleteRow = WriteRequest.Row.newBuilder()
            .withPrimaryKey(deleteKey)                            // set primary key
            .withOperationType(WriteRequest.OperationType.DELETE) // set operation type
            .build();
    // build write request
    WriteRequest writeRequest = WriteRequest.newBuilder()
                .withCollectionName(collectionName)                            // set collection name
                .withForwardColumnList(Arrays.asList("forward1", "forward2"))  // set forward column list
                .addIndexColumnMeta("index1", DataType.VECTOR_FP32, dimension) // add one index column meta, otherwise call withIndexColumnMetaList
                .addRow(insertRow)                                             // add insert row
                .addRow(updateRow)                                             // add update row
                .addRow(deleteRow)                                             // add delete row
                .build();
    try {
        // call write interface
        Status status = client.write(writeRequest);
        if (status.ok()) {
            System.out.println("============== Write success. ===============");
            return true;
        } else {
            System.out.println("Write failed " + status.toString());
            return false;
        }
    } catch (ProximaBEException e) {
        e.printStackTrace();
        return false;
    }*/
}
示例2:向集合 collection1 中删除一条记录
public boolean write2(ProximaSearchClient client) {
    String collectionName = "collection1";
    // build delete row
    long deleteKey = 123456;
    WriteRequest.Row deleteRow = WriteRequest.Row.newBuilder()
            .withPrimaryKey(deleteKey)                            // set primary key
            .withOperationType(WriteRequest.OperationType.DELETE) // set operation type
            .build();
    // build write request
    WriteRequest writeRequest = WriteRequest.newBuilder()
                .withCollectionName(collectionName)                            // set collection name
                .addRow(deleteRow)                                             // add delete row
                .build();
    try {
        // call write interface
        Status status = client.write(writeRequest);
        if (status.ok()) {
            System.out.println("============== Write success. ===============");
            return true;
        } else {
            System.out.println("Write failed " + status.toString());
            return false;
        }
    } catch (ProximaBEException e) {
        e.printStackTrace();
        return false;
    }*/
}
6. 文档查询
文档查询目前主要包括两种类型,一种是根据向量来进行 knn 的查询,另一种是直接根据文档的主键来查询相应的文档。
6.1. 向量查询
6.1.1 创建 QueryRequest
构造类:QueryRequest.Builder
通过 QueryRequest 的 newBuilder 接口创建出 QueryRequest 的 Builder 对象,然后通过 Builder 对象设置相关查询参数,主要包括集合名称和 KnnQueryParam等参数,最终调用 Builder 的 build 接口构建出 QueryRequest 对象。
参数说明:
| 参数 | 说明 | 
|---|---|
| collectionName | 要查询的集合名称,String类型 | 
| knnQueryParam | knn 查询的参数,KnnQueryParam类型,具体内容见下表 | 
| debugMode | 是否开启调试模式,boolean类型,默认为false | 
KnnQueryParam 参数
| 参数 | 说明 | 
|---|---|
| columnName | 要查询的索引列名,String类型 | 
| topk | 查询的结果数量,int类型,默认为100 | 
| features | 查询的特征,可以是单个或者多个向量,支持三种类型:
  | 
| dataType | 查询向量的数据类型,向量列表类型的特征支持自动推导,其它类型的必须设置 | 
| dimension | 查询向量的维度,向量列表类型的特征支持自动推导,其它类型的必须设置 | 
| batchCount | 查询的batch数量,向量列表类型的特征支持自动推导,其它类型的必须设置 | 
| radius | 过滤结果的分数阈值,仅当分数小于该阈值的结果会返回,float类型,默认值为0,表示不过滤 | 
| isLinear | 是否使用暴力检索,boolean类型,默认false | 
6.1.2 执行查询
接口: QueryResponse query(QueryRequest request)
通过调用上述接口,向 ProximaBE 发起查询请求,返回 QueryResponse,当传入的 QueryRequest 非法时,会抛出 ProximaBEException 异常。
参数说明:
- request:表示查询请求,包含查询的集合以及查询的向量等信息
 
返回值:
- QueryResponse:表示查询的返回结果,包含查询的状态信息,以及查询的文档结果。
 
6.1.3. 示例
根据某个向量查询最相似的文档
public boolean query(ProximaSearchClient client) {
    String collectionName = "collection1";
    float[] features = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f};
    //  when batch querying, features can be following:
    //  float[][] features = {
    //          {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f},
    //          {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f}
    //  };
    // build query request
    QueryRequest queryRequest = QueryRequest.newBuilder()
            .withCollectionName(collectionName)              // set collection name
            .withKnnQueryParam(                              // set knn query param
                    QueryRequest.KnnQueryParam.newBuilder()  // new KnnQueryParam builder
                            .withColumnName("index1")        // set index column name
                            .withTopk(10)                    // set topk
                            .withFeatures(features)          // set query features
                            .build())                        // build knnQueryParam object
            .build();                                        // build query request
    QueryResponse queryResponse = null;
    try {
        // call query interface
        queryResponse = client.query(queryRequest);
    } catch (ProximaBEException e) {
        e.printStackTrace();
        return false;
    }
    if (queryResponse.ok()) {
        System.out.println("================ Query success =====================");
        for (int i = 0; i < queryResponse.getQueryResultCount(); ++i) {
            QueryResult queryResult = queryResponse.getQueryResult(i);
            for (int d = 0; d < queryResult.getDocumentCount(); ++d) {
                Document document = queryResult.getDocument(d);
                System.out.println("Doc key: " + document.getPrimaryKey());
                System.out.println("Doc score: " + document.getScore());
                Set<String> forwardKeys = document.getForwardKeySet();
                for (String forwardKey : forwardKeys) {
                    System.out.println("Doc forward: " + forwardKey + " -> " +
                                                          document.getForwardValue(forwardKey).getStringValue());
                }
            }
        }
        return true;
    } else {
        System.out.println("Query failed: " + queryResponse.getStatus().toString());
        return false;
    }
}
6.2. 主键查询
6.2.1 创建 GetDocumentRequest
构造类:GetDocumentRequest.Builder
通过 GetDocumentRequest 的 newBuilder 接口,创建出 GetDocumentRequest 的 Builder 对象,然后通过 Builder 对象设置相关查询参数,主要包括集合名称和 主键等参数,最终调用 Builder 的 build 接口构建出 GetDocumentRequest 对象。
Builder 参数说明:
| 参数 | 说明 | 
|---|---|
| collectionName | 要查询的集合名称,String类型 | 
| primaryKey | 要查询的文档的主键,long类型 | 
| debugMode | 是否开启调试模式, boolean类型,默认为false | 
6.2.2 执行查询
接口: GetDocumentResponse getDocumentByKey(GetDocumentRequest request)
通过调用上述接口,向 ProximaBE 发起查询请求,返回 GetDocumentResponse 对象,当传入的 GetDocumentRequest 非法时,会抛出 ProximaBEException 异常。
参数说明:
- request:表示查询指定文档请求
 
返回值:
- GetDocumentResponse:表示查询的返回结果,包含查询的状态信息,以及查询文档的结果。
 
6.2.3 示例
public boolean getDocument(ProximaSearchClient client) {
    String collectionName = "collection1";
    // build get document request
    GetDocumentRequest getRequest = GetDocumentRequest.newBuilder()
            .withCollectionName(collectionName)    // set collection name
            .withPrimaryKey(123456)                // set primary key
            .withDebugMode(true)                   // set debug mode, defalut false
            .build();                              // build GetDocumentRequest object
    GetDocumentResponse getResponse = null;
    try {
        // call get document by key interface
        getResponse = client.getDocumentByKey(getRequest);
    } catch (ProximaBEException e) {
        e.printStackTrace();
        return false;
    }
    if (getResponse.ok()) {
        System.out.println("======================== Get Document success ======================== ");
        Document document = getResponse.getDocument();
        System.out.println("PrimaryKey: " + document.getPrimaryKey());
        System.out.println("Score: " + document.getScore());
        Set<String> forwardKeys = document.getForwardKeySet();
        for (String forwardKey : forwardKeys) {
            System.out.println("Doc forward: " + forwardKey + " -> " +
                   document.getForwardValue(forwardKey).getStringValue());
        }
        System.out.println("DebugInfo: " + getResponse.getDebugInfo());
        return true;
    } else {
        System.out.println("Get document failed " + getResponse.getStatus().toString());
        return false;
    }
}
4 - Golang SDK
用户可以使用Golang SDK进行集合管理、文档的增删该查等功能
1. BE客户端创建
ProximaSearchClient 是BE的客户端接口对象,用户通过该实例对象与BE进行交互,完成的管控功能
1.1. 创建客户端
NewProximaSearchClient(ConnectionProtocol, *Address) (ProximaSearchClient, error)
创建BE客户端,创建成功后返回ProximaSearchClient对象, 否则返回error。
参数说明:
- ConnectionProtocol: 与BE交互的协议类型,目前支持GRPC、HTTP两种协议,其中GRPC在性能以及资源占用上有明显的优势。
 - *Address: 该参数指定BE的网络连接信息,主要包含BE的域名,以及端口号,详细定义如下:
 
// Address reference to entrypoint of ProximaBE
type Address struct {
	// Host IP address or host name
	Host string `json:"host:omitempty"`
	// Port
	Port uint32 `json:"port"`
}
返回值:
- ProximaSearchClient: BE客户端对象
 - error: 执行错误时返回非nil
 
特殊说明:
- SDK中已封装了与BE通信的协议类型,如想进一步了解协议内容,请参考Restful API章节
 
示例: 创建BE客户端
package main
import (
	"log"
	"proxima-be-sdk-go/proxima/se/sdk"
)
func main() {
	// Create client of BE with GRPC protocol and connect to localhost:16000
	client, err := sdk.NewProximaSearchClient(sdk.GrpcProtocol, &sdk.Address{
		Host: "localhost",
		Port: 16000,
	})
	if err != nil {
		log.Fatal("Can't create ProximaClient instance.", err)
	}
}
2. 集合管理
2.1. 集合创建
CreateCollection(config *CollectionConfig) error
根据参数创建集合,创建成功后返回nil, 否则返回error。
参数说明:
- config: CollectionConfig中指定了集合的配置信息,包含不仅限于集合名、分片配置、正排列名、索引列信息等,当BE作为Mysql的从属库时,需指定Mysql Repo的相关配置,详情如示例。
 
返回值:
- error: 正常执行返回nil, 否则返回有效error对象
 
示例 1.1: 创建一个带有两个正排列,以及两个向量索引列的集合
fun createCollctionDemo(client *ProximaSearchClient) {
	// Create collection with no attached repository
	config := &sdk.CollectionConfig{
		CollectionName:    "example",
		MaxDocsPerSegment: 0, // 0 means unlimited, which is equal max value of system
		ForwardColumns:    []string{"forward", "forward1"},
		Columns: []sdk.ColumnIndex{
			{
				Name:        "column",
				IndexType:   0,                                     // 0 means default index, which is sdk.ProximaGraphIndex
				DataType:    0,                                     // 0 means default, which is sdk.VectorFP32
				Dimension:   8,                                     // Required field, no default value, 0 is not legal argument
				ExtraParams: map[string]string{"ef_search": "200"}, // Advanced params
			}, {
				Name:        "column1",
				IndexType:   sdk.ProximaGraphIndex,
				DataType:    sdk.VectorFP16, // Index type is fp16, query could be fp32 for lack of language types
				Dimension:   128,
				ExtraParams: map[string]string{},
			},
		},
		Repository: nil, // No repository attached
	}
	if err = client.CreateCollection(config); err != nil {
		log.Fatal("Can't create collection.", err)
	}
	log.Print("Create collection succeed.")
}
示例 1.2: 创建一个带有两个正排列、单个向量索引列、以及Mysql Repo的集合
fun createCollctionWithRepoDemo(client *ProximaSearchClient) {
	// Create collection with attached repository
	config := &sdk.CollectionConfig{
		CollectionName:    "example_with_repo",
		MaxDocsPerSegment: 0, // 0 means unlimited, which is equal max value of system
		ForwardColumns:    []string{"forward", "forward1"},
		Columns: []sdk.ColumnIndex{{
			Name:        "column1",
			IndexType:   0,                                     // 0 means default index, which is sdk.ProximaGraphIndex
			DataType:    0,                                     // 0 means default, which is sdk.VectorFP32
			Dimension:   512,                                   // Required field, no default value, 0 is not legal argument
			ExtraParams: map[string]string{"ef_search": "200"}, // Advanced params
		},
		},
		Repository: &sdk.DatabaseRepository{
			Repository: sdk.Repository{
				Name: "mysql_repo",
				Type: sdk.Database,
			},
			Connection: "mysql://host.com:8080/mysql_database", // JDBC connection uri
			TableName:  "table_name",                           // Table name
			User:       "root",                                 // User name
			Password:   "root",                                 // Password
		},
	}
	if err = client.CreateCollection(config); err != nil {
		log.Fatal("Can't create collection.", err)
	}
	log.Print("Create collection with attached mysql repository succeed.")
}
2.2. 获取集合配置信息
DescribeCollection(name string) (*CollectionInfo, error)
获取参数name指定的集合配置信息
参数说明:
- name: string指定集合名称
 
返回值:
- CollectionInfo: 指向CollectionInfo的指针,成功返回时该参数非nil, 失败时通过error参数判定失败原因
 - error: 失败返回非nil
 
示例 2.1: 获取集合配置信息
fun describeCollectionDemo(client *ProximaSearchClient) {
	// Retrieve collection named by 'example_with_repo'
	info, err = client.DescribeCollection("example_with_repo")
	if err != nil {
		log.Fatal("Lost collection named by 'example_with_repo', which created before.", err)
	}
	log.Printf("Collection(With Repository): %+v\n", info)
	// Delete collection
	if err = client.DropCollection("example_with_repo"); err != nil {
		log.Fatal("Failed to drop collection,", err)
	}
	log.Print("Drop collection succeed.")
}
2.3. 删除指定集合
DropCollection(name string) error
删除指定集合,集合名由参数name指定
参数说明:
- name: string指定集合名称
 
返回值:
- error: 失败返回非nil
 
示例 3.1: 删除集合
fun dropCollectionDemo(client *ProximaSearchClient) {
	client.DropCollection("example_with_repo")
	if err = client.CreateCollection(config); err != nil {
		log.Fatal("Can't create collection.", err)
	}
	log.Print("Create collection with attached mysql repository succeed.")
}
2.4. 获取集合统计信息
StatCollection(string) (*CollectionStat, error)
获取参数指定的集合统计信息,执行成功返回指向CollectionStat的有效指针,失败返回error
参数说明:
- string: 指定集合名称
 
返回值:
- *CollectionStat: Collection的统计信息
 - error: 失败返回非nil
 
示例 4.1: 获取集合统计信息
fun statCollectionDemo(client *ProximaSearchClient) {
	stat, err := client.StatCollection("example")
	if err != nil {
		log.Fatal("Stat collection failed.", err)
	}
	log.Printf("Collection Stat: %+v", stat)
}
2.5. 获取集合列表
ListCollections(filters …ListCollectionFilter) ([]*CollectionInfo, error)
获取符合条件的集合列表,执行成功返回CollectionInfo的列表,失败返回error
参数说明:
- ListCollectionFilter: 过滤器对象,过滤器可采用生成器自动生成,可选的生成器如下: - ByRepo(repo string): 包含指定repo名称的Collection
 
返回值:
- []*CollectionInfo: CollectionInfo列表
 - error: 失败返回非nil
 
示例 5.1: 获取集合列表
fun listCollectionsDemo(client *ProximaSearchClient) {
	// List all collections
	collections, err := client.ListCollections()
	if err != nil {
		log.Fatal("Can't retrieve collections from Proxima Server.", err)
	}
	log.Printf("Collections (%d): \n", len(collections))
	for _, collection := range collections {
		log.Printf("%+v\n", collection)
	}
	// List all collections by Repo
	collections, err = client.ListCollections(sdk.ByRepo("repo"))
	if err != nil {
		log.Fatal("Can't retrieve collections from Proxima Server.", err)
	}
	log.Printf("Collections (%d): \n", len(collections))
	for _, collection := range collections {
		log.Printf("%+v\n", collection)
	}
}
3. 文档管理
文档管理整合为一个通用接口Write, 通过接口参数描述所需的操作,接口定义如下:
Write(*WriteRequest) error
向BE中批量写入文档操作请求,执行成功后返回nil, 否则返回值error中描述了错误信息
参数说明:
- WriteRequest: 写入请求内容
 
// Row record
type Row struct {
	// Primary key of row record
	PrimaryKey uint64
	// Operation type
	OperationType
	// Index column value list
	IndexColumnValues []interface{}
	// Forward column value list
	ForwardColumnValues []interface{}
	// Log Sequence Number context
	*LsnContext
}
// RowMeta meta for row records
type RowMeta struct {
	// Index column name list
	IndexColumnNames []string
	// Index column name list
	ForwardColumnNames []string
}
// WriteRequest object, the parameter of ProximaBEClient.Write method
type WriteRequest struct {
	// Name of collection
	CollectionName string
	// Meta header
	Meta RowMeta
	// Row record list
	Rows []Row
	// Request ID, Optional
	RequestID string
	// Magic number, Optional
	MagicNumber uint64
}
Write API中根据传入参数的 Row.OperationType 判定当前数据是插入、删除、更新中的某种操作类型,可选的OperationType列表如下:
- **Insert: ** 新增文档
 - Update: 更新文档
 - Delete: 删除文档
 
返回值:
- error: 失败返回非nil
 
3.1. 文档插入
指定Row.OperationType为OPInsert可完成文档的插入操作
示例 1.1: 文档插入
fun insertDocumentDemo(client *ProximaSearchClient) {
	rows := &sdk.WriteRequest{
		CollectionName: "example",
		Meta: sdk.RowMeta{
			IndexColumnNames:   []string{"column"},
			ForwardColumnNames: []string{"forward", "forward1"},
		},
		Rows: []sdk.Row{
			{
				PrimaryKey:          0,
				OperationType:       sdk.Insert,
				ForwardColumnValues: []interface{}{1, float32(1.1)},
				IndexColumnValues: []interface{}{ // Data type should same with index created before
					[]float32{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0},
				},
				LsnContext: nil, // With empty context
			},
		},
		RequestID:   "", // Optional field
		MagicNumber: 0,  // Optional field
	}
	// Write rows to collection
	err = client.Write(rows)
	if err != nil {
		log.Fatal("Insert data to collection failed.", err)
	}
}
3.2. 文档更新
指定Row.OperationType为OPUpdate可完成文档的更新操作
示例 2.1:更新文档
fun updateDocumentDemo(client *ProximaSearchClient) {
	rows := &sdk.WriteRequest{
		CollectionName: "example",
		Meta: sdk.RowMeta{
			IndexColumnNames:   []string{"column"},
			ForwardColumnNames: []string{"forward", "forward1"},
		},
		Rows: []sdk.Row{
			{
				PrimaryKey:          0,
				OperationType:       sdk.Update,
				ForwardColumnValues: []interface{}{2, float32(2.2)},
				IndexColumnValues: []interface{}{ // Data type should same with index created before
					[]float32{21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0},
				},
				LsnContext: &sdk.LsnContext{ // With valid context
					LSN:     0,
					Context: "write context hear",
				},
			}},
		RequestID:   "", // Optional field
		MagicNumber: 0,  // Optional field
	}
	// Write rows to collection
	err = client.Write(rows)
	if err != nil {
		log.Fatal("Insert data to collection failed.", err)
	}
}
3.3. 文档删除
指定Row.OperationType为OPDelete可完成文档的删除操作
示例 3.1:删除文档
fun deleteDocumentDemo(client *ProximaSearchClient) {
	rows := &sdk.WriteRequest{
		CollectionName: "example",
		Meta: sdk.RowMeta{
			IndexColumnNames:   []string{"column"},
			ForwardColumnNames: []string{"forward", "forward1"},
		},
		Rows: []sdk.Row{
			{
				PrimaryKey:          0,
				OperationType:       sdk.Delete,
			},
		},
		RequestID:   "", // Optional field
		MagicNumber: 0,  // Optional field
	}
	// Write rows to collection
	err = client.Write(rows)
	if err != nil {
		log.Fatal("Insert data to collection failed.", err)
	}
}
3.4. 批量文档操作
请求中包含多行数据,并指定OperationType完成批量文档操作
示例 4.1:批量文档操作
fun batchDocumentOperationDemo(client *ProximaSearchClient) {
	rows := &sdk.WriteRequest{
		CollectionName: "example",
		Meta: sdk.RowMeta{
			IndexColumnNames:   []string{"column"},
			ForwardColumnNames: []string{"forward", "forward1"},
		},
		Rows: []sdk.Row{
			{
				PrimaryKey:          0,
				OperationType:       sdk.Insert,
				ForwardColumnValues: []interface{}{1, float32(1.1)},
				IndexColumnValues: []interface{}{ // Data type should same with index created before
					[]float32{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0},
				},
				LsnContext: nil, // With empty context
			}, {
				PrimaryKey:          2,
				OperationType:       sdk.Insert,
				ForwardColumnValues: []interface{}{2, float32(2.2)},
				IndexColumnValues: []interface{}{ // Data type should same with index created before
					[]float32{21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0},
				},
				LsnContext: &sdk.LsnContext{ // With valid context
					LSN:     0,
					Context: "write context hear",
				},
			}},
		RequestID:   "", // Optional field
		MagicNumber: 0,  // Optional field
	}
	// Write rows to collection
	err = client.Write(rows)
	if err != nil {
		log.Fatal("Insert data to collection failed.", err)
	}
}
4. 文档查询
4.1. 向量查询
Query(collection string, column string, features interface{}, opts …QueryOption) (*QueryResponse, error)
单次、批量向BE发起向量查询请求,执行成功返回QueryResponse的有效指针,失败返回error
参数说明:
- collection: string指定集合名称
 - column: string指定列名
 - features: 指定查询向量,该参数可以是切片、数组、或者二维矩阵(每行一个向量),向量中的原始数据类型支持int8/uint32/uint64/float32中的一种(由于语言限制,如果索引创建时数据类型配置为DTVectorFP16,请使用float32类型与BE交互,服务器端会自动进行类型转换)
 - opts:  QueryOption可选参数列表,可选的参数如下:
- WithTopK(int): 最近的邻居个数
 - WithRadius(float32): 搜索半径,可选区间为0~1的浮点数,越大召回效果上升、性能下降,越小召回效果下降、性能上升。当请求中同时打开暴力匹配选项,则此参数无效。
 - WithLinearSearch(): 暴力匹配选项,返回的为绝对topk结果(性能最低)
 - WithDebugMode(): 调试模式,将详细搜索的各阶段统计数据返回(不建议生产环境中打开)
 - WithParam(string, interface{}): 高级检索参数,可选配置项待发布
 
 
返回值:
- *QueryResponse: 最近邻的documents结果
 - error: 失败返回非nil
 
示例 1.1: 单次向量查询
fun queryDemo(client *ProximaSearchClient) {
	// Query one vector
	resp, err := client.Query("example", "column", []float32{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0}, sdk.WithTopK(10))
	if err != nil {
		log.Fatal("Query failed.", err)
	}
	log.Printf("Response: %+v\n", resp)
}
示例 1.2: 批量向量查询
fun batchQueryDemo(client *ProximaSearchClient) {
	// Query with matrix
	resp, err = client.Query("example", "column",
		[][]float32{{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0},
			{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0},
			{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0},
			{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0},
		},
		sdk.WithTopK(10),
		sdk.WithDebugMode(),    // Enable debug mode, do not recommend on product environments
		sdk.WithRadius(1.5),    // Search radius, no effect if sdk.WithLinearSearch enabled
		sdk.WithLinearSearch(), // Enable linear search
		sdk.WithParam("customize_param", 10),
		sdk.WithParam("customize_param2", 1.0),
		sdk.WithParam("customize_param3", "str"))
	if err != nil {
		log.Fatal("Query failed.", err)
	}
	log.Printf("Response: %+v\n", resp)
}
4.2. 主键查询
GetDocumentByKey(collection string, primaryKey uint64) (*Document, error)
通过文档主键获取文档,执行成功返回Document的有效指针,失败返回error
参数说明:
- collection: 集合名称
 - primaryKey: 文档主键
 
返回值:
- *Document: 文档对象
 - error: 失败返回非nil
 
示例 2.1: 根据文档主键获取文档内容
fun queryDocByPKDemo(client *ProximaSearchClient) {
	// Retrieve document by primary key
	doc, err := client.GetDocumentByKey("example", 0)
	if err != nil {
		log.Fatal("Failed to retrieve document from server.", err)
	}
	log.Printf("Document: %+v\n", doc)
}