@@ -51,7 +51,8 @@ public class UpsertExample {
5151 private static final String ID_FIELD = "pk" ;
5252 private static final String VECTOR_FIELD = "vector" ;
5353 private static final String TEXT_FIELD = "text" ;
54- private static final Integer VECTOR_DIM = 128 ;
54+ private static final String NULLABLE_FIELD = "nullable" ;
55+ private static final Integer VECTOR_DIM = 4 ;
5556
5657 private static List <Object > createCollection (boolean autoID ) {
5758 // Drop collection if exists
@@ -78,6 +79,11 @@ private static List<Object> createCollection(boolean autoID) {
7879 .dataType (DataType .VarChar )
7980 .maxLength (100 )
8081 .build ());
82+ collectionSchema .addField (AddFieldReq .builder ()
83+ .fieldName (NULLABLE_FIELD )
84+ .dataType (DataType .Int32 )
85+ .isNullable (true )
86+ .build ());
8187
8288 List <IndexParam > indexes = new ArrayList <>();
8389 indexes .add (IndexParam .builder ()
@@ -106,6 +112,7 @@ private static List<Object> createCollection(boolean autoID) {
106112 List <Float > vector = CommonUtils .generateFloatVector (VECTOR_DIM );
107113 row .add (VECTOR_FIELD , gson .toJsonTree (vector ));
108114 row .addProperty (TEXT_FIELD , String .format ("text_%d" , i ));
115+ row .addProperty (NULLABLE_FIELD , i );
109116 rows .add (row );
110117 }
111118 InsertResp resp = client .insert (InsertReq .builder ()
@@ -119,7 +126,7 @@ private static void queryWithExpr(String expr) {
119126 QueryResp queryRet = client .query (QueryReq .builder ()
120127 .collectionName (COLLECTION_NAME )
121128 .filter (expr )
122- .outputFields (Arrays .asList (ID_FIELD , TEXT_FIELD ))
129+ .outputFields (Arrays .asList (ID_FIELD , VECTOR_FIELD , TEXT_FIELD , NULLABLE_FIELD ))
123130 .consistencyLevel (ConsistencyLevel .STRONG )
124131 .build ());
125132 System .out .println ("\n Query with expression: " + expr );
@@ -130,34 +137,79 @@ private static void queryWithExpr(String expr) {
130137 }
131138
132139 private static void doUpsert (boolean autoID ) {
133- // if autoID is true, the collection primary key is auto-generated by server
140+ System .out .printf ("\n ============================= autoID = %s =============================" , autoID ? "true" : "false" );
141+ // If autoID is true, the collection primary key is auto-generated by server
134142 List <Object > ids = createCollection (autoID );
135143
136- // query before upsert
137- Long testID = (Long )ids .get (1 );
138- String filter = String .format ("%s == %d" , ID_FIELD , testID );
139- queryWithExpr (filter );
140-
141- // upsert
142- // the server will return a new primary key, the old entity is deleted,
143- // and a new entity is created with the new primary key
144144 Gson gson = new Gson ();
145- JsonObject row = new JsonObject ();
146- row .addProperty (ID_FIELD , testID );
147- List <Float > vector = CommonUtils .generateFloatVector (VECTOR_DIM );
148- row .add (VECTOR_FIELD , gson .toJsonTree (vector ));
149- row .addProperty (TEXT_FIELD , "this field has been updated" );
150- UpsertResp upsertResp = client .upsert (UpsertReq .builder ()
151- .collectionName (COLLECTION_NAME )
152- .data (Collections .singletonList (row ))
153- .build ());
154- List <Object > newIds = upsertResp .getPrimaryKeys ();
155- Long newID = (Long )newIds .get (0 );
156- System .out .println ("\n Upsert done" );
145+ {
146+ // Query before upsert, get the No.2 primary key
147+ Long oldID = (Long ) ids .get (1 );
148+ String filter = String .format ("%s == %d" , ID_FIELD , oldID );
149+ queryWithExpr (filter );
150+
151+ // Upsert, update all fields value
152+ // If autoID is true, the server will return a new primary key for the updated entity
153+ JsonObject row = new JsonObject ();
154+ row .addProperty (ID_FIELD , oldID );
155+ List <Float > vector = Arrays .asList (1.0f , 1.0f , 1.0f , 1.0f );
156+ row .add (VECTOR_FIELD , gson .toJsonTree (vector ));
157+ row .addProperty (TEXT_FIELD , "this field has been updated" );
158+ row .add (NULLABLE_FIELD , null ); // update nullable field to null
159+ UpsertResp upsertResp = client .upsert (UpsertReq .builder ()
160+ .collectionName (COLLECTION_NAME )
161+ .data (Collections .singletonList (row ))
162+ .build ());
163+ List <Object > newIds = upsertResp .getPrimaryKeys ();
164+ Long newID = (Long ) newIds .get (0 );
165+ System .out .printf ("\n Upsert done, primary key %d has been updated to %d%n" , oldID , newID );
166+
167+ // Query after upsert, you will see the vector field is [1.0f, 1.0f, 1.0f, 1.0f],
168+ // text field is "this field has been updated", nullable field is null
169+ filter = String .format ("%s == %d" , ID_FIELD , newID );
170+ queryWithExpr (filter );
171+ }
157172
158- // query after upsert
159- filter = String .format ("%s == %d" , ID_FIELD , newID );
160- queryWithExpr (filter );
173+ {
174+ // Query before upsert, get the No.5 and No.6 primary key
175+ Long oldID1 = (Long )ids .get (4 );
176+ Long oldID2 = (Long )ids .get (5 );
177+ String filter = String .format ("%s in [%d, %d]" , ID_FIELD , oldID1 , oldID2 );
178+ queryWithExpr (filter );
179+
180+ // Partial upsert, only update the specified field, other fields will keep old values
181+ // If autoID is true, the server will return a new primary key for the updated entity
182+ // Note: for the case to do partial upsert for multi entities, it only allows updating
183+ // the same fields for all rows.
184+ // For example, assume a collection has 2 fields: A and B
185+ // it is legal to update the same fields as: client.upsert(data = [ {"A": 1}, {"A": 3}])
186+ // it is illegal to update different fields as: client.upsert(data = [ {"A": 1}, {"B": 3}])
187+ // Read the doc for more info: https://milvus.io/docs/upsert-entities.md
188+ // Here we update the same field "text" for the two rows.
189+ JsonObject row1 = new JsonObject ();
190+ row1 .addProperty (ID_FIELD , oldID1 );
191+ row1 .addProperty (TEXT_FIELD , "this row has been partially updated" );
192+
193+ JsonObject row2 = new JsonObject ();
194+ row2 .addProperty (ID_FIELD , oldID2 );
195+ row2 .addProperty (TEXT_FIELD , "this row has been partially updated" );
196+
197+ UpsertResp upsertResp = client .upsert (UpsertReq .builder ()
198+ .collectionName (COLLECTION_NAME )
199+ .data (Arrays .asList (row1 , row2 ))
200+ .partialUpdate (true )
201+ .build ());
202+ List <Object > newIds = upsertResp .getPrimaryKeys ();
203+ Long newID1 = (Long ) newIds .get (0 );
204+ Long newID2 = (Long ) newIds .get (1 );
205+ System .out .printf ("\n Partial upsert done, primary key %d has been updated to %d, %d has been updated to %d%n" ,
206+ oldID1 , newID1 , oldID2 , newID2 );
207+
208+ // query after upsert, you will see the text field is "this row has been partially updated"
209+ // the other fields keep old values
210+ filter = String .format ("%s in [%d, %d]" , ID_FIELD , newID1 , newID2 );
211+ queryWithExpr (filter );
212+ }
161213 }
162214
163215 public static void main (String [] args ) {
0 commit comments