ferret 0.10.14 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/TODO +3 -0
- data/ext/analysis.c +5 -0
- data/ext/compound_io.c +46 -24
- data/ext/except.c +14 -0
- data/ext/except.h +29 -17
- data/ext/ferret.c +22 -1
- data/ext/ferret.h +2 -1
- data/ext/fs_store.c +9 -12
- data/ext/global.c +80 -0
- data/ext/global.h +10 -0
- data/ext/hash.c +0 -7
- data/ext/hash.h +0 -8
- data/ext/index.c +1289 -625
- data/ext/index.h +59 -14
- data/ext/q_boolean.c +12 -5
- data/ext/q_parser.c +570 -372
- data/ext/r_analysis.c +16 -16
- data/ext/r_index.c +41 -43
- data/ext/r_qparser.c +37 -36
- data/ext/r_search.c +10 -10
- data/ext/r_store.c +7 -7
- data/ext/ram_store.c +4 -3
- data/ext/search.c +3 -2
- data/ext/store.c +35 -19
- data/ext/store.h +3 -5
- data/lib/ferret/index.rb +4 -4
- data/lib/ferret_version.rb +1 -1
- data/test/threading/thread_safety_read_write_test.rb +76 -0
- data/test/threading/thread_safety_test.rb +17 -21
- data/test/unit/index/tc_index.rb +6 -2
- data/test/unit/index/tc_index_writer.rb +2 -2
- data/test/unit/query_parser/tc_query_parser.rb +20 -5
- data/test/unit/search/tc_index_searcher.rb +3 -1
- data/test/unit/search/tm_searcher.rb +3 -1
- metadata +3 -2
data/ext/r_search.c
CHANGED
@@ -160,9 +160,9 @@ frt_get_td(TopDocs *td, VALUE rsearcher)
|
|
160
160
|
VALUE rtop_docs;
|
161
161
|
VALUE hit_ary = rb_ary_new2(td->size);
|
162
162
|
|
163
|
-
RARRAY(hit_ary)->len = td->size;
|
164
163
|
for (i = 0; i < td->size; i++) {
|
165
164
|
RARRAY(hit_ary)->ptr[i] = frt_get_hit(td->hits[i]);
|
165
|
+
RARRAY(hit_ary)->len++;
|
166
166
|
}
|
167
167
|
|
168
168
|
rtop_docs = rb_struct_new(cTopDocs,
|
@@ -1015,7 +1015,7 @@ frt_bq_add_query(int argc, VALUE *argv, VALUE self)
|
|
1015
1015
|
rb_raise(rb_eArgError, "Cannot add %s to a BooleanQuery",
|
1016
1016
|
rb_class2name(klass));
|
1017
1017
|
}
|
1018
|
-
return
|
1018
|
+
return self;
|
1019
1019
|
}
|
1020
1020
|
|
1021
1021
|
/****************************************************************************
|
@@ -1206,7 +1206,7 @@ frt_phq_add(int argc, VALUE *argv, VALUE self)
|
|
1206
1206
|
default:
|
1207
1207
|
rb_raise(rb_eArgError, "You can only add a string or an array of "
|
1208
1208
|
"strings to a PhraseQuery, not a %s\n",
|
1209
|
-
|
1209
|
+
rs2s(rb_obj_as_string(rterm)));
|
1210
1210
|
}
|
1211
1211
|
return self;
|
1212
1212
|
}
|
@@ -2258,14 +2258,14 @@ frt_sort_add(Sort *sort, VALUE rsf, bool reverse)
|
|
2258
2258
|
break;
|
2259
2259
|
case T_SYMBOL:
|
2260
2260
|
rsf = rb_obj_as_string(rsf);
|
2261
|
-
sf = sort_field_auto_new(
|
2261
|
+
sf = sort_field_auto_new(rs2s(rsf), reverse);
|
2262
2262
|
/* need to give it a ruby object so it'll be freed when the
|
2263
2263
|
* sort is garbage collected */
|
2264
2264
|
rsf = frt_get_sf(sf);
|
2265
2265
|
sort_add_sort_field(sort, sf);
|
2266
2266
|
break;
|
2267
2267
|
case T_STRING:
|
2268
|
-
frt_parse_sort_str(sort,
|
2268
|
+
frt_parse_sort_str(sort, rs2s(rsf));
|
2269
2269
|
break;
|
2270
2270
|
default:
|
2271
2271
|
rb_raise(rb_eArgError, "Unknown SortField Type");
|
@@ -2697,7 +2697,7 @@ frt_sea_explain(VALUE self, VALUE rquery, VALUE rdoc_id)
|
|
2697
2697
|
* :num_excerpts:: Default: 2. Number of excerpts to return.
|
2698
2698
|
* :pre_tag:: Default: "<b>". Tag to place to the left of the match.
|
2699
2699
|
* You'll probably want to change this to a "<span>" tag
|
2700
|
-
* with a class "\033[7m" for use in a terminal.
|
2700
|
+
* with a class. Try "\033[7m" for use in a terminal.
|
2701
2701
|
* :post_tag:: Default: "</b>". This tag should close the +:pre_tag+.
|
2702
2702
|
* Try tag "\033[m" in the terminal.
|
2703
2703
|
* :ellipsis:: Default: "...". This is the string that is appended at
|
@@ -2733,13 +2733,13 @@ frt_sea_highlight(int argc, VALUE *argv, VALUE self)
|
|
2733
2733
|
}
|
2734
2734
|
}
|
2735
2735
|
if (Qnil != (v = rb_hash_aref(roptions, sym_pre_tag))) {
|
2736
|
-
pre_tag =
|
2736
|
+
pre_tag = rs2s(rb_obj_as_string(v));
|
2737
2737
|
}
|
2738
2738
|
if (Qnil != (v = rb_hash_aref(roptions, sym_post_tag))) {
|
2739
|
-
post_tag =
|
2739
|
+
post_tag = rs2s(rb_obj_as_string(v));
|
2740
2740
|
}
|
2741
2741
|
if (Qnil != (v = rb_hash_aref(roptions, sym_ellipsis))) {
|
2742
|
-
ellipsis =
|
2742
|
+
ellipsis = rs2s(rb_obj_as_string(v));
|
2743
2743
|
}
|
2744
2744
|
|
2745
2745
|
if ((excerpts = searcher_highlight(sea,
|
@@ -2754,10 +2754,10 @@ frt_sea_highlight(int argc, VALUE *argv, VALUE self)
|
|
2754
2754
|
const int size = ary_size(excerpts);
|
2755
2755
|
int i;
|
2756
2756
|
VALUE rexcerpts = rb_ary_new2(size);
|
2757
|
-
RARRAY(rexcerpts)->len = size;
|
2758
2757
|
|
2759
2758
|
for (i = 0; i < size; i++) {
|
2760
2759
|
RARRAY(rexcerpts)->ptr[i] = rb_str_new2(excerpts[i]);
|
2760
|
+
RARRAY(rexcerpts)->len++;
|
2761
2761
|
}
|
2762
2762
|
ary_destroy(excerpts, &free);
|
2763
2763
|
return rexcerpts;
|
data/ext/r_store.c
CHANGED
@@ -191,7 +191,7 @@ frt_dir_exists(VALUE self, VALUE rfname)
|
|
191
191
|
{
|
192
192
|
Store *store = DATA_PTR(self);
|
193
193
|
StringValue(rfname);
|
194
|
-
return store->exists(store,
|
194
|
+
return store->exists(store, rs2s(rfname)) ? Qtrue : Qfalse;
|
195
195
|
}
|
196
196
|
|
197
197
|
/*
|
@@ -205,7 +205,7 @@ frt_dir_touch(VALUE self, VALUE rfname)
|
|
205
205
|
{
|
206
206
|
Store *store = DATA_PTR(self);
|
207
207
|
StringValue(rfname);
|
208
|
-
store->touch(store,
|
208
|
+
store->touch(store, rs2s(rfname));
|
209
209
|
return Qnil;
|
210
210
|
}
|
211
211
|
|
@@ -220,7 +220,7 @@ frt_dir_delete(VALUE self, VALUE rfname)
|
|
220
220
|
{
|
221
221
|
Store *store = DATA_PTR(self);
|
222
222
|
StringValue(rfname);
|
223
|
-
return (store->remove(store,
|
223
|
+
return (store->remove(store, rs2s(rfname)) == 0) ? Qtrue : Qfalse;
|
224
224
|
}
|
225
225
|
|
226
226
|
/*
|
@@ -263,7 +263,7 @@ frt_dir_rename(VALUE self, VALUE rfrom, VALUE rto)
|
|
263
263
|
Store *store = DATA_PTR(self);
|
264
264
|
StringValue(rfrom);
|
265
265
|
StringValue(rto);
|
266
|
-
store->rename(store,
|
266
|
+
store->rename(store, rs2s(rfrom), rs2s(rto));
|
267
267
|
return self;
|
268
268
|
}
|
269
269
|
|
@@ -283,7 +283,7 @@ frt_dir_make_lock(VALUE self, VALUE rlock_name)
|
|
283
283
|
Lock *lock;
|
284
284
|
Store *store = DATA_PTR(self);
|
285
285
|
StringValue(rlock_name);
|
286
|
-
lock = open_lock(store,
|
286
|
+
lock = open_lock(store, rs2s(rlock_name));
|
287
287
|
rlock = Data_Wrap_Struct(cLock, &frt_lock_mark, &frt_lock_free, lock);
|
288
288
|
object_add(lock, rlock);
|
289
289
|
return rlock;
|
@@ -362,9 +362,9 @@ frt_fsdir_new(int argc, VALUE *argv, VALUE klass)
|
|
362
362
|
}
|
363
363
|
if (!rb_funcall(rb_cFile, id_is_directory, 1, rpath)) {
|
364
364
|
rb_raise(rb_eIOError, "No directory <%s> found. Use :create => true"
|
365
|
-
" to create one.",
|
365
|
+
" to create one.", rs2s(rpath));
|
366
366
|
}
|
367
|
-
store = open_fs_store(
|
367
|
+
store = open_fs_store(rs2s(rpath));
|
368
368
|
if (create) store->clear_all(store);
|
369
369
|
if ((self = object_get(store)) == Qnil) {
|
370
370
|
self = Data_Wrap_Struct(klass, NULL, &frt_dir_free, store);
|
data/ext/ram_store.c
CHANGED
@@ -354,13 +354,14 @@ static const struct InStreamMethods RAM_IN_STREAM_METHODS = {
|
|
354
354
|
static InStream *ram_open_input(Store *store, const char *filename)
|
355
355
|
{
|
356
356
|
RAMFile *rf = (RAMFile *)h_get(store->dir.ht, filename);
|
357
|
-
InStream *is =
|
357
|
+
InStream *is = NULL;
|
358
358
|
|
359
359
|
if (rf == NULL) {
|
360
|
-
RAISE(
|
360
|
+
RAISE(FILE_NOT_FOUND_ERROR,
|
361
|
+
"tried to open \"%s\" but it doesn't exist", filename);
|
361
362
|
}
|
362
363
|
REF(rf);
|
363
|
-
|
364
|
+
is = is_new();
|
364
365
|
is->file.rf = rf;
|
365
366
|
is->d.pointer = 0;
|
366
367
|
is->m = &RAM_IN_STREAM_METHODS;
|
data/ext/search.c
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#include <string.h>
|
2
|
+
#include <limits.h>
|
2
3
|
#include "search.h"
|
3
4
|
#include "array.h"
|
4
5
|
|
@@ -1021,7 +1022,7 @@ static TopDocs *isea_search_w(Searcher *self,
|
|
1021
1022
|
filter_ft filter_func,
|
1022
1023
|
bool load_fields)
|
1023
1024
|
{
|
1024
|
-
int max_size =
|
1025
|
+
int max_size = num_docs + (num_docs == INT_MAX ? 0 : first_doc);
|
1025
1026
|
int i;
|
1026
1027
|
Scorer *scorer;
|
1027
1028
|
Hit **score_docs = NULL;
|
@@ -1539,7 +1540,7 @@ static TopDocs *msea_search_w(Searcher *self,
|
|
1539
1540
|
filter_ft filter_func,
|
1540
1541
|
bool load_fields)
|
1541
1542
|
{
|
1542
|
-
int max_size =
|
1543
|
+
int max_size = num_docs + (num_docs == INT_MAX ? 0 : first_doc);
|
1543
1544
|
int i;
|
1544
1545
|
int total_hits = 0;
|
1545
1546
|
Hit **score_docs = NULL;
|
data/ext/store.c
CHANGED
@@ -568,36 +568,52 @@ void is2os_copy_vints(InStream *is, OutStream *os, int cnt)
|
|
568
568
|
/**
|
569
569
|
* Test argument used to test the store->each function
|
570
570
|
*/
|
571
|
-
struct
|
571
|
+
struct FileNameListArg
|
572
572
|
{
|
573
|
-
|
574
|
-
|
573
|
+
int count;
|
574
|
+
int size;
|
575
|
+
int total_len;
|
576
|
+
char **files;
|
575
577
|
};
|
576
578
|
|
577
579
|
/**
|
578
580
|
* Test function used to test store->each function
|
579
581
|
*/
|
580
|
-
static void
|
582
|
+
static void add_file_name(char *fname, void *arg)
|
581
583
|
{
|
582
|
-
struct
|
583
|
-
if (
|
584
|
-
|
585
|
-
|
586
|
-
*(fnca->p++) = ',';
|
587
|
-
*(fnca->p++) = ' ';
|
584
|
+
struct FileNameListArg *fnl = (struct FileNameListArg *)arg;
|
585
|
+
if (fnl->count >= fnl->size) {
|
586
|
+
fnl->size *= 2;
|
587
|
+
REALLOC_N(fnl->files, char *, fnl->size);
|
588
588
|
}
|
589
|
+
fnl->files[fnl->count++] = estrdup(fname);
|
590
|
+
fnl->total_len += strlen(fname) + 2;
|
589
591
|
}
|
590
592
|
|
591
|
-
char *store_to_s(Store *store
|
593
|
+
char *store_to_s(Store *store)
|
592
594
|
{
|
593
|
-
struct
|
595
|
+
struct FileNameListArg fnl;
|
596
|
+
char *buf, *b;
|
597
|
+
int i;
|
598
|
+
fnl.count = 0;
|
599
|
+
fnl.size = 16;
|
600
|
+
fnl.total_len = 10;
|
601
|
+
fnl.files = ALLOC_N(char *, 16);
|
602
|
+
|
603
|
+
store->each(store, &add_file_name, &fnl);
|
604
|
+
qsort(fnl.files, fnl.count, sizeof(char *), &scmp);
|
605
|
+
b = buf = ALLOC_N(char, fnl.total_len);
|
606
|
+
|
607
|
+
for (i = 0; i < fnl.count; i++) {
|
608
|
+
char *fn = fnl.files[i];
|
609
|
+
int len = strlen(fn);
|
610
|
+
memcpy(b, fn, len);
|
611
|
+
b += len;
|
612
|
+
*b++ = '\n';
|
613
|
+
free(fn);
|
614
|
+
}
|
615
|
+
*b = '\0';
|
616
|
+
free(fnl.files);
|
594
617
|
|
595
|
-
fnca.p = buf;
|
596
|
-
fnca.end = buf + buf_size;
|
597
|
-
store->each(store, &concat_filenames, &fnca);
|
598
|
-
if (fnca.p > buf + 2) {
|
599
|
-
fnca.p[-2] = '\0';
|
600
|
-
}
|
601
618
|
return buf;
|
602
619
|
}
|
603
|
-
|
data/ext/store.h
CHANGED
@@ -292,7 +292,7 @@ struct Store
|
|
292
292
|
*
|
293
293
|
* @param store self
|
294
294
|
* @param filename the name of the input stream
|
295
|
-
* @raise
|
295
|
+
* @raise FILE_NOT_FOUND_ERROR if the input stream cannot be opened
|
296
296
|
*/
|
297
297
|
InStream *(*open_input)(Store *store, const char *filename);
|
298
298
|
|
@@ -728,11 +728,9 @@ extern void is2os_copy_vints(InStream *is, OutStream *os, int cnt);
|
|
728
728
|
/**
|
729
729
|
* Print the filenames in a store to a buffer.
|
730
730
|
*
|
731
|
-
* @param store
|
732
|
-
* @param buf the buffer to print the filenames to
|
733
|
-
* @paran len the length of the buffer
|
731
|
+
* @param store the store to get the filenames from
|
734
732
|
*/
|
735
|
-
extern char *store_to_s(Store *store
|
733
|
+
extern char *store_to_s(Store *store);
|
736
734
|
|
737
735
|
extern Lock *open_lock(Store *store, char *lockname);
|
738
736
|
extern void close_lock(Lock *lock);
|
data/lib/ferret/index.rb
CHANGED
@@ -171,10 +171,10 @@ module Ferret::Index
|
|
171
171
|
# num_excerpts:: Default: 2. Number of excerpts to return.
|
172
172
|
# pre_tag:: Default: "<b>". Tag to place to the left of the
|
173
173
|
# match. You'll probably want to change this to a
|
174
|
-
# "<span>" tag with a class "\033[36m" for use in
|
175
|
-
# terminal.
|
174
|
+
# "<span>" tag with a class. Try "\033[36m" for use in
|
175
|
+
# a terminal.
|
176
176
|
# post_tag:: Default: "</b>". This tag should close the
|
177
|
-
# +:pre_tag+.
|
177
|
+
# +:pre_tag+. Try tag "\033[m" in the terminal.
|
178
178
|
# ellipsis:: Default: "...". This is the string that is appended
|
179
179
|
# at the beginning and end of excerpts (unless the
|
180
180
|
# excerpt hits the start or end of the field.
|
@@ -673,7 +673,7 @@ module Ferret::Index
|
|
673
673
|
latest = false
|
674
674
|
begin
|
675
675
|
latest = @reader.latest?
|
676
|
-
rescue LockError => le
|
676
|
+
rescue Lock::LockError => le
|
677
677
|
sleep(@options[:lock_retry_time]) # sleep for 2 seconds and try again
|
678
678
|
latest = @reader.latest?
|
679
679
|
end
|
data/lib/ferret_version.rb
CHANGED
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../test_helper"
|
2
|
+
require File.dirname(__FILE__) + "/../utils/number_to_spoken.rb"
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
class IndexThreadSafetyReadWriteTest < Test::Unit::TestCase
|
6
|
+
include Ferret::Index
|
7
|
+
include Ferret::Document
|
8
|
+
|
9
|
+
INDEX_DIR = File.expand_path(File.join(File.dirname(__FILE__), "index"))
|
10
|
+
ITERATIONS = 10000
|
11
|
+
ANALYZER = Ferret::Analysis::Analyzer.new()
|
12
|
+
|
13
|
+
def setup
|
14
|
+
@index = Index.new(:path => 'index2',
|
15
|
+
:create => true,
|
16
|
+
:analyzer => ANALYZER,
|
17
|
+
:default_field => 'contents')
|
18
|
+
end
|
19
|
+
|
20
|
+
def search_thread()
|
21
|
+
ITERATIONS.times do
|
22
|
+
do_search()
|
23
|
+
sleep(rand(1))
|
24
|
+
end
|
25
|
+
rescue => e
|
26
|
+
puts e
|
27
|
+
puts e.backtrace
|
28
|
+
@index = nil
|
29
|
+
raise e
|
30
|
+
end
|
31
|
+
|
32
|
+
def index_thread()
|
33
|
+
ITERATIONS.times do
|
34
|
+
do_add_doc()
|
35
|
+
sleep(rand(1))
|
36
|
+
end
|
37
|
+
rescue => e
|
38
|
+
puts e
|
39
|
+
puts e.backtrace
|
40
|
+
@index = nil
|
41
|
+
raise e
|
42
|
+
end
|
43
|
+
|
44
|
+
def do_add_doc
|
45
|
+
d = Document.new()
|
46
|
+
n = rand(0xFFFFFFFF)
|
47
|
+
d << Field.new("id", n.to_s, Field::Store::YES, Field::Index::UNTOKENIZED)
|
48
|
+
d << Field.new("contents", n.to_spoken, Field::Store::NO, Field::Index::TOKENIZED)
|
49
|
+
puts("Adding #{n}")
|
50
|
+
begin
|
51
|
+
@index << d
|
52
|
+
rescue => e
|
53
|
+
puts e
|
54
|
+
puts e.backtrace
|
55
|
+
@index = nil
|
56
|
+
raise e
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def do_search
|
61
|
+
n = rand(0xFFFFFFFF)
|
62
|
+
puts("Searching for #{n}")
|
63
|
+
hits = @index.search_each(n.to_spoken, :num_docs => 3) do |d, s|
|
64
|
+
puts "Hit for #{n}: #{@index[d]["id"]} - #{s}"
|
65
|
+
end
|
66
|
+
puts("Searched for #{n}: total = #{hits}")
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_threading
|
70
|
+
threads = []
|
71
|
+
threads << Thread.new { search_thread }
|
72
|
+
threads << Thread.new { index_thread }
|
73
|
+
|
74
|
+
threads.each { |t| t.join }
|
75
|
+
end
|
76
|
+
end
|
@@ -1,20 +1,22 @@
|
|
1
1
|
require File.dirname(__FILE__) + "/../test_helper"
|
2
|
-
require File.dirname(__FILE__)
|
2
|
+
require File.join(File.dirname(__FILE__), "number_to_spoken.rb")
|
3
3
|
require 'thread'
|
4
4
|
|
5
5
|
class ThreadSafetyTest
|
6
6
|
include Ferret::Index
|
7
7
|
include Ferret::Search
|
8
8
|
include Ferret::Store
|
9
|
-
include Ferret
|
9
|
+
include Ferret
|
10
10
|
|
11
11
|
def initialize(options)
|
12
12
|
@options = options
|
13
13
|
end
|
14
14
|
|
15
15
|
INDEX_DIR = File.expand_path(File.join(File.dirname(__FILE__), "index"))
|
16
|
-
ANALYZER = Ferret::Analysis::
|
17
|
-
ITERATIONS =
|
16
|
+
ANALYZER = Ferret::Analysis::WhiteSpaceAnalyzer.new()
|
17
|
+
ITERATIONS = 1000
|
18
|
+
QUERY_PARSER = Ferret::QueryParser.new(:analyzer => ANALYZER,
|
19
|
+
:default_field => 'contents')
|
18
20
|
@@searcher = nil
|
19
21
|
|
20
22
|
def run_index_thread(writer)
|
@@ -23,10 +25,8 @@ class ThreadSafetyTest
|
|
23
25
|
use_compound_file = false
|
24
26
|
|
25
27
|
(400*ITERATIONS).times do |i|
|
26
|
-
d = Document.new()
|
27
28
|
n = rand(0xFFFFFFFF)
|
28
|
-
d
|
29
|
-
d << Field.new("contents", n.to_spoken, Field::Store::NO, Field::Index::TOKENIZED)
|
29
|
+
d = {:id => n.to_s, :contents => n.to_spoken}
|
30
30
|
puts("Adding #{n}")
|
31
31
|
|
32
32
|
# Switch between single and multiple file segments
|
@@ -37,7 +37,7 @@ class ThreadSafetyTest
|
|
37
37
|
|
38
38
|
if (i % reopen_interval == 0)
|
39
39
|
writer.close()
|
40
|
-
writer = IndexWriter.new(INDEX_DIR, :analyzer => ANALYZER)
|
40
|
+
writer = IndexWriter.new(:path => INDEX_DIR, :analyzer => ANALYZER)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -52,17 +52,17 @@ class ThreadSafetyTest
|
|
52
52
|
reopen_interval = 10 + rand(20)
|
53
53
|
|
54
54
|
unless use_global
|
55
|
-
searcher =
|
55
|
+
searcher = Searcher.new(INDEX_DIR)
|
56
56
|
end
|
57
57
|
|
58
58
|
(50*ITERATIONS).times do |i|
|
59
59
|
search_for(rand(0xFFFFFFFF), (searcher.nil? ? @@searcher : searcher))
|
60
60
|
if (i%reopen_interval == 0)
|
61
61
|
if (searcher == nil)
|
62
|
-
@@searcher =
|
62
|
+
@@searcher = Searcher.new(INDEX_DIR)
|
63
63
|
else
|
64
64
|
searcher.close()
|
65
|
-
searcher =
|
65
|
+
searcher = Searcher.new(INDEX_DIR)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
@@ -74,30 +74,26 @@ class ThreadSafetyTest
|
|
74
74
|
|
75
75
|
def search_for(n, searcher)
|
76
76
|
puts("Searching for #{n}")
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
hits.each do |d, s|
|
82
|
-
puts "Hit for #{n}: #{searcher.reader.get_document(d)["id"]} - #{s}"
|
77
|
+
topdocs = searcher.search(QUERY_PARSER.parse(n.to_spoken), :limit => 3)
|
78
|
+
puts("Search for #{n}: total = #{topdocs.total_hits}")
|
79
|
+
topdocs.hits.each do |hit|
|
80
|
+
puts "Hit for #{n}: #{searcher.reader[hit.doc]["id"]} - #{hit.score}"
|
83
81
|
end
|
84
82
|
end
|
85
83
|
|
86
84
|
def run_test_threads
|
87
|
-
|
88
85
|
threads = []
|
89
86
|
unless @options[:read_only]
|
90
|
-
writer = IndexWriter.new(INDEX_DIR, :analyzer => ANALYZER,
|
87
|
+
writer = IndexWriter.new(:path => INDEX_DIR, :analyzer => ANALYZER,
|
91
88
|
:create => !@options[:add])
|
92
89
|
|
93
90
|
threads << Thread.new { run_index_thread(writer) }
|
94
|
-
|
95
91
|
sleep(1)
|
96
92
|
end
|
97
93
|
|
98
94
|
threads << Thread.new { run_search_thread(false)}
|
99
95
|
|
100
|
-
@@searcher =
|
96
|
+
@@searcher = Searcher.new(INDEX_DIR)
|
101
97
|
threads << Thread.new { run_search_thread(true)}
|
102
98
|
|
103
99
|
threads << Thread.new { run_search_thread(true)}
|