Compare commits
8 Commits
a9a9247773
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb8f61f868 | ||
|
|
091c258d41 | ||
|
|
8474c77163 | ||
|
|
21f527ba46 | ||
|
|
462041654d | ||
|
|
60d609dd6a | ||
| ccbd833361 | |||
| 24895fc1bc |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -22,4 +22,6 @@ build/
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
Thumbs.db
|
||||
|
||||
package-lock.json
|
||||
46
package.json
46
package.json
@@ -1,23 +1,59 @@
|
||||
{
|
||||
"name": "similarity-search",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"description": "A Node.js module for word order independent string similarity search",
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "node-gyp rebuild",
|
||||
"test": "node test.js"
|
||||
"rebuild": "node-gyp rebuild",
|
||||
"build": "node-gyp rebuild",
|
||||
"clean": "node-gyp clean",
|
||||
"configure": "node-gyp configure",
|
||||
"test": "node test.js",
|
||||
"pretest": "npm run build"
|
||||
},
|
||||
"keywords": [
|
||||
"search",
|
||||
"similarity",
|
||||
"string",
|
||||
"fuzzy"
|
||||
"fuzzy",
|
||||
"native",
|
||||
"addon",
|
||||
"c++",
|
||||
"performance"
|
||||
],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nan": "^2.22.2",
|
||||
"node-addon-api": "^6.0.0"
|
||||
"node-addon-api": "^6.0.0",
|
||||
"node-gyp": "^11.2.0"
|
||||
},
|
||||
"gypfile": true
|
||||
"devDependencies": {
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": ""
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"binding.gyp",
|
||||
"similarity_search.c",
|
||||
"similarity_search.h",
|
||||
"similarity_search_addon.cc",
|
||||
"README.md"
|
||||
],
|
||||
"gypfile": true,
|
||||
"os": [
|
||||
"win32",
|
||||
"darwin",
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"x64",
|
||||
"arm64"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#ifdef _WIN32
|
||||
#include <malloc.h> // For alloca on Windows
|
||||
#else
|
||||
#include <alloca.h> // For alloca on Unix-like systems
|
||||
#endif
|
||||
#include "similarity_search.h"
|
||||
|
||||
// Case insensitive string comparison
|
||||
@@ -43,7 +48,9 @@ int split_into_words(const char *s,
|
||||
|
||||
// Free memory allocated for words
|
||||
void free_words(char *storage) { /* simplified */
|
||||
free(storage); /* single free, if any */
|
||||
if (storage) { /* check for NULL */
|
||||
free(storage); /* single free, if any */
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate Levenshtein distance between two strings
|
||||
@@ -77,8 +84,8 @@ float word_similarity(const char *word1, const char *word2) {
|
||||
int len1 = strlen(word1);
|
||||
int len2 = strlen(word2);
|
||||
|
||||
// For very short words (3 chars or less), require exact match
|
||||
if (len1 <= 3 || len2 <= 3) {
|
||||
// For very short words (2 chars or less), require exact match
|
||||
if (len1 <= 2 || len2 <= 2) {
|
||||
return str_case_cmp(word1, word2) == 0 ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
@@ -100,7 +107,7 @@ float word_similarity(const char *word1, const char *word2) {
|
||||
// Calculate similarity between query and target string
|
||||
float calculate_similarity(const char *query, const char *target, float cutoff) {
|
||||
// Split strings into words
|
||||
char *query_buf, *target_buf;
|
||||
char *query_buf = NULL, *target_buf = NULL;
|
||||
char *query_words[MAX_WORDS], *target_words[MAX_WORDS];
|
||||
|
||||
int query_word_count = split_into_words(query, query_words, &query_buf);
|
||||
@@ -299,27 +306,26 @@ SearchResult* search_index(SearchIndex* index, const char* query, float cutoff,
|
||||
}
|
||||
}
|
||||
|
||||
// If no results found, return NULL properly
|
||||
if (*num_results == 0) {
|
||||
free(temp_results);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Sort results by similarity
|
||||
qsort(temp_results, *num_results, sizeof(SearchResult), compare_results);
|
||||
|
||||
// Allocate final result array with exact size
|
||||
SearchResult* results = (SearchResult*)malloc(*num_results * sizeof(SearchResult));
|
||||
// Shrink temp_results to exact size and return it directly
|
||||
SearchResult* results = (SearchResult*)realloc(
|
||||
temp_results, *num_results * sizeof(SearchResult));
|
||||
if (!results) {
|
||||
// Free all strings in temp_results
|
||||
// realloc failure – temp_results unchanged, clean up
|
||||
for (int i = 0; i < *num_results; i++) {
|
||||
free(temp_results[i].string);
|
||||
}
|
||||
free(temp_results);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy results to final array
|
||||
for (int i = 0; i < *num_results; i++) {
|
||||
results[i].string = temp_results[i].string;
|
||||
results[i].similarity = temp_results[i].similarity;
|
||||
}
|
||||
free(temp_results);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -332,4 +338,4 @@ void free_search_results(SearchResult* results, int num_results) {
|
||||
free(results[i].string);
|
||||
}
|
||||
free(results);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,9 +129,9 @@ Napi::Value SearchIndexWrapper::Search(const Napi::CallbackInfo& info) {
|
||||
int num_results = 0;
|
||||
SearchResult* results = search_index(this->index_, query.c_str(), cutoff, &num_results);
|
||||
|
||||
if (!results) {
|
||||
Napi::Error::New(env, "Search failed").ThrowAsJavaScriptException();
|
||||
return env.Null();
|
||||
// If no results found, return empty array instead of throwing error
|
||||
if (!results || num_results == 0) {
|
||||
return Napi::Array::New(env, 0);
|
||||
}
|
||||
|
||||
Napi::Array result_array = Napi::Array::New(env, num_results);
|
||||
|
||||
Reference in New Issue
Block a user