@@ -33,6 +33,7 @@ public class HnswIndex<TId, TVector, TItem extends Item<TId, TVector>, TDistance
3333 implements Index <TId , TVector , TItem , TDistance > {
3434
3535 private static final byte VERSION_1 = 0x01 ;
36+ private static final byte VERSION_2 = 0x02 ;
3637
3738 private static final long serialVersionUID = 1L ;
3839
@@ -42,6 +43,7 @@ public class HnswIndex<TId, TVector, TItem extends Item<TId, TVector>, TDistance
4243 private Comparator <TDistance > distanceComparator ;
4344 private MaxValueComparator <TDistance > maxValueDistanceComparator ;
4445
46+ private boolean immutable ;
4547 private int dimensions ;
4648 private int maxItemCount ;
4749 private int m ;
@@ -74,6 +76,7 @@ public class HnswIndex<TId, TVector, TItem extends Item<TId, TVector>, TDistance
7476
7577 private HnswIndex (RefinedBuilder <TId , TVector , TItem , TDistance > builder ) {
7678
79+ this .immutable = builder .immutable ;
7780 this .dimensions = builder .dimensions ;
7881 this .maxItemCount = builder .maxItemCount ;
7982 this .distanceFunction = builder .distanceFunction ;
@@ -202,6 +205,9 @@ public boolean remove(TId id, long version) {
202205 */
203206 @ Override
204207 public boolean add (TItem item ) {
208+ if (immutable ) {
209+ throw new UnsupportedOperationException ("Index is immutable" );
210+ }
205211 if (item .dimensions () != dimensions ) {
206212 throw new IllegalArgumentException ("Item does not have dimensionality of : " + dimensions );
207213 }
@@ -757,7 +763,7 @@ public void save(OutputStream out) throws IOException {
757763 }
758764
759765 private void writeObject (ObjectOutputStream oos ) throws IOException {
760- oos .writeByte (VERSION_1 );
766+ oos .writeByte (VERSION_2 );
761767 oos .writeInt (dimensions );
762768 oos .writeObject (distanceFunction );
763769 oos .writeObject (distanceComparator );
@@ -776,6 +782,7 @@ private void writeObject(ObjectOutputStream oos) throws IOException {
776782 writeMutableObjectLongMap (oos , deletedItemVersions );
777783 writeNodesArray (oos , nodes );
778784 oos .writeInt (entryPoint == null ? -1 : entryPoint .id );
785+ oos .writeBoolean (immutable );
779786 }
780787
781788 @ SuppressWarnings ("unchecked" )
@@ -802,6 +809,8 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound
802809 this .nodes = readNodesArray (ois , itemSerializer , maxM0 , maxM );
803810
804811 int entrypointNodeId = ois .readInt ();
812+
813+ this .immutable = version != VERSION_1 && ois .readBoolean ();
805814 this .entryPoint = entrypointNodeId == -1 ? null : nodes .get (entrypointNodeId );
806815
807816 this .globalLock = new ReentrantLock ();
@@ -1069,7 +1078,26 @@ public static <TVector, TDistance extends Comparable<TDistance>> Builder<TVector
10691078
10701079 Comparator <TDistance > distanceComparator = Comparator .naturalOrder ();
10711080
1072- return new Builder <>(dimensions , distanceFunction , distanceComparator , maxItemCount );
1081+ return new Builder <>(false , dimensions , distanceFunction , distanceComparator , maxItemCount );
1082+ }
1083+
1084+ /**
1085+ * Creates an immutable empty index.
1086+ *
1087+ * @return the empty index
1088+ * @param <TId> Type of the external identifier of an item
1089+ * @param <TVector> Type of the vector to perform distance calculation on
1090+ * @param <TItem> Type of items stored in the index
1091+ * @param <TDistance> Type of distance between items (expect any numeric type: float, double, int, ..)
1092+ */
1093+ public static <TId , TVector , TItem extends Item <TId , TVector >, TDistance > HnswIndex <TId , TVector , TItem , TDistance > empty () {
1094+ Builder <TVector , TDistance > builder = new Builder <>(true , 0 , new DistanceFunction <TVector , TDistance >() {
1095+ @ Override
1096+ public TDistance distance (TVector u , TVector v ) {
1097+ throw new UnsupportedOperationException ();
1098+ }
1099+ }, new DummyComparator <>(), 0 );
1100+ return builder .build ();
10731101 }
10741102
10751103 /**
@@ -1089,7 +1117,7 @@ public static <TVector, TDistance> Builder<TVector, TDistance> newBuilder(
10891117 Comparator <TDistance > distanceComparator ,
10901118 int maxItemCount ) {
10911119
1092- return new Builder <>(dimensions , distanceFunction , distanceComparator , maxItemCount );
1120+ return new Builder <>(false , dimensions , distanceFunction , distanceComparator , maxItemCount );
10931121 }
10941122
10951123 private int assignLevel (TId value , double lambda ) {
@@ -1318,6 +1346,7 @@ public static abstract class BuilderBase<TBuilder extends BuilderBase<TBuilder,
13181346 public static final int DEFAULT_EF_CONSTRUCTION = 200 ;
13191347 public static final boolean DEFAULT_REMOVE_ENABLED = false ;
13201348
1349+ boolean immutable ;
13211350 int dimensions ;
13221351 DistanceFunction <TVector , TDistance > distanceFunction ;
13231352 Comparator <TDistance > distanceComparator ;
@@ -1329,11 +1358,12 @@ public static abstract class BuilderBase<TBuilder extends BuilderBase<TBuilder,
13291358 int efConstruction = DEFAULT_EF_CONSTRUCTION ;
13301359 boolean removeEnabled = DEFAULT_REMOVE_ENABLED ;
13311360
1332- BuilderBase (int dimensions ,
1361+ BuilderBase (boolean immutable ,
1362+ int dimensions ,
13331363 DistanceFunction <TVector , TDistance > distanceFunction ,
13341364 Comparator <TDistance > distanceComparator ,
13351365 int maxItemCount ) {
1336-
1366+ this . immutable = immutable ;
13371367 this .dimensions = dimensions ;
13381368 this .distanceFunction = distanceFunction ;
13391369 this .distanceComparator = distanceComparator ;
@@ -1417,12 +1447,13 @@ public static class Builder<TVector, TDistance> extends BuilderBase<Builder<TVec
14171447 * @param distanceFunction the distance function
14181448 * @param maxItemCount the maximum number of elements in the index
14191449 */
1420- Builder (int dimensions ,
1450+ Builder (boolean immutable ,
1451+ int dimensions ,
14211452 DistanceFunction <TVector , TDistance > distanceFunction ,
14221453 Comparator <TDistance > distanceComparator ,
14231454 int maxItemCount ) {
14241455
1425- super (dimensions , distanceFunction , distanceComparator , maxItemCount );
1456+ super (immutable , dimensions , distanceFunction , distanceComparator , maxItemCount );
14261457 }
14271458
14281459 @ Override
@@ -1440,7 +1471,7 @@ Builder<TVector, TDistance> self() {
14401471 * @return the builder
14411472 */
14421473 public <TId , TItem extends Item <TId , TVector >> RefinedBuilder <TId , TVector , TItem , TDistance > withCustomSerializers (ObjectSerializer <TId > itemIdSerializer , ObjectSerializer <TItem > itemSerializer ) {
1443- return new RefinedBuilder <>(dimensions , distanceFunction , distanceComparator , maxItemCount , m , ef , efConstruction ,
1474+ return new RefinedBuilder <>(immutable , dimensions , distanceFunction , distanceComparator , maxItemCount , m , ef , efConstruction ,
14441475 removeEnabled , itemIdSerializer , itemSerializer );
14451476 }
14461477
@@ -1475,7 +1506,8 @@ public static class RefinedBuilder<TId, TVector, TItem extends Item<TId, TVector
14751506 private ObjectSerializer <TId > itemIdSerializer ;
14761507 private ObjectSerializer <TItem > itemSerializer ;
14771508
1478- RefinedBuilder (int dimensions ,
1509+ RefinedBuilder (boolean immutable ,
1510+ int dimensions ,
14791511 DistanceFunction <TVector , TDistance > distanceFunction ,
14801512 Comparator <TDistance > distanceComparator ,
14811513 int maxItemCount ,
@@ -1486,7 +1518,7 @@ public static class RefinedBuilder<TId, TVector, TItem extends Item<TId, TVector
14861518 ObjectSerializer <TId > itemIdSerializer ,
14871519 ObjectSerializer <TItem > itemSerializer ) {
14881520
1489- super (dimensions , distanceFunction , distanceComparator , maxItemCount );
1521+ super (immutable , dimensions , distanceFunction , distanceComparator , maxItemCount );
14901522
14911523 this .m = m ;
14921524 this .ef = ef ;
0 commit comments