Skip to content

Commit f342185

Browse files
author
Yinwei Li
committed
Update proto files.
Update proto files and add some releated struct fields due to the changes. Add alter_collection_field() Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> add collection apis: - alter_collection_properties - create_schema - describe_alias - drop_collection_properties - list_aliases - rename_collection Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> Add apis for query and partition What's changed: 1. client.rs: Add comment for list_aliases 2. collectoin.rs: Change the return type for describe_collection() from `collection` to `DescribeCollection`,containing more info than before,which now acts like pymilvus. 3. partitions.rs: Add load_partitions and release_partitions,following their options' struct. 4. query.rs: Add get() and it's following functions and struct,like extract_primary_field and pack_pks_expr,like pymilvus.Add options for query() to use and some build functions for QueryOptions. 5. test/: Change some settings and details to adapt to the changes above Why Change Some Struct: To catch up with pymivus,we need to approve optional params,so we need to change the option struct Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> Update search() and add hybrid_search() Update search() function following the pymilvus'api.Add hybrid_search() function and it's related structures and help_functions(). Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> Add query_iterator() in iterator and add an example file. Add the query_iterator() function which return an iterator on QueryResult,public api includs next().To do this,add two Error type in src/error.rs.To test functions with data,I modifed the create_test_collection() function in tests/common/mod.rs. Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> Add search_iterator() and example. Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> Add database apis. Add full database apis including create,alter,drop,etc. To add using_database(),I need to add a member to client Struct,db_interceptor.And changed some codes with respect to it. Then I add an example file to test the apis,which works well. Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> Add resource group apis. Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> Add apis in Management. Move some index apis to src/index/utils,and add some more apis.Add two Index type.Fix some related errors due to the change. Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> Add all apis for authentication. In this commit I've complete all the apis related to authentication,including users,role,privilege,privilege groups,etc. And I've added an example to show how to use these apis and test the apis to a certain extent. Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> Delete some unecessary 'use's in some file. Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> Add comments doc to query.rs Signed-off-by: Yinwei Li <yinwei.li@zilliz.com> [bugfix]Change AnnSearchRequest and The params settings for search and hybrid_search. Changed AnnSearchRequest's params from KeyValuePair to Vec<KeyValuePair> to enable different search options for different anns_field. Change the default params setting mothod,following pymilvus. Add some more graceful error handlers to raw_id.Now if the search result is null,the code will throw an error and continue to run. Signed-off-by: Yinwei Li <yinwei.li@zilliz.com>
1 parent 84ec674 commit f342185

36 files changed

+8874
-326
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ strum = "0.24"
2222
strum_macros = "0.24"
2323
base64 = "0.21.0"
2424
dashmap = "5.5.3"
25+
lazy_static = "1.4"
2526

