mini_search 1.0.3

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.
@@ -0,0 +1,34 @@
1
+ module MiniSearch
2
+ RSpec.describe InvertedIndex do
3
+ subject { InvertedIndex.new }
4
+
5
+ it "indexes documents and searches them" do
6
+ subject.index(id: 1, indexed_field: 'red duck')
7
+ subject.index(id: 2, indexed_field: 'yellow big dog')
8
+ subject.index(id: 3, indexed_field: 'small cat')
9
+ subject.index(id: 4, indexed_field: 'red monkey noisy')
10
+ subject.index(id: 5, indexed_field: 'small horse')
11
+ subject.index(id: 6, indexed_field: 'purple turtle')
12
+ subject.index(id: 7, indexed_field: 'tiny red spider')
13
+ subject.index(id: 8, indexed_field: 'big blue whale')
14
+ subject.index(id: 9, indexed_field: 'huge elephant')
15
+ subject.index(id: 10, indexed_field: 'red big cat')
16
+
17
+ expect(subject.search('red cat')).to eq([
18
+ # 10 - matches both red and cat so it is the first
19
+ { document: { id: 10, indexed_field: 'red big cat' }, score: 0.4666666666666667 },
20
+
21
+ # 3 - matches cat so it is the second as cat has a bigger IDF (it is more uncommon)
22
+ { document: { id: 3, indexed_field: 'small cat' }, score: 0.4 },
23
+
24
+ # 1 - matches red but has only 2 terms, so the red here has a bigger weight
25
+ { document: { id: 1, indexed_field: 'red duck' }, score: 0.3 },
26
+
27
+ # 4, 7 - both match red as well, but they have 3 terms, so red here has a lower frequency (tf)
28
+ # comparing with 1
29
+ { document: { id: 4, indexed_field: 'red monkey noisy' }, score: 0.19999999999999998 },
30
+ { document: { id: 7, indexed_field: 'tiny red spider' }, score: 0.19999999999999998 }
31
+ ])
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ module MiniSearch
2
+ module LanguageSupport
3
+ class Portuguese
4
+ attr_reader :stemmer, :stop_words
5
+
6
+ def initialize(stop_words = [])
7
+ @stemmer = ::MiniSearch::Stemmer::Portuguese.new
8
+ @stop_words = %w[
9
+ a á à ainda alem ambas ambos antes ao aonde aos apos aquele aqueles as assim com como contra contudo cuja cujas cujo cujos da
10
+ das de dela dele deles demais depois desde desta deste dispoe dispoem diversa diversas diversos do dos durante e é ela elas
11
+ ele eles em entao entre essa essas esse esses esta estas este estes ha isso isto logo mais mas mediante menos mesma mesmas mesmo
12
+ mesmos na nas nao nas nem nesse neste nos o os ou outra outras outro outros pela pelas pelas pelo pelos perante pois por porque portanto
13
+ proprio quais qual qualquer quando quanto que quem quer se seja sem sendo seu seus sob sobre sua suas tal tambem teu
14
+ teus toda todas todo todos tua tuas tudo um uma umas uns
15
+ ] + stop_words
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniSearch
4
+ # All the transformations and normalizations we need to
5
+ # do when indexing a document or searching
6
+ class Pipeline
7
+ def initialize(tokenizer, filters)
8
+ @tokenizer = tokenizer
9
+ @filters = filters
10
+ end
11
+
12
+ def execute(string)
13
+ tokens = @tokenizer.execute(string)
14
+
15
+ @filters.reduce(tokens) do |filtered_tokens, filter|
16
+ filter.execute(filtered_tokens)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniSearch
4
+ class RemovePunctuationFilter
5
+ def execute(tokens)
6
+ tokens.map do |token|
7
+ token.tr(',.!;:', '')
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MiniSearch
4
+ class StandardWhitespaceTokenizer
5
+ def execute(string)
6
+ string.strip.split(' ')
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,365 @@
1
+ module MiniSearch
2
+ module Stemmer
3
+ # Implementation of the algorithm for the RSLP Stemmer which was presented by the paper
4
+ # 'A Stemming Algorithm for the Portuguese Language'.
5
+ #
6
+ # In Proceedings of the SPIRE Conference, Laguna de San Raphael, Chile, November 13-15, 2001,
7
+ # written by Viviane Moreira Orengo and Christian Huyck.
8
+ #
9
+ # More info: http://www.inf.ufrgs.br/~viviane/rslp/index.htm
10
+ # Datasets got from: https://www.kaggle.com/nltkdata/rslp-stemmer
11
+ #
12
+ class Portuguese
13
+ def initialize
14
+ @rules_sets = {
15
+ 'plural_reduction' => plural_reduction,
16
+ 'feminine_reduction' => feminine_reduction,
17
+ 'augmentative_diminutive_reduction' => augmentative_diminutive_reduction,
18
+ 'adverb_reduction' => adverb_reduction,
19
+ 'noun_suffix_reduction' => noun_suffix_reduction,
20
+ 'verb_suffix_reduction' => verb_suffix_reduction,
21
+ 'vowel_removal' => vowel_removal
22
+ }
23
+ end
24
+
25
+ def stem(word)
26
+ if word.end_with?('s')
27
+ word = apply_rule('plural_reduction', word)
28
+ end
29
+
30
+ if word.end_with?('a')
31
+ word = apply_rule('feminine_reduction', word)
32
+ end
33
+
34
+ word = apply_rule('augmentative_diminutive_reduction', word)
35
+
36
+ word = apply_rule('adverb_reduction', word)
37
+
38
+ prev_word = word
39
+ word = apply_rule('noun_suffix_reduction', word)
40
+
41
+ if word == prev_word
42
+ prev_word = word
43
+ word = apply_rule('verb_suffix_reduction', word)
44
+
45
+ if word == prev_word
46
+ word = apply_rule('vowel_removal', word)
47
+ end
48
+ end
49
+
50
+ word
51
+ end
52
+
53
+ private
54
+
55
+ def apply_rule(rule_name, word)
56
+ @rules_sets[rule_name].each do |rule|
57
+ suffix = rule[0]
58
+ min_suffix_length = rule[1]
59
+ replacement = rule[2]
60
+ exceptions = rule[3]
61
+
62
+ # next unless suffix matches
63
+ next unless word.end_with?(suffix)
64
+
65
+ # next unless we have minimum size
66
+ next unless word.length >= suffix.length + min_suffix_length
67
+
68
+ # next if word is an exception
69
+ next if exceptions.include?(word)
70
+
71
+ word = "#{word[0, word.length - suffix.length]}#{replacement}"
72
+
73
+ break
74
+ end
75
+
76
+ word
77
+ end
78
+
79
+ def format_rules(rules)
80
+ rules.map do |rule|
81
+ [
82
+ rule[0],
83
+ rule[1].to_i,
84
+ rule[2],
85
+ (rule[3] == '*' ? [] : rule[3].split(','))
86
+ ]
87
+ end
88
+ end
89
+
90
+ def plural_reduction
91
+ format_rules [
92
+ ['ns', '1', 'm', '*'],
93
+ ['ões', '3', 'ão', '*'],
94
+ ['ães', '1', 'ão', 'mãe'],
95
+ ['ais', '1', 'al', 'cais,mais'],
96
+ ['éis', '2', 'el', '*'],
97
+ ['eis', '2', 'el', '*'],
98
+ ['óis', '2', 'ol', '*'],
99
+ ['is', '2', 'il', 'lápis,cais,mais,crúcis,biquínis,pois,depois,dois,leis'],
100
+ ['les', '3', 'l', '*'],
101
+ ['res', '3', 'r', 'árvores'],
102
+ ['s', '2', '', 'aliás,pires,lápis,cais,mais,mas,menos,férias,fezes,pêsames,crúcis,gás,atrás,moisés,através,convés,ês,país,após,ambas,ambos,messias,depois']
103
+ ]
104
+ end
105
+
106
+ def feminine_reduction
107
+ format_rules [
108
+ ['ona', '3', 'ão', 'abandona,lona,iona,cortisona,monótona,maratona,acetona,detona,carona'],
109
+ ['ora', '3', 'or', '*'],
110
+ ['na', '4', 'no', 'carona,abandona,lona,iona,cortisona,monótona,maratona,acetona,detona,guiana,campana,grana,caravana,banana,paisana'],
111
+ ['inha', '3', 'inho', 'rainha,linha,minha'],
112
+ ['esa', '3', 'ês', 'mesa,obesa,princesa,turquesa,ilesa,pesa,presa'],
113
+ ['osa', '3', 'oso', 'mucosa,prosa'],
114
+ ['íaca', '3', 'íaco', '*'],
115
+ ['ica', '3', 'ico', 'dica'],
116
+ ['ada', '2', 'ado', 'pitada'],
117
+ ['ida', '3', 'ido', 'vida'],
118
+ ['ída', '3', 'ido', 'recaída,saída,dúvida'],
119
+ ['ima', '3', 'imo', 'vítima'],
120
+ ['iva', '3', 'ivo', 'saliva,oliva'],
121
+ ['eira', '3', 'eiro', 'beira,cadeira,frigideira,bandeira,feira,capoeira,barreira,fronteira,besteira,poeira'],
122
+ ['ã', '2', 'ão', 'amanhã,arapuã,fã,divã']
123
+ ]
124
+ end
125
+
126
+ def adverb_reduction
127
+ format_rules [
128
+ ['mente', '4', '', 'experimente']
129
+ ]
130
+ end
131
+
132
+ def augmentative_diminutive_reduction
133
+ format_rules [
134
+ ['díssimo', '5', '', '*'],
135
+ ['abilíssimo', '5', '', '*'],
136
+ ['íssimo', '3', '', '*'],
137
+ ['ésimo', '3', '', '*'],
138
+ ['érrimo', '4', '', '*'],
139
+ ['zinho', '2', '', '*'],
140
+ ['quinho', '4', 'c', '*'],
141
+ ['uinho', '4', '', '*'],
142
+ ['adinho', '3', '', '*'],
143
+ ['inho', '3', '', 'caminho,cominho'],
144
+ ['alhão', '4', '', '*'],
145
+ ['uça', '4', '', '*'],
146
+ ['aço', '4', '', 'antebraço'],
147
+ ['aça', '4', '', '*'],
148
+ ['adão', '4', '', '*'],
149
+ ['idão', '4', '', '*'],
150
+ ['ázio', '3', '', 'topázio'],
151
+ ['arraz', '4', '', '*'],
152
+ ['zarrão', '3', '', '*'],
153
+ ['arrão', '4', '', '*'],
154
+ ['arra', '3', '', '*'],
155
+ ['zão', '2', '', 'coalizão'],
156
+ ['ão', '3', '', 'camarão,chimarrão,canção,coração,embrião,grotão,glutão,ficção,fogão,feição,furacão,gamão,lampião,leão,macacão,nação,órfão,orgão,patrão,portão,quinhão,rincão,tração,falcão,espião,mamão,folião,cordão,aptidão,campeão,colchão,limão,leilão,melão,barão,milhão,bilhão,fusão,cristão,ilusão,capitão,estação,senão']
157
+ ]
158
+ end
159
+
160
+ def noun_suffix_reduction
161
+ format_rules [
162
+ ['encialista', '4', '', '*'],
163
+ ['alista', '5', '', '*'],
164
+ ['agem', '3', '', 'coragem,chantagem,vantagem,carruagem'],
165
+ ['iamento', '4', '', '*'],
166
+ ['amento', '3', '', 'firmamento,fundamento,departamento'],
167
+ ['imento', '3', '', '*'],
168
+ ['mento', '6', '', 'firmamento,elemento,complemento,instrumento,departamento'],
169
+ ['alizado', '4', '', '*'],
170
+ ['atizado', '4', '', '*'],
171
+ ['tizado', '4', '', 'alfabetizado'],
172
+ ['izado', '5', '', 'organizado,pulverizado'],
173
+ ['ativo', '4', '', 'pejorativo,relativo'],
174
+ ['tivo', '4', '', 'relativo'],
175
+ ['ivo', '4', '', 'passivo,possessivo,pejorativo,positivo'],
176
+ ['ado', '2', '', 'grado'],
177
+ ['ido', '3', '', 'cândido,consolido,rápido,decido,tímido,duvido,marido'],
178
+ ['ador', '3', '', '*'],
179
+ ['edor', '3', '', '*'],
180
+ ['idor', '4', '', 'ouvidor'],
181
+ ['dor', '4', '', 'ouvidor'],
182
+ ['sor', '4', '', 'assessor'],
183
+ ['atoria', '5', '', '*'],
184
+ ['tor', '3', '', 'benfeitor,leitor,editor,pastor,produtor,promotor,consultor'],
185
+ ['or', '2', '', 'motor,melhor,redor,rigor,sensor,tambor,tumor,assessor,benfeitor,pastor,terior,favor,autor'],
186
+ ['abilidade', '5', '', '*'],
187
+ ['icionista', '4', '', '*'],
188
+ ['cionista', '5', '', '*'],
189
+ ['ionista', '5', '', '*'],
190
+ ['ionar', '5', '', '*'],
191
+ ['ional', '4', '', '*'],
192
+ ['ência', '3', '', '*'],
193
+ ['ância', '4', '', 'ambulância'],
194
+ ['edouro', '3', '', '*'],
195
+ ['queiro', '3', 'c', '*'],
196
+ ['adeiro', '4', '', 'desfiladeiro'],
197
+ ['eiro', '3', '', 'desfiladeiro,pioneiro,mosteiro'],
198
+ ['uoso', '3', '', '*'],
199
+ ['oso', '3', '', 'precioso'],
200
+ ['alizaç', '5', '', '*'],
201
+ ['atizaç', '5', '', '*'],
202
+ ['tizaç', '5', '', '*'],
203
+ ['izaç', '5', '', 'organizaç'],
204
+ ['aç', '3', '', 'equaç,relaç'],
205
+ ['iç', '3', '', 'eleição'],
206
+ ['ário', '3', '', 'voluntário,salário,aniversário,diário,lionário,armárioatório,3rio,5,,voluntário,salário,aniversário,diário,compulsório,lionário,próprio,stério,armário'],
207
+ ['ério', '6', '', '*'],
208
+ ['ês', '4', '', '*'],
209
+ ['eza', '3', '', '*'],
210
+ ['ez', '4', '', '*'],
211
+ ['esco', '4', '', '*'],
212
+ ['ante', '2', '', 'gigante,elefante,adiante,possante,instante,restaurante'],
213
+ ['ástico', '4', '', 'eclesiástico'],
214
+ ['alístico', '3', '', '*'],
215
+ ['áutico', '4', '', '*'],
216
+ ['êutico', '4', '', '*'],
217
+ ['tico', '3', '', 'político,eclesiástico,diagnostico,prático,doméstico,diagnóstico,idêntico,alopático,artístico,autêntico,eclético,crítico,critico'],
218
+ ['ico', '4', '', 'tico,público,explico'],
219
+ ['ividade', '5', '', '*'],
220
+ ['idade', '4', '', 'autoridade,comunidade'],
221
+ ['oria', '4', '', 'categoria'],
222
+ ['encial', '5', '', '*'],
223
+ ['ista', '4', '', '*'],
224
+ ['auta', '5', '', '*'],
225
+ ['quice', '4', 'c', '*'],
226
+ ['ice', '4', '', 'cúmplice'],
227
+ ['íaco', '3', '', '*'],
228
+ ['ente', '4', '', 'freqüente,alimente,acrescente,permanente,oriente,aparente'],
229
+ ['ense', '5', '', '*'],
230
+ ['inal', '3', '', '*'],
231
+ ['ano', '4', '', '*'],
232
+ ['ável', '2', '', 'afável,razoável,potável,vulnerável'],
233
+ ['ível', '3', '', 'possível'],
234
+ ['vel', '5', '', 'possível,vulnerável,solúvel'],
235
+ ['bil', '3', 'vel', '*'],
236
+ ['ura', '4', '', 'imatura,acupuntura,costura'],
237
+ ['ural', '4', '', '*'],
238
+ ['ual', '3', '', 'bissexual,virtual,visual,pontual'],
239
+ ['ial', '3', '', '*'],
240
+ ['al', '4', '', 'afinal,animal,estatal,bissexual,desleal,fiscal,formal,pessoal,liberal,postal,virtual,visual,pontual,sideral,sucursal'],
241
+ ['alismo', '4', '', '*'],
242
+ ['ivismo', '4', '', '*'],
243
+ ['ismo', '3', '', 'cinismo']
244
+ ]
245
+ end
246
+
247
+ def verb_suffix_reduction
248
+ format_rules [
249
+ ['aríamo', '2', '', '*'],
250
+ ['ássemo', '2', '', '*'],
251
+ ['eríamo', '2', '', '*'],
252
+ ['êssemo', '2', '', '*'],
253
+ ['iríamo', '3', '', '*'],
254
+ ['íssemo', '3', '', '*'],
255
+ ['áramo', '2', '', '*'],
256
+ ['árei', '2', '', '*'],
257
+ ['aremo', '2', '', '*'],
258
+ ['ariam', '2', '', '*'],
259
+ ['aríei', '2', '', '*'],
260
+ ['ássei', '2', '', '*'],
261
+ ['assem', '2', '', '*'],
262
+ ['ávamo', '2', '', '*'],
263
+ ['êramo', '3', '', '*'],
264
+ ['eremo', '3', '', '*'],
265
+ ['eriam', '3', '', '*'],
266
+ ['eríei', '3', '', '*'],
267
+ ['êssei', '3', '', '*'],
268
+ ['essem', '3', '', '*'],
269
+ ['íramo', '3', '', '*'],
270
+ ['iremo', '3', '', '*'],
271
+ ['iriam', '3', '', '*'],
272
+ ['iríei', '3', '', '*'],
273
+ ['íssei', '3', '', '*'],
274
+ ['issem', '3', '', '*'],
275
+ ['ando', '2', '', '*'],
276
+ ['endo', '3', '', '*'],
277
+ ['indo', '3', '', '*'],
278
+ ['ondo', '3', '', '*'],
279
+ ['aram', '2', '', '*'],
280
+ ['arão', '2', '', '*'],
281
+ ['arde', '2', '', '*'],
282
+ ['arei', '2', '', '*'],
283
+ ['arem', '2', '', '*'],
284
+ ['aria', '2', '', '*'],
285
+ ['armo', '2', '', '*'],
286
+ ['asse', '2', '', '*'],
287
+ ['aste', '2', '', '*'],
288
+ ['avam', '2', '', 'agravam'],
289
+ ['ávei', '2', '', '*'],
290
+ ['eram', '3', '', '*'],
291
+ ['erão', '3', '', '*'],
292
+ ['erde', '3', '', '*'],
293
+ ['erei', '3', '', '*'],
294
+ ['êrei', '3', '', '*'],
295
+ ['erem', '3', '', '*'],
296
+ ['eria', '3', '', '*'],
297
+ ['ermo', '3', '', '*'],
298
+ ['esse', '3', '', '*'],
299
+ ['este', '3', '', 'faroeste,agreste'],
300
+ ['íamo', '3', '', '*'],
301
+ ['iram', '3', '', '*'],
302
+ ['íram', '3', '', '*'],
303
+ ['irão', '2', '', '*'],
304
+ ['irde', '2', '', '*'],
305
+ ['irei', '3', '', 'admirei'],
306
+ ['irem', '3', '', 'adquirem'],
307
+ ['iria', '3', '', '*'],
308
+ ['irmo', '3', '', '*'],
309
+ ['isse', '3', '', '*'],
310
+ ['iste', '4', '', '*'],
311
+ ['iava', '4', '', 'ampliava'],
312
+ ['amo', '2', '', '*'],
313
+ ['iona', '3', '', '*'],
314
+ ['ara', '2', '', 'arara,prepara'],
315
+ ['ará', '2', '', 'alvará'],
316
+ ['are', '2', '', 'prepare'],
317
+ ['ava', '2', '', 'agrava'],
318
+ ['emo', '2', '', '*'],
319
+ ['era', '3', '', 'acelera,espera'],
320
+ ['erá', '3', '', '*'],
321
+ ['ere', '3', '', 'espere'],
322
+ ['iam', '3', '', 'enfiam,ampliam,elogiam,ensaiam'],
323
+ ['íei', '3', '', '*'],
324
+ ['imo', '3', '', 'reprimo,intimo,íntimo,nimo,queimo,ximo'],
325
+ ['ira', '3', '', 'fronteira,sátira'],
326
+ ['ído', '3', '', 'irá'],
327
+ ['tizar', '4', '', 'alfabetizar'],
328
+ ['izar', '5', '', 'organizar'],
329
+ ['itar', '5', '', 'acreditar,explicitar,estreitar'],
330
+ ['ire', '3', '', 'adquire'],
331
+ ['omo', '3', '', '*'],
332
+ ['ai', '2', '', '*'],
333
+ ['am', '2', '', '*'],
334
+ ['ear', '4', '', 'alardear,nuclear'],
335
+ ['ar', '2', '', 'azar,bazaar,patamar'],
336
+ ['uei', '3', '', '*'],
337
+ ['uía', '5', 'u', '*'],
338
+ ['ei', '3', '', '*'],
339
+ ['guem', '3', 'g', '*'],
340
+ ['em', '2', '', 'alem,virgem'],
341
+ ['er', '2', '', 'éter,pier'],
342
+ ['eu', '3', '', 'chapeu'],
343
+ ['ia', '3', '', 'estória,fatia,acia,praia,elogia,mania,lábia,aprecia,polícia,arredia,cheia,ásia'],
344
+ ['ir', '3', '', 'freir'],
345
+ ['iu', '3', '', '*'],
346
+ ['eou', '5', '', '*'],
347
+ ['ou', '3', '', '*'],
348
+ ['i', '3', '', '*']
349
+ ]
350
+ end
351
+
352
+ def vowel_removal
353
+ format_rules [
354
+ ['bil', '2', 'vel', '*'],
355
+ ['gue', '2', 'g', 'gangue,jegue'],
356
+ ['á', '3', '', '*'],
357
+ ['ê', '3', '', 'bebê'],
358
+ ['a', '3', '', 'ásia'],
359
+ ['e', '3', '', '*'],
360
+ ['o', '3', '', 'ão']
361
+ ]
362
+ end
363
+ end
364
+ end
365
+ end