@delali/narsil-react-native 0.3.1-next.154 → 0.3.1-next.156
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +144 -0
- package/NarsilReactNative.podspec +2 -2
- package/android/CMakeLists.txt +1 -1
- package/cpp/HybridNarsilCoreAnalysis.cpp +277 -0
- package/cpp/HybridNarsilCoreImpl.hpp +43 -0
- package/cpp/HybridNarsilCoreKeyword.cpp +253 -0
- package/cpp/HybridNarsilCoreMath.cpp +47 -0
- package/cpp/core/include/narsil_analysis.h +86 -0
- package/cpp/core/include/narsil_core.h +1 -1
- package/cpp/core/include/narsil_keyword.h +110 -0
- package/cpp/core/include/narsil_math.h +36 -0
- package/cpp/core/src/analysis/analyse.c +281 -0
- package/cpp/core/src/analysis/analyser.h +49 -0
- package/cpp/core/src/analysis/languages.c +79 -0
- package/cpp/core/src/analysis/languages.h +42 -0
- package/cpp/core/src/analysis/normalise.c +242 -0
- package/cpp/core/src/analysis/normalise.h +28 -0
- package/cpp/core/src/analysis/split.c +183 -0
- package/cpp/core/src/analysis/split.h +27 -0
- package/cpp/core/src/analysis/stop_words.c +82 -0
- package/cpp/core/src/analysis/stop_words.h +19 -0
- package/cpp/core/src/analysis/term_cache.c +88 -0
- package/cpp/core/src/analysis/term_cache.h +36 -0
- package/cpp/core/src/analysis/text.c +161 -0
- package/cpp/core/src/analysis/text.h +45 -0
- package/cpp/core/src/analysis/transform.c +103 -0
- package/cpp/core/src/analysis/unicode.c +252 -0
- package/cpp/core/src/analysis/unicode.h +54 -0
- package/cpp/core/src/internal.h +4 -0
- package/cpp/core/src/keyword/pass.h +117 -0
- package/cpp/core/src/keyword/prune.c +324 -0
- package/cpp/core/src/keyword/request.c +179 -0
- package/cpp/core/src/keyword/rows.c +83 -0
- package/cpp/core/src/keyword/rows.h +18 -0
- package/cpp/core/src/keyword/score.c +257 -0
- package/cpp/core/src/keyword/score.h +17 -0
- package/cpp/core/src/keyword/scratch.c +226 -0
- package/cpp/core/src/keyword/scratch.h +55 -0
- package/cpp/core/src/keyword/select.c +155 -0
- package/cpp/core/src/keyword/select.h +17 -0
- package/cpp/core/src/languages/bulgarian_stemmer.c +114 -0
- package/cpp/core/src/languages/data/albanian.c +54 -0
- package/cpp/core/src/languages/data/amharic.c +93 -0
- package/cpp/core/src/languages/data/arabic.c +146 -0
- package/cpp/core/src/languages/data/armenian.c +46 -0
- package/cpp/core/src/languages/data/azerbaijani.c +68 -0
- package/cpp/core/src/languages/data/bambara.c +48 -0
- package/cpp/core/src/languages/data/basque.c +62 -0
- package/cpp/core/src/languages/data/belarusian.c +56 -0
- package/cpp/core/src/languages/data/bengali.c +63 -0
- package/cpp/core/src/languages/data/bosnian.c +73 -0
- package/cpp/core/src/languages/data/breton.c +52 -0
- package/cpp/core/src/languages/data/bulgarian.c +144 -0
- package/cpp/core/src/languages/data/burmese.c +48 -0
- package/cpp/core/src/languages/data/catalan.c +84 -0
- package/cpp/core/src/languages/data/chinese.c +70 -0
- package/cpp/core/src/languages/data/croatian.c +72 -0
- package/cpp/core/src/languages/data/czech.c +72 -0
- package/cpp/core/src/languages/data/dagbani.c +88 -0
- package/cpp/core/src/languages/data/danish.c +56 -0
- package/cpp/core/src/languages/data/declarations.h +114 -0
- package/cpp/core/src/languages/data/dutch.c +58 -0
- package/cpp/core/src/languages/data/english.c +172 -0
- package/cpp/core/src/languages/data/esperanto.c +71 -0
- package/cpp/core/src/languages/data/estonian.c +417 -0
- package/cpp/core/src/languages/data/ewe.c +89 -0
- package/cpp/core/src/languages/data/faroese.c +54 -0
- package/cpp/core/src/languages/data/fijian.c +44 -0
- package/cpp/core/src/languages/data/finnish.c +100 -0
- package/cpp/core/src/languages/data/french.c +74 -0
- package/cpp/core/src/languages/data/ga.c +83 -0
- package/cpp/core/src/languages/data/galician.c +70 -0
- package/cpp/core/src/languages/data/georgian.c +57 -0
- package/cpp/core/src/languages/data/german.c +96 -0
- package/cpp/core/src/languages/data/greek.c +202 -0
- package/cpp/core/src/languages/data/guarani.c +110 -0
- package/cpp/core/src/languages/data/gujarati.c +90 -0
- package/cpp/core/src/languages/data/haitian-creole.c +54 -0
- package/cpp/core/src/languages/data/hausa.c +85 -0
- package/cpp/core/src/languages/data/hawaiian.c +50 -0
- package/cpp/core/src/languages/data/hebrew.c +85 -0
- package/cpp/core/src/languages/data/hindi.c +91 -0
- package/cpp/core/src/languages/data/hungarian.c +98 -0
- package/cpp/core/src/languages/data/icelandic.c +73 -0
- package/cpp/core/src/languages/data/igbo.c +90 -0
- package/cpp/core/src/languages/data/indonesian.c +296 -0
- package/cpp/core/src/languages/data/irish.c +60 -0
- package/cpp/core/src/languages/data/italian.c +107 -0
- package/cpp/core/src/languages/data/japanese.c +52 -0
- package/cpp/core/src/languages/data/kannada.c +60 -0
- package/cpp/core/src/languages/data/kazakh.c +57 -0
- package/cpp/core/src/languages/data/khmer.c +71 -0
- package/cpp/core/src/languages/data/kinyarwanda.c +54 -0
- package/cpp/core/src/languages/data/kirundi.c +53 -0
- package/cpp/core/src/languages/data/korean.c +74 -0
- package/cpp/core/src/languages/data/kurmanji.c +43 -0
- package/cpp/core/src/languages/data/kyrgyz.c +65 -0
- package/cpp/core/src/languages/data/lao.c +46 -0
- package/cpp/core/src/languages/data/latin.c +46 -0
- package/cpp/core/src/languages/data/latvian.c +75 -0
- package/cpp/core/src/languages/data/lingala.c +88 -0
- package/cpp/core/src/languages/data/lithuanian.c +65 -0
- package/cpp/core/src/languages/data/luxembourgish.c +80 -0
- package/cpp/core/src/languages/data/macedonian.c +286 -0
- package/cpp/core/src/languages/data/malagasy.c +51 -0
- package/cpp/core/src/languages/data/malay.c +184 -0
- package/cpp/core/src/languages/data/malayalam.c +64 -0
- package/cpp/core/src/languages/data/maltese.c +102 -0
- package/cpp/core/src/languages/data/maori.c +52 -0
- package/cpp/core/src/languages/data/marathi.c +62 -0
- package/cpp/core/src/languages/data/nepali.c +72 -0
- package/cpp/core/src/languages/data/norwegian.c +74 -0
- package/cpp/core/src/languages/data/oromo.c +51 -0
- package/cpp/core/src/languages/data/persian.c +150 -0
- package/cpp/core/src/languages/data/polish.c +111 -0
- package/cpp/core/src/languages/data/portuguese.c +91 -0
- package/cpp/core/src/languages/data/punjabi.c +80 -0
- package/cpp/core/src/languages/data/registry.c +116 -0
- package/cpp/core/src/languages/data/romanian.c +93 -0
- package/cpp/core/src/languages/data/russian.c +76 -0
- package/cpp/core/src/languages/data/samoan.c +47 -0
- package/cpp/core/src/languages/data/sanskrit.c +53 -0
- package/cpp/core/src/languages/data/scottish-gaelic.c +119 -0
- package/cpp/core/src/languages/data/serbian.c +84 -0
- package/cpp/core/src/languages/data/shona.c +55 -0
- package/cpp/core/src/languages/data/sinhala.c +78 -0
- package/cpp/core/src/languages/data/slovak.c +135 -0
- package/cpp/core/src/languages/data/slovenian.c +139 -0
- package/cpp/core/src/languages/data/sorani.c +55 -0
- package/cpp/core/src/languages/data/spanish.c +84 -0
- package/cpp/core/src/languages/data/swahili.c +59 -0
- package/cpp/core/src/languages/data/swedish.c +60 -0
- package/cpp/core/src/languages/data/tagalog.c +75 -0
- package/cpp/core/src/languages/data/tamil.c +69 -0
- package/cpp/core/src/languages/data/tatar.c +548 -0
- package/cpp/core/src/languages/data/telugu.c +54 -0
- package/cpp/core/src/languages/data/thai.c +46 -0
- package/cpp/core/src/languages/data/tibetan.c +55 -0
- package/cpp/core/src/languages/data/tigrinya.c +73 -0
- package/cpp/core/src/languages/data/tongan.c +47 -0
- package/cpp/core/src/languages/data/turkish.c +100 -0
- package/cpp/core/src/languages/data/twi.c +88 -0
- package/cpp/core/src/languages/data/ukrainian.c +99 -0
- package/cpp/core/src/languages/data/urdu.c +174 -0
- package/cpp/core/src/languages/data/vietnamese.c +88 -0
- package/cpp/core/src/languages/data/welsh.c +143 -0
- package/cpp/core/src/languages/data/wolof.c +51 -0
- package/cpp/core/src/languages/data/xhosa.c +56 -0
- package/cpp/core/src/languages/data/yoruba.c +93 -0
- package/cpp/core/src/languages/data/zulu.c +58 -0
- package/cpp/core/src/languages/marks.c +64 -0
- package/cpp/core/src/languages/rules.c +63 -0
- package/cpp/core/src/languages/rules.h +68 -0
- package/cpp/core/src/languages/sanskrit_stemmer.c +50 -0
- package/cpp/core/src/languages/scripts.c +143 -0
- package/cpp/core/src/languages/slovenian_stemmer.c +46 -0
- package/cpp/core/src/languages/snowball/api.c +52 -0
- package/cpp/core/src/languages/snowball/api.h +43 -0
- package/cpp/core/src/languages/snowball/arabic_stemmer.c +1506 -0
- package/cpp/core/src/languages/snowball/arabic_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/armenian_stemmer.c +523 -0
- package/cpp/core/src/languages/snowball/armenian_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/basque_stemmer.c +1089 -0
- package/cpp/core/src/languages/snowball/basque_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/catalan_stemmer.c +1380 -0
- package/cpp/core/src/languages/snowball/catalan_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/czech_stemmer.c +582 -0
- package/cpp/core/src/languages/snowball/czech_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/danish_stemmer.c +352 -0
- package/cpp/core/src/languages/snowball/danish_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/dutch_stemmer.c +1657 -0
- package/cpp/core/src/languages/snowball/dutch_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/english_stemmer.c +1019 -0
- package/cpp/core/src/languages/snowball/english_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/esperanto_stemmer.c +716 -0
- package/cpp/core/src/languages/snowball/esperanto_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/estonian_stemmer.c +1361 -0
- package/cpp/core/src/languages/snowball/estonian_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/finnish_stemmer.c +800 -0
- package/cpp/core/src/languages/snowball/finnish_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/french_stemmer.c +1217 -0
- package/cpp/core/src/languages/snowball/french_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/german_stemmer.c +567 -0
- package/cpp/core/src/languages/snowball/german_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/greek_stemmer.c +3450 -0
- package/cpp/core/src/languages/snowball/greek_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/hindi_stemmer.c +325 -0
- package/cpp/core/src/languages/snowball/hindi_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/hungarian_stemmer.c +742 -0
- package/cpp/core/src/languages/snowball/hungarian_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/indonesian_stemmer.c +443 -0
- package/cpp/core/src/languages/snowball/indonesian_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/irish_stemmer.c +428 -0
- package/cpp/core/src/languages/snowball/irish_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/italian_stemmer.c +983 -0
- package/cpp/core/src/languages/snowball/italian_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/lithuanian_stemmer.c +794 -0
- package/cpp/core/src/languages/snowball/lithuanian_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/nepali_stemmer.c +361 -0
- package/cpp/core/src/languages/snowball/nepali_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/norwegian_stemmer.c +332 -0
- package/cpp/core/src/languages/snowball/norwegian_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/persian_stemmer.c +538 -0
- package/cpp/core/src/languages/snowball/persian_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/polish_stemmer.c +501 -0
- package/cpp/core/src/languages/snowball/polish_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/portuguese_stemmer.c +866 -0
- package/cpp/core/src/languages/snowball/portuguese_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/romanian_stemmer.c +940 -0
- package/cpp/core/src/languages/snowball/romanian_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/russian_stemmer.c +598 -0
- package/cpp/core/src/languages/snowball/russian_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/serbian_stemmer.c +6765 -0
- package/cpp/core/src/languages/snowball/serbian_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/snowball_runtime.h +122 -0
- package/cpp/core/src/languages/snowball/spanish_stemmer.c +955 -0
- package/cpp/core/src/languages/snowball/spanish_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/swedish_stemmer.c +364 -0
- package/cpp/core/src/languages/snowball/swedish_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/tamil_stemmer.c +1305 -0
- package/cpp/core/src/languages/snowball/tamil_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/turkish_stemmer.c +1700 -0
- package/cpp/core/src/languages/snowball/turkish_stemmer.h +24 -0
- package/cpp/core/src/languages/snowball/utilities.c +716 -0
- package/cpp/core/src/languages/substitutions.c +131 -0
- package/cpp/core/src/languages/swahili_stemmer.c +85 -0
- package/cpp/core/src/languages/ukrainian_stemmer.c +168 -0
- package/cpp/core/src/locks.c +2 -15
- package/cpp/core/src/math/apply.c +44 -0
- package/cpp/core/src/math/fdlibm.h +16 -0
- package/cpp/core/src/math/inverse.c +242 -0
- package/cpp/core/src/math/log.c +90 -0
- package/cpp/core/src/math/reduce.c +325 -0
- package/cpp/core/src/math/trig.c +188 -0
- package/cpp/core/src/math/words.h +45 -0
- package/cpp/core/src/thread_yield.h +18 -0
- package/cpp/core/src/unicode/decompositions.c +310 -0
- package/cpp/core/src/unicode/lowercase.c +172 -0
- package/cpp/core/src/unicode/properties.c +214 -0
- package/cpp/core/src/workspace.c +5 -1
- package/lib/engine/analysis.d.ts +3 -0
- package/lib/engine/analysis.js +76 -0
- package/lib/engine/core.js +5 -0
- package/lib/engine/keyword.d.ts +3 -0
- package/lib/engine/keyword.js +25 -0
- package/lib/specs/core.nitro.d.ts +1 -0
- package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.hpp +1 -0
- package/package.json +4 -3
- package/src/engine/analysis.ts +87 -0
- package/src/engine/core.ts +6 -0
- package/src/engine/keyword.ts +26 -0
- package/src/specs/core.nitro.ts +1 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#ifndef NARSIL_KEYWORD_PASS_H
|
|
2
|
+
#define NARSIL_KEYWORD_PASS_H
|
|
3
|
+
|
|
4
|
+
#include "scratch.h"
|
|
5
|
+
|
|
6
|
+
#include "../../include/narsil_keyword.h"
|
|
7
|
+
|
|
8
|
+
#include <stddef.h>
|
|
9
|
+
#include <stdint.h>
|
|
10
|
+
#include <string.h>
|
|
11
|
+
|
|
12
|
+
#define KEYWORD_BITS_PER_WORD 32U
|
|
13
|
+
#define KEYWORD_WORD_SHIFT 5U
|
|
14
|
+
#define KEYWORD_BIT_MASK 31U
|
|
15
|
+
|
|
16
|
+
typedef struct {
|
|
17
|
+
const narsil_keyword_request *request;
|
|
18
|
+
keyword_scratch *scratch;
|
|
19
|
+
narsil_keyword_output *output;
|
|
20
|
+
const double *boosts;
|
|
21
|
+
const double *averages;
|
|
22
|
+
const double *k1s;
|
|
23
|
+
const double *bs;
|
|
24
|
+
uint32_t field_count;
|
|
25
|
+
uint32_t capacity;
|
|
26
|
+
uint32_t list_count;
|
|
27
|
+
int tracks_coverage;
|
|
28
|
+
int has_limit;
|
|
29
|
+
uint32_t limit;
|
|
30
|
+
const uint32_t *scorable_bits;
|
|
31
|
+
uint32_t scorable_words;
|
|
32
|
+
} keyword_pass;
|
|
33
|
+
|
|
34
|
+
typedef struct {
|
|
35
|
+
const uint32_t *doc_ids;
|
|
36
|
+
const uint16_t *fields;
|
|
37
|
+
const uint16_t *narrow_frequencies;
|
|
38
|
+
const double *wide_frequencies;
|
|
39
|
+
} keyword_rows;
|
|
40
|
+
|
|
41
|
+
double keyword_idf(double document_frequency, double total_documents);
|
|
42
|
+
void keyword_list_rows(const keyword_pass *pass, uint32_t list, keyword_rows *rows);
|
|
43
|
+
|
|
44
|
+
static inline double keyword_frequency(const keyword_rows *rows, uint32_t row) {
|
|
45
|
+
return rows->wide_frequencies != NULL ? rows->wide_frequencies[row] : (double)rows->narrow_frequencies[row];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static inline uint32_t keyword_list_start(const narsil_keyword_request *request, uint32_t list) {
|
|
49
|
+
return request->lists[((size_t)list * NARSIL_KEYWORD_LIST_STRIDE) + NARSIL_KEYWORD_LIST_START];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static inline uint32_t keyword_list_length(const narsil_keyword_request *request, uint32_t list) {
|
|
53
|
+
return request->lists[((size_t)list * NARSIL_KEYWORD_LIST_STRIDE) + NARSIL_KEYWORD_LIST_LENGTH];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static inline uint32_t keyword_list_flags(const narsil_keyword_request *request, uint32_t list) {
|
|
57
|
+
return request->lists[((size_t)list * NARSIL_KEYWORD_LIST_STRIDE) + NARSIL_KEYWORD_LIST_FLAGS];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static inline double keyword_list_value(const narsil_keyword_request *request, uint32_t list, uint32_t column) {
|
|
61
|
+
return request->list_values[((size_t)list * NARSIL_KEYWORD_LIST_VALUE_STRIDE) + column];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static inline uint32_t keyword_words_for(uint32_t capacity) {
|
|
65
|
+
return (capacity + KEYWORD_BITS_PER_WORD - 1U) / KEYWORD_BITS_PER_WORD;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static inline int keyword_holds(const uint32_t *bits, uint32_t words, uint32_t ordinal) {
|
|
69
|
+
uint32_t word = ordinal >> KEYWORD_WORD_SHIFT;
|
|
70
|
+
return word < words && ((bits[word] >> (ordinal & KEYWORD_BIT_MASK)) & 1U) == 1U;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static inline double keyword_kept_or_zero(double value, uint32_t keep) {
|
|
74
|
+
uint64_t bits = 0;
|
|
75
|
+
memcpy(&bits, &value, sizeof bits);
|
|
76
|
+
bits &= (uint64_t)0 - (uint64_t)keep;
|
|
77
|
+
double kept = 0;
|
|
78
|
+
memcpy(&kept, &bits, sizeof kept);
|
|
79
|
+
return kept;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static inline int keyword_scorable(const keyword_pass *pass, uint32_t ordinal) {
|
|
83
|
+
if (pass->scorable_bits != NULL) { return keyword_holds(pass->scorable_bits, pass->scorable_words, ordinal); }
|
|
84
|
+
const narsil_keyword_request *request = pass->request;
|
|
85
|
+
if (ordinal >= pass->capacity || !keyword_holds(request->live, request->live_words, ordinal) ||
|
|
86
|
+
keyword_holds(request->removed, request->removed_words, ordinal)) {
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
return !request->has_filter || keyword_holds(request->filter, request->filter_words, ordinal);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static inline int keyword_searchable(const keyword_pass *pass, uint32_t field) {
|
|
93
|
+
return field < pass->field_count && pass->request->searchable[field] != 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static inline double keyword_bm25(const keyword_pass *pass, double idf, double frequency, double length,
|
|
97
|
+
uint32_t field) {
|
|
98
|
+
double average = pass->averages[field];
|
|
99
|
+
double bm25 = 0;
|
|
100
|
+
if (average != 0) {
|
|
101
|
+
double saturation = pass->k1s[field];
|
|
102
|
+
double length_weight = pass->bs[field];
|
|
103
|
+
double top = frequency * (saturation + 1);
|
|
104
|
+
double bottom = frequency + (saturation * ((1 - length_weight) + ((length_weight * length) / average)));
|
|
105
|
+
bm25 = bottom == 0 ? 0 : idf * (top / bottom);
|
|
106
|
+
}
|
|
107
|
+
return bm25 * pass->boosts[field];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static inline double keyword_row_score(const keyword_pass *pass, double idf, double frequency, uint32_t field,
|
|
111
|
+
uint32_t ordinal) {
|
|
112
|
+
const narsil_keyword_column *column = &pass->request->lengths[field];
|
|
113
|
+
uint32_t stored = column->values != NULL && ordinal < column->length ? column->values[ordinal] : 0;
|
|
114
|
+
return keyword_bm25(pass, idf, frequency, stored > 0 ? (double)stored : pass->averages[field], field);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#endif
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
#include "pass.h"
|
|
2
|
+
#include "rows.h"
|
|
3
|
+
#include "score.h"
|
|
4
|
+
#include "scratch.h"
|
|
5
|
+
#include "select.h"
|
|
6
|
+
|
|
7
|
+
#include "../../include/narsil_keyword.h"
|
|
8
|
+
|
|
9
|
+
#include <float.h>
|
|
10
|
+
#include <math.h>
|
|
11
|
+
#include <stddef.h>
|
|
12
|
+
#include <stdint.h>
|
|
13
|
+
#include <string.h>
|
|
14
|
+
|
|
15
|
+
#define PRUNING_SLACK 1e-9
|
|
16
|
+
#define PRUNING_MAX_ROWS_PER_DOCUMENT 100000U
|
|
17
|
+
|
|
18
|
+
typedef struct {
|
|
19
|
+
uint32_t *order;
|
|
20
|
+
const double *bounds;
|
|
21
|
+
uint32_t size;
|
|
22
|
+
} list_heap;
|
|
23
|
+
|
|
24
|
+
typedef struct {
|
|
25
|
+
double row_weight;
|
|
26
|
+
uint32_t rows_per_document;
|
|
27
|
+
} field_ceiling;
|
|
28
|
+
|
|
29
|
+
typedef struct {
|
|
30
|
+
uint32_t rows_per_document;
|
|
31
|
+
uint32_t exceeded;
|
|
32
|
+
} row_check;
|
|
33
|
+
|
|
34
|
+
static int fields_keep_scores_non_negative(const keyword_pass *pass, field_ceiling *ceiling) {
|
|
35
|
+
ceiling->row_weight = 0;
|
|
36
|
+
ceiling->rows_per_document = 0;
|
|
37
|
+
for (uint32_t field = 0; field < pass->field_count; field++) {
|
|
38
|
+
if (!keyword_searchable(pass, field)) { continue; }
|
|
39
|
+
ceiling->rows_per_document++;
|
|
40
|
+
double boost = pass->boosts[field];
|
|
41
|
+
double average = pass->averages[field];
|
|
42
|
+
double saturation = pass->k1s[field];
|
|
43
|
+
double length_weight = pass->bs[field];
|
|
44
|
+
if (!(boost >= 0 && boost <= DBL_MAX) || !(average >= 0 && average <= DBL_MAX) ||
|
|
45
|
+
!(saturation >= 0 && saturation <= DBL_MAX) || !(length_weight >= 0 && length_weight <= 1)) {
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
double weight = (saturation + 1) * boost;
|
|
49
|
+
if (weight > ceiling->row_weight) { ceiling->row_weight = weight; }
|
|
50
|
+
}
|
|
51
|
+
return ceiling->rows_per_document > 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static int prunable(const keyword_pass *pass, field_ceiling *ceiling) {
|
|
55
|
+
const narsil_keyword_request *request = pass->request;
|
|
56
|
+
if (!pass->has_limit || pass->limit < 1 || request->min_score > 0) { return 0; }
|
|
57
|
+
if (request->terms > 0 && (request->term_match > 1 || request->term_match > request->terms)) { return 0; }
|
|
58
|
+
if (pass->list_count < 2 || pass->scorable_bits == NULL) { return 0; }
|
|
59
|
+
for (uint32_t slot = 0; slot < request->slot_count; slot++) {
|
|
60
|
+
uint32_t kind = request->slots[((size_t)slot * NARSIL_KEYWORD_SLOT_STRIDE) + NARSIL_KEYWORD_SLOT_KIND];
|
|
61
|
+
if (kind != NARSIL_KEYWORD_TERM_SLOT) { return 0; }
|
|
62
|
+
}
|
|
63
|
+
for (uint32_t list = 0; list < pass->list_count; list++) {
|
|
64
|
+
uint32_t flags = keyword_list_flags(request, list);
|
|
65
|
+
if ((flags & NARSIL_KEYWORD_LIST_FROM_ROWS) != 0 || (flags & NARSIL_KEYWORD_LIST_ORDERED) == 0) { return 0; }
|
|
66
|
+
}
|
|
67
|
+
if ((uint64_t)pass->list_count * pass->field_count > PRUNING_MAX_ROWS_PER_DOCUMENT) { return 0; }
|
|
68
|
+
return fields_keep_scores_non_negative(pass, ceiling);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static int list_before(const list_heap *heap, uint32_t lhs, uint32_t rhs) {
|
|
72
|
+
if (heap->bounds[lhs] != heap->bounds[rhs]) { return heap->bounds[lhs] > heap->bounds[rhs]; }
|
|
73
|
+
return lhs < rhs;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static void sift_list_down(const list_heap *heap, uint32_t root) {
|
|
77
|
+
uint32_t *order = heap->order;
|
|
78
|
+
uint32_t node = root;
|
|
79
|
+
for (;;) {
|
|
80
|
+
uint64_t left = (2 * (uint64_t)node) + 1;
|
|
81
|
+
if (left >= heap->size) { return; }
|
|
82
|
+
uint64_t last = node;
|
|
83
|
+
if (list_before(heap, order[last], order[left])) { last = left; }
|
|
84
|
+
if (left + 1 < heap->size && list_before(heap, order[last], order[left + 1])) { last = left + 1; }
|
|
85
|
+
if (last == node) { return; }
|
|
86
|
+
uint32_t held = order[node];
|
|
87
|
+
order[node] = order[last];
|
|
88
|
+
order[last] = held;
|
|
89
|
+
node = (uint32_t)last;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static void sort_lists_by_bound(keyword_scratch *scratch, uint32_t count) {
|
|
94
|
+
list_heap heap = {scratch->list_order, scratch->list_bounds, count};
|
|
95
|
+
for (uint32_t root = count / 2; root > 0; root--) { sift_list_down(&heap, root - 1); }
|
|
96
|
+
for (uint32_t size = count; size > 1; size--) {
|
|
97
|
+
uint32_t held = heap.order[0];
|
|
98
|
+
heap.order[0] = heap.order[size - 1];
|
|
99
|
+
heap.order[size - 1] = held;
|
|
100
|
+
heap.size = size - 1;
|
|
101
|
+
sift_list_down(&heap, 0);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static uint32_t next_run(uint32_t run, uint32_t ordinal, uint32_t previous) {
|
|
106
|
+
return (run & ((uint32_t)0 - (uint32_t)(ordinal == previous))) + 1U;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static void score_every_row(const keyword_pass *pass, uint32_t list, row_check *check) {
|
|
110
|
+
const narsil_keyword_request *request = pass->request;
|
|
111
|
+
keyword_scratch *scratch = pass->scratch;
|
|
112
|
+
const uint32_t *doc_ids = request->pool_doc_ids;
|
|
113
|
+
const uint16_t *fields = request->pool_fields;
|
|
114
|
+
const uint16_t *frequencies = request->pool_frequencies;
|
|
115
|
+
uint32_t start = keyword_list_start(request, list);
|
|
116
|
+
uint32_t end = start + keyword_list_length(request, list);
|
|
117
|
+
double idf = scratch->list_idfs[list];
|
|
118
|
+
const uint32_t *scorable = pass->scorable_bits;
|
|
119
|
+
uint32_t *seen_bits = scratch->seen_bits;
|
|
120
|
+
double *scores = scratch->scores;
|
|
121
|
+
uint32_t *touched = scratch->touched;
|
|
122
|
+
uint32_t touched_count = scratch->touched_count;
|
|
123
|
+
uint32_t rows_per_document = check->rows_per_document;
|
|
124
|
+
uint32_t exceeded = 0;
|
|
125
|
+
uint32_t previous = UINT32_MAX;
|
|
126
|
+
uint32_t run = 0;
|
|
127
|
+
for (uint32_t row = start; row < end; row++) {
|
|
128
|
+
uint16_t field = fields[row];
|
|
129
|
+
uint32_t ordinal = doc_ids[row];
|
|
130
|
+
if (!keyword_searchable(pass, field) || ordinal >= pass->capacity) { continue; }
|
|
131
|
+
run = next_run(run, ordinal, previous);
|
|
132
|
+
previous = ordinal;
|
|
133
|
+
exceeded |= (uint32_t)(run > rows_per_document);
|
|
134
|
+
double score = keyword_row_score(pass, idf, (double)frequencies[row], field, ordinal);
|
|
135
|
+
uint32_t word = ordinal >> KEYWORD_WORD_SHIFT;
|
|
136
|
+
uint32_t shift = ordinal & KEYWORD_BIT_MASK;
|
|
137
|
+
uint32_t seen = (seen_bits[word] >> shift) & 1U;
|
|
138
|
+
uint32_t fresh = ((scorable[word] & ~seen_bits[word]) >> shift) & 1U;
|
|
139
|
+
seen_bits[word] |= fresh << shift;
|
|
140
|
+
scores[ordinal] = keyword_kept_or_zero(scores[ordinal], seen) + score;
|
|
141
|
+
touched[touched_count] = ordinal;
|
|
142
|
+
touched_count += fresh;
|
|
143
|
+
}
|
|
144
|
+
scratch->touched_count = touched_count;
|
|
145
|
+
check->exceeded |= exceeded;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static uint32_t score_known_rows(const keyword_pass *pass, uint32_t list, row_check *check) {
|
|
149
|
+
const narsil_keyword_request *request = pass->request;
|
|
150
|
+
keyword_scratch *scratch = pass->scratch;
|
|
151
|
+
const uint32_t *doc_ids = request->pool_doc_ids;
|
|
152
|
+
const uint16_t *fields = request->pool_fields;
|
|
153
|
+
const uint16_t *frequencies = request->pool_frequencies;
|
|
154
|
+
uint32_t start = keyword_list_start(request, list);
|
|
155
|
+
uint32_t end = start + keyword_list_length(request, list);
|
|
156
|
+
double idf = scratch->list_idfs[list];
|
|
157
|
+
const uint32_t *scorable = pass->scorable_bits;
|
|
158
|
+
const uint32_t *seen_bits = scratch->seen_bits;
|
|
159
|
+
uint32_t *counted_bits = scratch->counted_bits;
|
|
160
|
+
double *scores = scratch->scores;
|
|
161
|
+
uint32_t *matched = request->collect ? pass->output->matched : NULL;
|
|
162
|
+
uint32_t counted = 0;
|
|
163
|
+
uint32_t *seen_rows = scratch->order;
|
|
164
|
+
uint32_t seen_count = 0;
|
|
165
|
+
uint32_t rows_per_document = check->rows_per_document;
|
|
166
|
+
uint32_t exceeded = 0;
|
|
167
|
+
uint32_t previous = UINT32_MAX;
|
|
168
|
+
uint32_t run = 0;
|
|
169
|
+
for (uint32_t row = start; row < end; row++) {
|
|
170
|
+
uint16_t field = fields[row];
|
|
171
|
+
uint32_t ordinal = doc_ids[row];
|
|
172
|
+
if (!keyword_searchable(pass, field) || ordinal >= pass->capacity) { continue; }
|
|
173
|
+
run = next_run(run, ordinal, previous);
|
|
174
|
+
previous = ordinal;
|
|
175
|
+
exceeded |= (uint32_t)(run > rows_per_document);
|
|
176
|
+
uint32_t word = ordinal >> KEYWORD_WORD_SHIFT;
|
|
177
|
+
uint32_t shift = ordinal & KEYWORD_BIT_MASK;
|
|
178
|
+
uint32_t seen = (seen_bits[word] >> shift) & 1U;
|
|
179
|
+
uint32_t fresh = ((scorable[word] & ~(seen_bits[word] | counted_bits[word])) >> shift) & 1U;
|
|
180
|
+
counted_bits[word] |= fresh << shift;
|
|
181
|
+
if (matched != NULL) { matched[word] |= fresh << shift; }
|
|
182
|
+
counted += fresh;
|
|
183
|
+
seen_rows[seen_count] = row;
|
|
184
|
+
seen_count += seen;
|
|
185
|
+
}
|
|
186
|
+
for (uint32_t place = 0; place < seen_count; place++) {
|
|
187
|
+
uint32_t row = seen_rows[place];
|
|
188
|
+
uint32_t ordinal = doc_ids[row];
|
|
189
|
+
uint16_t field = fields[row];
|
|
190
|
+
scores[ordinal] += keyword_row_score(pass, idf, (double)frequencies[row], field, ordinal);
|
|
191
|
+
}
|
|
192
|
+
check->exceeded |= exceeded;
|
|
193
|
+
return counted;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
static uint32_t first_row_of(const uint32_t *doc_ids, uint32_t begin, uint32_t end, uint32_t ordinal) {
|
|
197
|
+
if (begin >= end) { return begin; }
|
|
198
|
+
uint32_t low = begin;
|
|
199
|
+
uint32_t length = end - begin;
|
|
200
|
+
while (length > 1) {
|
|
201
|
+
uint32_t half = length / 2;
|
|
202
|
+
low = doc_ids[low + half - 1] < ordinal ? low + half : low;
|
|
203
|
+
length -= half;
|
|
204
|
+
}
|
|
205
|
+
return low + (uint32_t)(doc_ids[low] < ordinal);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
static double exact_score(const keyword_pass *pass, const keyword_row_keys *keys, uint32_t ordinal) {
|
|
209
|
+
const narsil_keyword_request *request = pass->request;
|
|
210
|
+
const uint16_t *frequencies = request->pool_frequencies;
|
|
211
|
+
double score = 0;
|
|
212
|
+
for (uint32_t list = 0; list < pass->list_count; list++) {
|
|
213
|
+
uint32_t start = keyword_list_start(request, list);
|
|
214
|
+
uint32_t end = start + keyword_list_length(request, list);
|
|
215
|
+
uint32_t first = first_row_of(keys->doc_ids, start, end, ordinal);
|
|
216
|
+
uint32_t last = first;
|
|
217
|
+
while (last < end && keys->doc_ids[last] == ordinal) { last++; }
|
|
218
|
+
if (last == first) { continue; }
|
|
219
|
+
double idf = pass->scratch->list_idfs[list];
|
|
220
|
+
const uint32_t *rows = keyword_rank_ordered_run(pass, keys, first, last - first);
|
|
221
|
+
for (uint32_t place = 0; place < last - first; place++) {
|
|
222
|
+
uint32_t row = rows[place];
|
|
223
|
+
uint32_t field = keys->fields[row];
|
|
224
|
+
if (keyword_searchable(pass, field)) {
|
|
225
|
+
score += keyword_row_score(pass, idf, (double)frequencies[row], field, ordinal);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return score;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
static uint32_t score_essential_lists(const keyword_pass *pass, row_check *check) {
|
|
233
|
+
keyword_scratch *scratch = pass->scratch;
|
|
234
|
+
const double *remaining_bounds = scratch->remaining_bounds;
|
|
235
|
+
uint32_t essential = 0;
|
|
236
|
+
int checked = 0;
|
|
237
|
+
double threshold_ceiling = 0;
|
|
238
|
+
for (; essential < pass->list_count; essential++) {
|
|
239
|
+
double remaining = remaining_bounds[essential];
|
|
240
|
+
if (essential > 0 && scratch->touched_count >= pass->limit && remaining < remaining_bounds[0] - remaining &&
|
|
241
|
+
(!checked || 2 * remaining < threshold_ceiling)) {
|
|
242
|
+
double threshold = keyword_touched_best_score(pass);
|
|
243
|
+
if (remaining * (1 + PRUNING_SLACK) < threshold * (1 - PRUNING_SLACK)) { break; }
|
|
244
|
+
checked = 1;
|
|
245
|
+
threshold_ceiling = threshold + remaining;
|
|
246
|
+
}
|
|
247
|
+
score_every_row(pass, scratch->list_order[essential], check);
|
|
248
|
+
}
|
|
249
|
+
return essential;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
static int order_lists(const keyword_pass *pass, const field_ceiling *ceiling, uint64_t *total_rows) {
|
|
253
|
+
const narsil_keyword_request *request = pass->request;
|
|
254
|
+
keyword_scratch *scratch = pass->scratch;
|
|
255
|
+
uint32_t list_count = pass->list_count;
|
|
256
|
+
double document_ceiling = ceiling->row_weight * (double)ceiling->rows_per_document;
|
|
257
|
+
for (uint32_t list = 0; list < list_count; list++) {
|
|
258
|
+
double idf = keyword_idf(keyword_list_value(request, list, NARSIL_KEYWORD_LIST_DOCUMENT_FREQUENCY),
|
|
259
|
+
request->total_documents);
|
|
260
|
+
if (!(idf >= 0 && idf <= DBL_MAX)) { return 0; }
|
|
261
|
+
*total_rows += keyword_list_length(request, list);
|
|
262
|
+
scratch->list_idfs[list] = idf;
|
|
263
|
+
scratch->list_bounds[list] = idf * document_ceiling;
|
|
264
|
+
scratch->list_order[list] = list;
|
|
265
|
+
}
|
|
266
|
+
sort_lists_by_bound(scratch, list_count);
|
|
267
|
+
double *remaining = scratch->remaining_bounds;
|
|
268
|
+
remaining[list_count] = 0;
|
|
269
|
+
for (uint32_t place = list_count; place > 0; place--) {
|
|
270
|
+
remaining[place - 1] = remaining[place] + scratch->list_bounds[scratch->list_order[place - 1]];
|
|
271
|
+
}
|
|
272
|
+
return remaining[0] <= DBL_MAX;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
static uint32_t score_in_full_after_pruning(const keyword_pass *pass) {
|
|
276
|
+
pass->output->scoring_path = NARSIL_KEYWORD_PRUNED_THEN_FULL;
|
|
277
|
+
return keyword_score_every_slot(pass);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
static void mark_touched(const keyword_pass *pass) {
|
|
281
|
+
const keyword_scratch *scratch = pass->scratch;
|
|
282
|
+
for (uint32_t index = 0; index < scratch->touched_count; index++) {
|
|
283
|
+
keyword_mark_matched(pass->output->matched, scratch->touched[index]);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
uint32_t keyword_score_pruned(const keyword_pass *pass) {
|
|
288
|
+
field_ceiling ceiling;
|
|
289
|
+
if (!prunable(pass, &ceiling)) { return KEYWORD_NOT_PRUNED; }
|
|
290
|
+
const narsil_keyword_request *request = pass->request;
|
|
291
|
+
keyword_scratch *scratch = pass->scratch;
|
|
292
|
+
narsil_keyword_output *output = pass->output;
|
|
293
|
+
uint64_t total_rows = 0;
|
|
294
|
+
if (!order_lists(pass, &ceiling, &total_rows)) { return KEYWORD_NOT_PRUNED; }
|
|
295
|
+
size_t bitset_bytes = (size_t)pass->scorable_words * sizeof *scratch->seen_bits;
|
|
296
|
+
memset(scratch->seen_bits, 0, bitset_bytes);
|
|
297
|
+
memset(scratch->counted_bits, 0, bitset_bytes);
|
|
298
|
+
scratch->touched_count = 0;
|
|
299
|
+
row_check check = {ceiling.rows_per_document, 0};
|
|
300
|
+
uint32_t essential = score_essential_lists(pass, &check);
|
|
301
|
+
if (request->collect) { keyword_clear_matched(pass); }
|
|
302
|
+
uint32_t counted = 0;
|
|
303
|
+
for (uint32_t rest = essential; rest < pass->list_count; rest++) {
|
|
304
|
+
counted += score_known_rows(pass, scratch->list_order[rest], &check);
|
|
305
|
+
}
|
|
306
|
+
if (check.exceeded) { return score_in_full_after_pruning(pass); }
|
|
307
|
+
if (request->collect) { mark_touched(pass); }
|
|
308
|
+
double floor =
|
|
309
|
+
scratch->touched_count > pass->limit ? keyword_touched_best_score(pass) * (1 - PRUNING_SLACK) : -HUGE_VAL;
|
|
310
|
+
uint32_t candidates = 0;
|
|
311
|
+
for (uint32_t index = 0; index < scratch->touched_count; index++) {
|
|
312
|
+
uint32_t ordinal = scratch->touched[index];
|
|
313
|
+
if (scratch->scores[ordinal] >= floor) { output->ordinals[candidates++] = (int32_t)ordinal; }
|
|
314
|
+
}
|
|
315
|
+
if ((uint64_t)candidates * pass->list_count > total_rows) { return score_in_full_after_pruning(pass); }
|
|
316
|
+
keyword_row_keys keys;
|
|
317
|
+
keyword_list_keys(pass, 0, &keys);
|
|
318
|
+
for (uint32_t place = 0; place < candidates; place++) {
|
|
319
|
+
output->scores[place] = exact_score(pass, &keys, (uint32_t)output->ordinals[place]);
|
|
320
|
+
}
|
|
321
|
+
output->total_matched = scratch->touched_count + counted;
|
|
322
|
+
output->scoring_path = NARSIL_KEYWORD_PRUNED;
|
|
323
|
+
return keyword_keep_best(pass, candidates);
|
|
324
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#include "pass.h"
|
|
2
|
+
#include "score.h"
|
|
3
|
+
#include "scratch.h"
|
|
4
|
+
|
|
5
|
+
#include "../internal.h"
|
|
6
|
+
|
|
7
|
+
#include "../../include/narsil_core.h"
|
|
8
|
+
#include "../../include/narsil_keyword.h"
|
|
9
|
+
|
|
10
|
+
#include <stddef.h>
|
|
11
|
+
#include <stdint.h>
|
|
12
|
+
|
|
13
|
+
#define KNOWN_LIST_FLAGS (NARSIL_KEYWORD_LIST_FROM_ROWS | NARSIL_KEYWORD_LIST_ORDERED)
|
|
14
|
+
#define MAX_SLOT_TERM 0xFFFFU
|
|
15
|
+
|
|
16
|
+
typedef struct {
|
|
17
|
+
keyword_needs *needs;
|
|
18
|
+
keyword_pass *pass;
|
|
19
|
+
uint64_t total_rows;
|
|
20
|
+
} request_check;
|
|
21
|
+
|
|
22
|
+
static int read_limit(double limit, keyword_pass *pass) {
|
|
23
|
+
pass->has_limit = 0;
|
|
24
|
+
pass->limit = 0;
|
|
25
|
+
if (limit == NARSIL_KEYWORD_NO_LIMIT || limit != limit) { return 1; }
|
|
26
|
+
if (!(limit >= 0)) { return 0; }
|
|
27
|
+
pass->has_limit = 1;
|
|
28
|
+
if (limit >= (double)UINT32_MAX) {
|
|
29
|
+
pass->limit = UINT32_MAX;
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
pass->limit = (uint32_t)limit;
|
|
33
|
+
return (double)pass->limit == limit;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static int rows_are_present(const narsil_keyword_request *request) {
|
|
37
|
+
if (request->pool_length > 0 &&
|
|
38
|
+
(request->pool_doc_ids == NULL || request->pool_frequencies == NULL || request->pool_fields == NULL)) {
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
return request->row_length == 0 ||
|
|
42
|
+
(request->row_doc_ids != NULL && request->row_frequencies != NULL && request->row_fields != NULL);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static int bitsets_are_present(const narsil_keyword_request *request) {
|
|
46
|
+
if (request->live_words > 0 && request->live == NULL) { return 0; }
|
|
47
|
+
if (request->removed_words > 0 && request->removed == NULL) { return 0; }
|
|
48
|
+
return !request->has_filter || request->filter_words == 0 || request->filter != NULL;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static int fields_are_present(const narsil_keyword_request *request) {
|
|
52
|
+
uint32_t count = request->field_count;
|
|
53
|
+
if (count > NARSIL_KEYWORD_MAX_FIELDS) { return 0; }
|
|
54
|
+
if (count == 0) { return 1; }
|
|
55
|
+
if (request->searchable == NULL || request->partial_marks == NULL || request->name_ranks == NULL ||
|
|
56
|
+
request->field_numbers == NULL || request->lengths == NULL) {
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
for (uint32_t field = 0; field < count; field++) {
|
|
60
|
+
if (request->lengths[field].length > 0 && request->lengths[field].values == NULL) { return 0; }
|
|
61
|
+
}
|
|
62
|
+
return 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static int slots_are_valid(const narsil_keyword_request *request, request_check *check) {
|
|
66
|
+
if (request->slot_count > request->slot_capacity || (request->slot_count > 0 && request->slots == NULL)) { return 0; }
|
|
67
|
+
uint32_t list_from = 0;
|
|
68
|
+
uint32_t value_from = 0;
|
|
69
|
+
for (uint32_t slot = 0; slot < request->slot_count; slot++) {
|
|
70
|
+
const uint32_t *words = request->slots + ((size_t)slot * NARSIL_KEYWORD_SLOT_STRIDE);
|
|
71
|
+
uint32_t kind = words[NARSIL_KEYWORD_SLOT_KIND];
|
|
72
|
+
uint32_t list_end = words[NARSIL_KEYWORD_SLOT_LIST_END];
|
|
73
|
+
uint32_t value_end = words[NARSIL_KEYWORD_SLOT_VALUE_END];
|
|
74
|
+
if (kind > NARSIL_KEYWORD_PHRASE_SLOT || words[NARSIL_KEYWORD_SLOT_TERM] > MAX_SLOT_TERM || list_end < list_from ||
|
|
75
|
+
list_end > request->list_capacity || value_end < value_from || value_end > request->slot_value_capacity) {
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
if (kind == NARSIL_KEYWORD_GROUP_SLOT) {
|
|
79
|
+
if (value_end == value_from) { return 0; }
|
|
80
|
+
check->needs->groups = 1;
|
|
81
|
+
}
|
|
82
|
+
list_from = list_end;
|
|
83
|
+
value_from = value_end;
|
|
84
|
+
}
|
|
85
|
+
if (value_from > 0 && request->slot_values == NULL) { return 0; }
|
|
86
|
+
check->pass->list_count = list_from;
|
|
87
|
+
return 1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static int lists_are_valid(const narsil_keyword_request *request, request_check *check) {
|
|
91
|
+
uint32_t list_count = check->pass->list_count;
|
|
92
|
+
if (list_count > 0 && (request->lists == NULL || request->list_values == NULL)) { return 0; }
|
|
93
|
+
uint32_t longest = 0;
|
|
94
|
+
for (uint32_t list = 0; list < list_count; list++) {
|
|
95
|
+
uint32_t flags = keyword_list_flags(request, list);
|
|
96
|
+
uint32_t start = keyword_list_start(request, list);
|
|
97
|
+
uint32_t length = keyword_list_length(request, list);
|
|
98
|
+
uint32_t rows = (flags & NARSIL_KEYWORD_LIST_FROM_ROWS) != 0 ? request->row_length : request->pool_length;
|
|
99
|
+
if ((flags & ~KNOWN_LIST_FLAGS) != 0 || start > rows || length > rows - start) { return 0; }
|
|
100
|
+
if (length > longest) { longest = length; }
|
|
101
|
+
check->total_rows += length;
|
|
102
|
+
}
|
|
103
|
+
check->needs->order = longest;
|
|
104
|
+
check->needs->lists = list_count;
|
|
105
|
+
return 1;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static int output_is_valid(const narsil_keyword_request *request, const narsil_keyword_output *output) {
|
|
109
|
+
uint32_t capacity = request->capacity;
|
|
110
|
+
if (capacity > (uint32_t)INT32_MAX || capacity > output->length) { return 0; }
|
|
111
|
+
if (output->length > 0 && (output->ordinals == NULL || output->scores == NULL)) { return 0; }
|
|
112
|
+
uint32_t words = keyword_words_for(capacity);
|
|
113
|
+
return !request->collect || (output->matched_words >= words && (words == 0 || output->matched != NULL));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
static void load_pass(const narsil_keyword_request *request, request_check *check) {
|
|
117
|
+
keyword_pass *pass = check->pass;
|
|
118
|
+
keyword_needs *needs = check->needs;
|
|
119
|
+
uint32_t count = request->field_count;
|
|
120
|
+
const double *numbers = request->field_numbers;
|
|
121
|
+
pass->request = request;
|
|
122
|
+
pass->field_count = count;
|
|
123
|
+
pass->capacity = request->capacity;
|
|
124
|
+
pass->boosts = numbers == NULL ? NULL : numbers + ((size_t)NARSIL_KEYWORD_FIELD_BOOSTS * count);
|
|
125
|
+
pass->averages = numbers == NULL ? NULL : numbers + ((size_t)NARSIL_KEYWORD_FIELD_AVERAGE_LENGTHS * count);
|
|
126
|
+
pass->k1s = numbers == NULL ? NULL : numbers + ((size_t)NARSIL_KEYWORD_FIELD_K1 * count);
|
|
127
|
+
pass->bs = numbers == NULL ? NULL : numbers + ((size_t)NARSIL_KEYWORD_FIELD_B * count);
|
|
128
|
+
double terms = request->terms;
|
|
129
|
+
double required = request->term_match > 0 && terms > 0 ? request->term_match : 0;
|
|
130
|
+
pass->tracks_coverage = required > 0 && required <= terms;
|
|
131
|
+
needs->coverage = pass->tracks_coverage;
|
|
132
|
+
needs->capacity = request->capacity;
|
|
133
|
+
needs->selection = pass->has_limit && pass->limit < request->capacity ? pass->limit : request->capacity;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
static void build_scorable(keyword_pass *pass, uint32_t *bits) {
|
|
137
|
+
const narsil_keyword_request *request = pass->request;
|
|
138
|
+
uint32_t words = keyword_words_for(pass->capacity);
|
|
139
|
+
for (uint32_t word = 0; word < words; word++) {
|
|
140
|
+
uint32_t value = word < request->live_words ? request->live[word] : 0;
|
|
141
|
+
if (word < request->removed_words) { value &= ~request->removed[word]; }
|
|
142
|
+
if (request->has_filter) { value &= word < request->filter_words ? request->filter[word] : 0; }
|
|
143
|
+
bits[word] = value;
|
|
144
|
+
}
|
|
145
|
+
uint32_t tail = pass->capacity & KEYWORD_BIT_MASK;
|
|
146
|
+
if (tail != 0) { bits[words - 1] &= (1U << tail) - 1U; }
|
|
147
|
+
pass->scorable_bits = bits;
|
|
148
|
+
pass->scorable_words = words;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static int request_is_valid(const narsil_keyword_request *request, const narsil_keyword_output *output,
|
|
152
|
+
request_check *check) {
|
|
153
|
+
return read_limit(request->limit, check->pass) && rows_are_present(request) && bitsets_are_present(request) &&
|
|
154
|
+
fields_are_present(request) && slots_are_valid(request, check) && lists_are_valid(request, check) &&
|
|
155
|
+
output_is_valid(request, output);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
narsil_status narsil_keyword_score(narsil_workspace *workspace, const narsil_keyword_request *request,
|
|
159
|
+
narsil_keyword_output *output) {
|
|
160
|
+
if (workspace == NULL || request == NULL || output == NULL) { return NARSIL_INVALID_ARGUMENT; }
|
|
161
|
+
keyword_needs needs = {0, 0, 0, 0, 0, 0};
|
|
162
|
+
keyword_pass pass = {0};
|
|
163
|
+
request_check check = {&needs, &pass, 0};
|
|
164
|
+
output->count = 0;
|
|
165
|
+
output->total_matched = 0;
|
|
166
|
+
output->scoring_path = NARSIL_KEYWORD_SCORED_IN_FULL;
|
|
167
|
+
if (!request_is_valid(request, output, &check)) { return NARSIL_INVALID_ARGUMENT; }
|
|
168
|
+
load_pass(request, &check);
|
|
169
|
+
keyword_scratch *scratch = workspace_keyword_scratch(workspace);
|
|
170
|
+
narsil_status status = keyword_reserve(scratch, &needs);
|
|
171
|
+
if (status != NARSIL_OK) { return status; }
|
|
172
|
+
pass.scratch = scratch;
|
|
173
|
+
pass.output = output;
|
|
174
|
+
if (pass.capacity > 0 && keyword_words_for(pass.capacity) <= check.total_rows) {
|
|
175
|
+
build_scorable(&pass, scratch->scorable);
|
|
176
|
+
}
|
|
177
|
+
if (keyword_score_pruned(&pass) == KEYWORD_NOT_PRUNED) { keyword_score_every_slot(&pass); }
|
|
178
|
+
return NARSIL_OK;
|
|
179
|
+
}
|