2627
[build-dependencies]
2728
tonic-build = { version = "0.8.2", default-features = false, features = [

examples/authentication.rs

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
use milvus::client::{Client, ClientBuilder};
2+
use milvus::error::Result;
3+
4+
#[tokio::main]
5+
async fn main() -> Result<()> {
6+
let client = ClientBuilder::new("http://localhost:19530")
7+
.username("root")
8+
.password("Milvus")
9+
.build()
10+
.await?;
11+
//user test
12+
user_test(&client).await?;
13+
//role test
14+
role_test(&client).await?;
15+
//privilege test
16+
privilege_test(&client).await?;
17+
Ok(())
18+
}
19+
20+
async fn user_test(client: &Client) -> Result<()> {
21+
let user_name_a = "test_user_A";
22+
let user_name_b = "test_user_B";
23+
let password = "test_password";
24+
let new_password = "new_password";
25+
let old_password = "test_password";
26+
println!("========== Start user test ==========");
27+
//create user
28+
client.create_user(user_name_a, password).await?;
29+
client.create_user(user_name_b, password).await?;
30+
let res = client.list_users().await?;
31+
println!("After create users: {:?}", res);
32+
//describe user
33+
let res = client.describe_user(user_name_a).await?;
34+
println!("Describe user_a: {:?}", res);
35+
//update password
36+
client
37+
.update_password(user_name_a, old_password, new_password)
38+
.await?;
39+
//describe user
40+
let res = client.describe_user(user_name_a).await?;
41+
println!("After update password: {:?}", res);
42+
//drop user
43+
client.drop_user(user_name_a).await?;
44+
client.drop_user(user_name_b).await?;
45+
let res = client.list_users().await?;
46+
println!("After drop users: {:?}", res);
47+
println!("========== End user test ==========\n");
48+
Ok(())
49+
}
50+
51+
async fn role_test(client: &Client) -> Result<()> {
52+
let user_name_a = "test_user_a";
53+
let role_name_a = "test_role_A";
54+
let role_name_b = "test_role_B";
55+
let password = "test_password";
56+
println!("========== Start role test ==========");
57+
//create role
58+
client.create_role(role_name_a).await?;
59+
client.create_role(role_name_b).await?;
60+
let res = client.list_roles().await?;
61+
println!("After create roles: {:?}", res);
62+
//describe role
63+
let res = client.describe_role(role_name_a).await?;
64+
println!("Describe role_a: {:?}", res);
65+
//grant role
66+
client.create_user(user_name_a, password).await?;
67+
client.grant_role(user_name_a, role_name_a).await?;
68+
let res = client.describe_user(user_name_a).await?;
69+
println!("Grant role to user: {:?}", res);
70+
//revoke role
71+
client.revoke_role(user_name_a, role_name_a).await?;
72+
let res = client.describe_user(user_name_a).await?;
73+
println!("Revoke role from user: {:?}", res);
74+
//drop role
75+
client.drop_role(role_name_a, true).await?;
76+
client.drop_role(role_name_b, true).await?;
77+
let res = client.list_roles().await?;
78+
println!("After drop roles: {:?}", res);
79+
//drop user
80+
client.drop_user(user_name_a).await?;
81+
println!("========== End role test ==========\n");
82+
Ok(())
83+
}
84+
85+
async fn privilege_test(client: &Client) -> Result<()> {
86+
let privilege_group_name = "test_privilege_group";
87+
let privilege_name = "ShowCollections";
88+
let role_name = "test_role";
89+
let user_name = "test_user";
90+
let password = "test_password";
91+
println!("========== Start privilege test ==========");
92+
//create privilege group
93+
if client
94+
.list_privilege_groups()
95+
.await?
96+
.contains_key(&privilege_group_name.to_string())
97+
{
98+
client.drop_privilege_group(privilege_group_name).await?;
99+
}
100+
client.create_privilege_group(privilege_group_name).await?;
101+
let res = client.list_privilege_groups().await?;
102+
println!("After create privilege group: {:#?}", res);
103+
//create role
104+
if client.list_roles().await?.contains(&role_name.to_string()) {
105+
client.drop_role(role_name, true).await?;
106+
}
107+
client.create_role(role_name).await?;
108+
//create user
109+
if client.list_users().await?.contains(&user_name.to_string()) {
110+
client.drop_user(user_name).await?;
111+
}
112+
client.create_user(user_name, password).await?;
113+
//grant privilege
114+
client
115+
.grant_privilege(role_name, privilege_name, "Global", "*", None)
116+
.await?;
117+
let res = client.describe_role(role_name).await?;
118+
println!("After grant privilege: {:#?}", res);
119+
//add privilege to group
120+
client
121+
.add_privilege_to_group(privilege_group_name, vec![privilege_name.to_string()])
122+
.await?;
123+
let res = client.list_privilege_groups().await?;
124+
println!("After add privilege to group: {:#?}", res);
125+
//revoke privilege from group
126+
client
127+
.revoke_privilege_from_group(privilege_group_name, vec![privilege_name.to_string()])
128+
.await?;
129+
let res = client.list_privilege_groups().await?;
130+
println!("After revoke privilege from group: {:#?}", res);
131+
//revoke privilege
132+
client
133+
.revoke_privilege(role_name, "Global", "ShowCollections", "*", None)
134+
.await?;
135+
let res = client.describe_role(role_name).await?;
136+
println!("After revoke privilege: {:#?}", res);
137+
//drop privilege group
138+
client.drop_privilege_group(privilege_group_name).await?;
139+
let res = client.list_privilege_groups().await?;
140+
println!("After drop privilege group: {:#?}", res);
141+
//drop role
142+
client.drop_role(role_name, true).await?;
143+
client.drop_user(user_name).await?;
144+
println!("========== End privilege test ==========\n");
145+
Ok(())
146+
}

examples/database.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use milvus::error::Result;
2+
use milvus::schema::{CollectionSchemaBuilder, FieldSchema};
3+
use milvus::{client::Client, database::CreateDbOptions};
4+
5+
const TEST_NAME_A: &str = "test_database_A";
6+
const TEST_NAME_B: &str = "test_database_B";
7+
8+
#[tokio::main]
9+
async fn main() -> Result<()> {
10+
let mut client = Client::new("http://localhost:19530").await?;
11+
12+
//create database with properties
13+
let db_properties = CreateDbOptions::new().replica_number(1).max_collections(3);
14+
client
15+
.create_database(TEST_NAME_A, Some(db_properties))
16+
.await?;
17+
let db_properties = CreateDbOptions::new().replica_number(1).max_collections(3);
18+
client
19+
.create_database(TEST_NAME_B, Some(db_properties))
20+
.await?;
21+
22+
//list database
23+
let res = client.list_databases().await?;
24+
println!("After create databases:{:?}", res);
25+
26+
//describe database
27+
let res = client.describe_database(TEST_NAME_A).await?;
28+
println!("Describe database_A : \n{:#?}", res);
29+
30+
//alter database properties
31+
let options = CreateDbOptions::new().replica_number(0).max_collections(2);
32+
client
33+
.alter_database_properties(TEST_NAME_A, options)
34+
.await?;
35+
let res = client.describe_database(TEST_NAME_A).await?;
36+
println!("After alter database_A properties:\n{:#?}\n", res);
37+
38+
//using database
39+
let collection_name_a = "collection_A";
40+
let collection_name_b = "collection_B";
41+
let schema_a = CollectionSchemaBuilder::new(collection_name_a, "For database test")
42+
.add_field(FieldSchema::new_primary_int64("id", "", true))
43+
.add_field(FieldSchema::new_float_vector("vector_A", "", 128))
44+
.build()?;
45+
let schema_b = CollectionSchemaBuilder::new(collection_name_b, "For database test")
46+
.add_field(FieldSchema::new_primary_int64("id", "", true))
47+
.add_field(FieldSchema::new_float_vector("vector_B", "", 128))
48+
.build()?;
49+
//use db_A
50+
client.using_database(TEST_NAME_A).await?;
51+
client.create_collection(schema_a, None).await?;
52+
let res = client.list_collections().await?;
53+
println!("Database A collections: {:?} ", res);
54+
client.drop_collection(collection_name_a).await?;
55+
//use db_B
56+
client.using_database(TEST_NAME_B).await?;
57+
client.create_collection(schema_b, None).await?;
58+
let res = client.list_collections().await?;
59+
println!("Database B collections: {:?}", res);
60+
//drop database
61+
client.drop_collection(collection_name_b).await?;
62+
63+
client.drop_database(TEST_NAME_A).await?;
64+
client.drop_database(TEST_NAME_B).await?;
65+
let res = client.list_databases().await?;
66+
println!("After drop database A and B there are databases: {:?}", res);
67+
Ok(())
68+
}

examples/index_example.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
use milvus::{
2+
client::Client,
3+
data::FieldColumn,
4+
index::{IndexParams, IndexType, MetricType},
5+
options::LoadOptions,
6+
query::QueryOptions,
7+
schema::{CollectionSchemaBuilder, FieldSchema},
8+
};
9+
use rand::Rng;
10+
use std::collections::HashMap;
11+
12+
const DIM: i64 = 8;
13+
const COLLECTION_NAME: &str = "hello_milvus";
14+
15+
#[tokio::main]
16+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
17+
let client = Client::new("http://localhost:19530").await?;
18+
19+
if client.has_collection(COLLECTION_NAME).await? {
20+
println!("Dropping existing collection: {}", COLLECTION_NAME);
21+
client.drop_collection(COLLECTION_NAME).await?;
22+
}
23+
24+
let mut schema = CollectionSchemaBuilder::new(COLLECTION_NAME, "Hello Milvus collection");
25+
schema
26+
.add_field(FieldSchema::new_primary_int64("id", "", true)) // is_primary = true
27+
.add_field(FieldSchema::new_float_vector("embeddings", "", DIM))
28+
.add_field(FieldSchema::new_varchar("title", "", 64))
29+
.enable_dynamic_field();
30+
31+
let schema = schema.build()?;
32+
33+
println!("Creating collection");
34+
client.create_collection(schema.clone(), None).await?;
35+
36+
println!("Start inserting entities");
37+
let mut rng = rand::thread_rng();
38+
39+
let mut embeddings_data = Vec::new();
40+
let mut title_data = Vec::new();
41+
42+
for i in 1..=6 {
43+
embeddings_data.extend((0..DIM).map(|_| rng.gen::<f32>()));
44+
title_data.push(format!("t{}", i));
45+
}
46+
47+
let embeddings_col = FieldColumn::new(schema.get_field("embeddings").unwrap(), embeddings_data);
48+
let title_col = FieldColumn::new(schema.get_field("title").unwrap(), title_data);
49+
50+
let insert_result = client
51+
.insert(COLLECTION_NAME, vec![embeddings_col, title_col], None)
52+
.await?;
53+
println!("Inserting entities done");
54+
println!("Insert result: {:?}", insert_result);
55+
56+
client.flush(COLLECTION_NAME).await?;
57+
58+
println!("Start create index for embeddings");
59+
let index_params = IndexParams::new(
60+
"embeddings_index".to_string(),
61+
IndexType::IvfFlat,
62+
MetricType::L2,
63+
HashMap::from([("nlist".to_string(), "32".to_string())]),
64+
);
65+
client
66+
.create_index(COLLECTION_NAME, "embeddings", index_params)
67+
.await?;
68+
69+
println!("Start create index for title");
70+
let title_index_params = IndexParams::new(
71+
"my_trie".to_string(),
72+
IndexType::Trie,
73+
MetricType::L2,
74+
HashMap::new(),
75+
);
76+
client
77+
.create_index(COLLECTION_NAME, "title", title_index_params)
78+
.await?;
79+
80+
let index_names = client.list_indexes(COLLECTION_NAME, None).await?;
81+
println!("Index names for {}: {:?}", COLLECTION_NAME, index_names);
82+
83+
for index_name in &index_names {
84+
let index_info = client.describe_index(COLLECTION_NAME, index_name).await?;
85+
println!("Index info for index {}: {:?}", index_name, index_info);
86+
}
87+
88+
println!("Start load collection");
89+
client
90+
.load_collection(COLLECTION_NAME, Some(LoadOptions::default()))
91+
.await?;
92+
93+
println!("Start query by specifying primary keys");
94+
let query_options = QueryOptions::default();
95+
let query_results = client
96+
.query(COLLECTION_NAME, "id == 2", &query_options)
97+
.await?;
98+
if let Some(result) = query_results.first() {
99+
println!("Query result: {:?}", result);
100+
}
101+
102+
println!("Start query by specifying filtering expression");
103+
let query_results = client
104+
.query(COLLECTION_NAME, "title == 't2'", &query_options)
105+
.await?;
106+
for ret in query_results {
107+
println!("Query result: {:?}", ret);
108+
}
109+
110+
let field_index_names = client
111+
.list_indexes(COLLECTION_NAME, Some("embeddings"))
112+
.await?;
113+
println!(
114+
"Index names for {}'s field embeddings: {:?}",
115+
COLLECTION_NAME, field_index_names
116+
);
117+
118+
println!("Try to drop index");
119+
client.release_collection(COLLECTION_NAME).await?;
120+
121+
match client.drop_index(COLLECTION_NAME, "my_trie").await {
122+
Ok(_) => println!("Successfully dropped index for title field"),
123+
Err(e) => println!("Caught error when dropping index: {}", e),
124+
}
125+
126+
match client.drop_index(COLLECTION_NAME, "my_trie").await {
127+
Ok(_) => println!("Successfully dropped index for title field"),
128+
Err(e) => println!("Caught error when dropping index: {}", e),
129+
}
130+
131+
client.drop_collection(COLLECTION_NAME).await?;
132+
133+
println!("Example completed successfully!");
134+
Ok(())
135+
}

0 commit comments

Comments
 (0)