Skip to content

Commit b058d21

Browse files
kiplingwilyajob05
authored andcommitted
hnswlib/{bruteforce,hnswalg}.h: Added new generic serial / deserialization interfaces for HierarchicalNSW and BruteforceSearch...
README.md: Noted new serial / deserialization interfaces... setup.py: Bumped patch version because new interfaces introduced...
1 parent 2fba7fb commit b058d21

4 files changed

Lines changed: 52 additions & 22 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ Header-only C++ HNSW implementation with python bindings, insertions and updates
33

44
**NEWS:**
55

6+
**version 0.8.1**
7+
8+
* Added generic serialization / deserialization interfaces for HierarchicalNSW and BruteforceSearch that take `std::ostream` / `std::istream` arguments
9+
610
**version 0.8.0**
711

812
* Multi-vector document search and epsilon search (for now, only in C++)

hnswlib/bruteforce.h

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <mutex>
88
#include <algorithm>
99
#include <assert.h>
10+
#include <iostream>
1011

1112
namespace hnswlib {
1213
template<typename dist_t>
@@ -130,25 +131,30 @@ class BruteforceSearch : public AlgorithmInterface<dist_t> {
130131
}
131132

132133

133-
Status saveIndexNoExceptions(const std::string &location) override {
134-
std::ofstream output(location, std::ios::binary);
135-
std::streampos position;
136-
134+
Status saveIndexNoExceptions(std::ostream &output) {
137135
writeBinaryPOD(output, maxelements_);
138136
writeBinaryPOD(output, size_per_element_);
139137
writeBinaryPOD(output, cur_element_count);
140138

141139
output.write(data_, maxelements_ * size_per_element_);
140+
return OkStatus();
141+
}
142+
143+
144+
Status saveIndexNoExceptions(const std::string &location) override {
145+
std::ofstream output(location, std::ios::binary);
146+
147+
Status status = saveIndexNoExceptions(output);
148+
if (!status.ok()) {
149+
HNSWLIB_THROW_RUNTIME_ERROR(status.message());
150+
}
142151

143152
output.close();
144153
return OkStatus();
145154
}
146155

147156

148-
void loadIndex(const std::string &location, SpaceInterface<dist_t> *s) {
149-
std::ifstream input(location, std::ios::binary);
150-
std::streampos position;
151-
157+
void loadIndex(std::istream &input, SpaceInterface<dist_t> *s) {
152158
readBinaryPOD(input, maxelements_);
153159
readBinaryPOD(input, size_per_element_);
154160
readBinaryPOD(input, cur_element_count);
@@ -162,6 +168,13 @@ class BruteforceSearch : public AlgorithmInterface<dist_t> {
162168
HNSWLIB_THROW_RUNTIME_ERROR("Not enough memory: loadIndex failed to allocate data");
163169

164170
input.read(data_, maxelements_ * size_per_element_);
171+
}
172+
173+
174+
void loadIndex(const std::string &location, SpaceInterface<dist_t> *s) {
175+
std::ifstream input(location, std::ios::binary);
176+
177+
loadIndex(input, s);
165178

166179
input.close();
167180
}

hnswlib/hnswalg.h

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <stdlib.h>
88

99
#include <atomic>
10+
#include <iostream>
1011
#include <limits>
1112
#include <list>
1213
#include <memory>
@@ -723,10 +724,7 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
723724
return size;
724725
}
725726

726-
Status saveIndexNoExceptions(const std::string &location) override {
727-
728-
std::ofstream output(location, std::ios::binary);
729-
727+
Status saveIndexNoExceptions(std::ostream &output) {
730728
writeBinaryPOD(output, offsetLevel0_);
731729
writeBinaryPOD(output, max_elements_);
732730
writeBinaryPOD(output, cur_element_count);
@@ -750,24 +748,22 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
750748
if (linkListSize)
751749
output.write(linkLists_[i], linkListSize);
752750
}
753-
output.close();
754751
return OkStatus();
755752
}
756753

757754

758-
void loadIndex(const std::string &location, SpaceInterface<dist_t> *s, size_t max_elements_i = 0) {
759-
Status status = loadIndexNoExceptions(location, s, max_elements_i);
755+
Status saveIndexNoExceptions(const std::string &location) override {
756+
std::ofstream output(location, std::ios::binary);
757+
Status status = saveIndexNoExceptions(output);
760758
if (!status.ok()) {
761759
HNSWLIB_THROW_RUNTIME_ERROR(status.message());
762760
}
761+
output.close();
762+
return OkStatus();
763763
}
764764

765-
Status loadIndexNoExceptions(const std::string &location, SpaceInterface<dist_t> *s, size_t max_elements_i = 0) {
766-
std::ifstream input(location, std::ios::binary);
767-
768-
if (!input.is_open())
769-
return Status("Cannot open file");
770765

766+
Status loadIndexNoExceptions(std::istream &input, SpaceInterface<dist_t> *s, size_t max_elements_i = 0) {
771767
clear();
772768
// get file size:
773769
input.seekg(0, input.end);
@@ -865,11 +861,28 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
865861
}
866862
}
867863

864+
return OkStatus();
865+
}
866+
867+
868+
869+
void loadIndex(const std::string &location, SpaceInterface<dist_t> *s, size_t max_elements_i = 0) {
870+
std::ifstream input(location, std::ios::binary);
871+
872+
if (!input.is_open())
873+
throw std::runtime_error("Cannot open file");
874+
875+
Status status = loadIndexNoExceptions(input, s, max_elements_i);
876+
if (!status.ok()) {
877+
HNSWLIB_THROW_RUNTIME_ERROR(status.message());
878+
}
879+
868880
input.close();
869881

870-
return OkStatus();
882+
return;
871883
}
872884

885+
873886
template<typename data_t>
874887
std::vector<data_t>
875888
getDataByLabel(labeltype label) const {

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from setuptools import Extension, setup
99
from setuptools.command.build_ext import build_ext
1010

11-
__version__ = '0.8.0'
11+
__version__ = '0.8.1'
1212

1313

1414
include_dirs = [

0 commit comments

Comments
 (0)