in jni/src/nmslib_wrapper.cpp [30:136]
void knn_jni::nmslib_wrapper::CreateIndex(knn_jni::JNIUtilInterface * jniUtil, JNIEnv * env, jintArray idsJ,
jobjectArray vectorsJ, jstring indexPathJ, jobject parametersJ) {
if (idsJ == nullptr) {
throw std::runtime_error("IDs cannot be null");
}
if (vectorsJ == nullptr) {
throw std::runtime_error("Vectors cannot be null");
}
if (indexPathJ == nullptr) {
throw std::runtime_error("Index path cannot be null");
}
if (parametersJ == nullptr) {
throw std::runtime_error("Parameters cannot be null");
}
// Handle parameters
auto parametersCpp = jniUtil->ConvertJavaMapToCppMap(env, parametersJ);
std::vector<std::string> indexParameters;
// Algorithm parameters will be in a sub map
if(parametersCpp.find(knn_jni::PARAMETERS) != parametersCpp.end()) {
jobject subParametersJ = parametersCpp[knn_jni::PARAMETERS];
auto subParametersCpp = jniUtil->ConvertJavaMapToCppMap(env, subParametersJ);
if(subParametersCpp.find(knn_jni::EF_CONSTRUCTION) != subParametersCpp.end()) {
auto efConstruction = jniUtil->ConvertJavaObjectToCppInteger(env, subParametersCpp[knn_jni::EF_CONSTRUCTION]);
indexParameters.push_back(knn_jni::EF_CONSTRUCTION_NMSLIB + "=" + std::to_string(efConstruction));
}
if(subParametersCpp.find(knn_jni::M) != subParametersCpp.end()) {
auto m = jniUtil->ConvertJavaObjectToCppInteger(env, subParametersCpp[knn_jni::M]);
indexParameters.push_back(knn_jni::M_NMSLIB + "=" + std::to_string(m));
}
jniUtil->DeleteLocalRef(env, subParametersJ);
}
if(parametersCpp.find(knn_jni::INDEX_THREAD_QUANTITY) != parametersCpp.end()) {
auto indexThreadQty = jniUtil->ConvertJavaObjectToCppInteger(env, parametersCpp[knn_jni::INDEX_THREAD_QUANTITY]);
indexParameters.push_back(knn_jni::INDEX_THREAD_QUANTITY + "=" + std::to_string(indexThreadQty));
}
jniUtil->DeleteLocalRef(env, parametersJ);
// Get the path to save the index
std::string indexPathCpp(jniUtil->ConvertJavaStringToCppString(env, indexPathJ));
// Get space type for this index
jobject spaceTypeJ = knn_jni::GetJObjectFromMapOrThrow(parametersCpp, knn_jni::SPACE_TYPE);
std::string spaceTypeCpp(jniUtil->ConvertJavaObjectToCppString(env, spaceTypeJ));
spaceTypeCpp = TranslateSpaceType(spaceTypeCpp);
std::unique_ptr<similarity::Space<float>> space;
space.reset(similarity::SpaceFactoryRegistry<float>::Instance().CreateSpace(spaceTypeCpp,similarity::AnyParams()));
// Get number of ids and vectors and dimension
int numVectors = jniUtil->GetJavaObjectArrayLength(env, vectorsJ);
int numIds = jniUtil->GetJavaIntArrayLength(env, idsJ);
if (numIds != numVectors) {
throw std::runtime_error("Number of IDs does not match number of vectors");
}
int dim = jniUtil->GetInnerDimensionOf2dJavaFloatArray(env, vectorsJ);
// Read dataset
similarity::ObjectVector dataset;
int* idsCpp;
try {
// Read in data set
idsCpp = jniUtil->GetIntArrayElements(env, idsJ, nullptr);
float* floatArrayCpp;
jfloatArray floatArrayJ;
for (int i = 0; i < numVectors; i++) {
floatArrayJ = (jfloatArray)jniUtil->GetObjectArrayElement(env, vectorsJ, i);
if (dim != jniUtil->GetJavaFloatArrayLength(env, floatArrayJ)) {
throw std::runtime_error("Dimension of vectors is inconsistent");
}
floatArrayCpp = jniUtil->GetFloatArrayElements(env, floatArrayJ, nullptr);
dataset.push_back(new similarity::Object(idsCpp[i], -1, dim*sizeof(float), floatArrayCpp));
jniUtil->ReleaseFloatArrayElements(env, floatArrayJ, floatArrayCpp, JNI_ABORT);
}
jniUtil->ReleaseIntArrayElements(env, idsJ, idsCpp, JNI_ABORT);
std::unique_ptr<similarity::Index<float>> index;
index.reset(similarity::MethodFactoryRegistry<float>::Instance().CreateMethod(false, "hnsw", spaceTypeCpp, *(space), dataset));
index->CreateIndex(similarity::AnyParams(indexParameters));
index->SaveIndex(indexPathCpp);
for (auto & it : dataset) {
delete it;
}
} catch (...) {
for (auto & it : dataset) {
delete it;
}
jniUtil->ReleaseIntArrayElements(env, idsJ, idsCpp, JNI_ABORT);
throw;
}
}