mini_search 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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