rlibsphinxclient 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/CHANGELOG.rdoc +18 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +151 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/ext/extconf.rb +20 -0
- data/ext/rlibsphinxclient.i +314 -0
- data/ext/rlibsphinxclient_wrap.c +5931 -0
- data/init.rb +1 -0
- data/lib/sphinx.rb +22 -0
- data/lib/sphinx/client.rb +1070 -0
- data/lib/sphinx/fast_client.rb +184 -0
- data/lib/sphinx/request.rb +49 -0
- data/lib/sphinx/response.rb +69 -0
- data/lib/sphinx/safe_executor.rb +11 -0
- data/lib/sphinx/timeout.rb +9 -0
- data/rlibsphinxclient.gemspec +117 -0
- data/spec/client_response_spec.rb +135 -0
- data/spec/client_spec.rb +548 -0
- data/spec/fixtures/default_search.php +8 -0
- data/spec/fixtures/default_search_index.php +8 -0
- data/spec/fixtures/excerpt_custom.php +11 -0
- data/spec/fixtures/excerpt_default.php +8 -0
- data/spec/fixtures/excerpt_flags.php +11 -0
- data/spec/fixtures/field_weights.php +9 -0
- data/spec/fixtures/filter.php +9 -0
- data/spec/fixtures/filter_exclude.php +9 -0
- data/spec/fixtures/filter_float_range.php +9 -0
- data/spec/fixtures/filter_float_range_exclude.php +9 -0
- data/spec/fixtures/filter_range.php +9 -0
- data/spec/fixtures/filter_range_exclude.php +9 -0
- data/spec/fixtures/filter_ranges.php +10 -0
- data/spec/fixtures/filters.php +10 -0
- data/spec/fixtures/filters_different.php +13 -0
- data/spec/fixtures/geo_anchor.php +9 -0
- data/spec/fixtures/group_by_attr.php +9 -0
- data/spec/fixtures/group_by_attrpair.php +9 -0
- data/spec/fixtures/group_by_day.php +9 -0
- data/spec/fixtures/group_by_day_sort.php +9 -0
- data/spec/fixtures/group_by_month.php +9 -0
- data/spec/fixtures/group_by_week.php +9 -0
- data/spec/fixtures/group_by_year.php +9 -0
- data/spec/fixtures/group_distinct.php +10 -0
- data/spec/fixtures/id_range.php +9 -0
- data/spec/fixtures/id_range64.php +9 -0
- data/spec/fixtures/index_weights.php +9 -0
- data/spec/fixtures/keywords.php +8 -0
- data/spec/fixtures/limits.php +9 -0
- data/spec/fixtures/limits_cutoff.php +9 -0
- data/spec/fixtures/limits_max.php +9 -0
- data/spec/fixtures/limits_max_cutoff.php +9 -0
- data/spec/fixtures/match_all.php +9 -0
- data/spec/fixtures/match_any.php +9 -0
- data/spec/fixtures/match_boolean.php +9 -0
- data/spec/fixtures/match_extended.php +9 -0
- data/spec/fixtures/match_extended2.php +9 -0
- data/spec/fixtures/match_fullscan.php +9 -0
- data/spec/fixtures/match_phrase.php +9 -0
- data/spec/fixtures/max_query_time.php +9 -0
- data/spec/fixtures/miltiple_queries.php +12 -0
- data/spec/fixtures/ranking_bm25.php +9 -0
- data/spec/fixtures/ranking_none.php +9 -0
- data/spec/fixtures/ranking_proximity_bm25.php +9 -0
- data/spec/fixtures/ranking_wordcount.php +9 -0
- data/spec/fixtures/retries.php +9 -0
- data/spec/fixtures/retries_delay.php +9 -0
- data/spec/fixtures/sort_attr_asc.php +9 -0
- data/spec/fixtures/sort_attr_desc.php +9 -0
- data/spec/fixtures/sort_expr.php +9 -0
- data/spec/fixtures/sort_extended.php +9 -0
- data/spec/fixtures/sort_relevance.php +9 -0
- data/spec/fixtures/sort_time_segments.php +9 -0
- data/spec/fixtures/sphinxapi.php +1181 -0
- data/spec/fixtures/update_attributes.php +8 -0
- data/spec/fixtures/weights.php +9 -0
- data/spec/sphinx/sphinx.conf +67 -0
- data/spec/sphinx/sphinx_test.sql +86 -0
- metadata +133 -0
data/.gitignore
ADDED
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
=== Version 0.2.2 / 2009-10-15
|
2
|
+
|
3
|
+
* Moved from Echoe to Jeweler, gem is hosted on Gemcutter now.
|
4
|
+
|
5
|
+
=== Version 0.2.1 / 2009-01-27
|
6
|
+
|
7
|
+
* 4 minor bug fixes
|
8
|
+
|
9
|
+
* Fixed extconf.rb to use /opt/sphinx as default library search path.
|
10
|
+
* Updated Mac OS X installation steps and prerequisites section in README.rdoc.
|
11
|
+
* Updated Manifest to include LICENSE file.
|
12
|
+
* Added CHANGELOG file.
|
13
|
+
|
14
|
+
=== Version 0.2.0 / 2009-01-27
|
15
|
+
|
16
|
+
This is the first preview release of rsphinxclientapi, a Ruby wrapper for pure C searchd client API library.
|
17
|
+
|
18
|
+
* Implemented wrappers for all API functions.
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Dmytro Shteflyuk
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
= rlibsphinxclient
|
2
|
+
|
3
|
+
A Ruby wrapper for pure C searchd client API library. This is *highly experimental* library
|
4
|
+
so use it at your own risk.
|
5
|
+
|
6
|
+
== Installing the rlibsphinxclient gem
|
7
|
+
|
8
|
+
This gem can be more difficult to install than the typical Ruby extension. First you have to
|
9
|
+
install Sphinx and Sphinx pure C searchd client API library.
|
10
|
+
|
11
|
+
=== Step 1: Install pure C Sphinx client API
|
12
|
+
|
13
|
+
Go to http://sphinxsearch.com/downloads.html and download the latest stable release.
|
14
|
+
Then go to <tt>api/libsphinxclient</tt> directory and install client API to your
|
15
|
+
preferred folder (I like /opt/sphinx):
|
16
|
+
|
17
|
+
cd api/libsphinxclient
|
18
|
+
./configure --prefix=/opt/sphinx
|
19
|
+
make
|
20
|
+
sudo make install
|
21
|
+
|
22
|
+
On Max OS X you may get the following error:
|
23
|
+
|
24
|
+
configure: error: C++ preprocessor "/lib/cpp" fails sanity check
|
25
|
+
|
26
|
+
In this case you should specify environment variable for <tt>./configure</tt> script:
|
27
|
+
|
28
|
+
CXXCPP="gcc -E" ./configure --prefix=/opt/sphinx
|
29
|
+
|
30
|
+
=== Step 2: Install rlibsphinxclient gem
|
31
|
+
|
32
|
+
If you have installed the Sphinx to <tt>/opt/sphinx</tt>, just run:
|
33
|
+
|
34
|
+
sudo gem install kpumuk-rlibsphinxclient --no-ri --no-rdoc
|
35
|
+
|
36
|
+
Otherwise, specify where sphinx has been installed to:
|
37
|
+
|
38
|
+
sudo gem install kpumuk-rlibsphinxclient --no-ri --no-rdoc -- --with-libsphinxclient-dir=/opt/sphinx-0.9.9
|
39
|
+
|
40
|
+
On Mac OS X with MacPorts you should specify <tt>ARCHFLAGS</tt> environment variable:
|
41
|
+
|
42
|
+
sudo env ARCHFLAGS="-arch i386" gem install kpumuk-rlibsphinxclient --no-rdoc --no-ri -- --with-libsphinxclient-dir=/opt/sphinx-0.9.9
|
43
|
+
|
44
|
+
If you are working on Ruby on Rails application, you can add gem dependency to your
|
45
|
+
<tt>config/environment.rb</tt>:
|
46
|
+
|
47
|
+
config.gem 'kpumuk-rlibsphinxclient', :lib => 'sphinx'
|
48
|
+
|
49
|
+
Also don't forget to remove the <tt>sphinx</tt> plugin, because it's functionality
|
50
|
+
is completely covered by this gem.
|
51
|
+
|
52
|
+
== Using the rlibsphinxclient gem
|
53
|
+
|
54
|
+
The gem includes two versions of the client API: pure Ruby and wrapper for pure C client API.
|
55
|
+
They are 100% equivalent in use, so you can switch to any of them. To use pure Ruby client,
|
56
|
+
instantiate the <tt>Sphinx::Client</tt>, for pure C wrapper use <tt>Sphinx::FastClient</tt>.
|
57
|
+
|
58
|
+
Important note: you should call <tt>destroy</tt> method when you do not need client API any more.
|
59
|
+
The reason for that is the C wrapper saves all query results in memory, and frees them in
|
60
|
+
the <tt>destroy</tt> method call. You can omit this call in pure Ruby library, but I'd like
|
61
|
+
to do call in any case just for consistence (to be able to switch to another client).
|
62
|
+
|
63
|
+
Important note #2: to ensure that <tt>destroy</tt> method will be called, use <tt>ensure</tt>
|
64
|
+
block:
|
65
|
+
|
66
|
+
begin
|
67
|
+
@sphinx = Sphinx::FastClient.new
|
68
|
+
@sphinx.Query('test')
|
69
|
+
ensure
|
70
|
+
@sphinx.destroy
|
71
|
+
end
|
72
|
+
|
73
|
+
== Examples of usage
|
74
|
+
|
75
|
+
Ok, let's take a look at the examples. First, here is the search example with all possible
|
76
|
+
filters and options set:
|
77
|
+
|
78
|
+
require 'sphinx'
|
79
|
+
@sphinx = Sphinx::FastClient.new
|
80
|
+
@sphinx.SetServer('localhost', 3312)
|
81
|
+
@sphinx.SetLimits(1, 100, 20, 30)
|
82
|
+
@sphinx.SetMaxQueryTime(5)
|
83
|
+
@sphinx.SetMatchMode(Sphinx::Client::SPH_MATCH_EXTENDED2)
|
84
|
+
@sphinx.SetRankingMode(Sphinx::Client::SPH_RANK_BM25)
|
85
|
+
@sphinx.SetSortMode(Sphinx::Client::SPH_SORT_RELEVANCE)
|
86
|
+
@sphinx.SetFieldWeights('group_id' => 10, 'rating' => 20)
|
87
|
+
@sphinx.SetIndexWeights('test1' => 20, 'test2' => 30)
|
88
|
+
@sphinx.SetIDRange(1, 100)
|
89
|
+
@sphinx.SetFilter('group_id', [1], true)
|
90
|
+
@sphinx.SetFilterRange('group_id', 1, 2, true)
|
91
|
+
@sphinx.SetFilterFloatRange('rating', 1, 3, true)
|
92
|
+
@sphinx.SetGroupBy('created_at', Sphinx::Client::SPH_GROUPBY_DAY)
|
93
|
+
@sphinx.SetGroupDistinct('group_id')
|
94
|
+
@sphinx.SetRetries(5, 10)
|
95
|
+
results = @sphinx.Query('test')
|
96
|
+
@sphinx.destroy
|
97
|
+
|
98
|
+
<tt>BuildKeywords</tt> example:
|
99
|
+
|
100
|
+
require 'sphinx'
|
101
|
+
@sphinx = Sphinx::FastClient.new
|
102
|
+
results = @sphinx.BuildKeywords('wifi gprs', 'test1', true)
|
103
|
+
@sphinx.destroy
|
104
|
+
|
105
|
+
<tt>BuildExcerpts</tt> example:
|
106
|
+
|
107
|
+
require 'sphinx'
|
108
|
+
@sphinx = Sphinx::FastClient.new
|
109
|
+
results = @sphinx.BuildExcerpts(['what the world', 'London is the capital of Great Britain'], 'test1', 'the')
|
110
|
+
@sphinx.destroy
|
111
|
+
|
112
|
+
<tt>UpdateAttributes</tt> example:
|
113
|
+
|
114
|
+
require 'sphinx'
|
115
|
+
@sphinx = Sphinx::FastClient.new
|
116
|
+
results = @sphinx.UpdateAttributes('test1', ['group_id'], { 2 => [1] })
|
117
|
+
@sphinx.destroy
|
118
|
+
|
119
|
+
== Benchmarks
|
120
|
+
|
121
|
+
The reason to write this gem was to investigate why we keep getting timeout errors
|
122
|
+
when using Sphinx (occur rarely, but they are annoying me.) But the side effect of
|
123
|
+
this library was the slight search performance improvement: Ruby library is slower
|
124
|
+
when generating Sphinx request and parsing its results.
|
125
|
+
|
126
|
+
require 'sphinx'
|
127
|
+
require 'benchmark'
|
128
|
+
|
129
|
+
def run_test(klass)
|
130
|
+
sphinx = klass.new
|
131
|
+
sphinx.Query('test hello')
|
132
|
+
ensure
|
133
|
+
sphinx.destroy
|
134
|
+
end
|
135
|
+
|
136
|
+
Benchmark.bm do |x|
|
137
|
+
x.report('pure ruby') { 1000.times { run_test(Sphinx::Client) } }
|
138
|
+
x.report('c wrapper') { 1000.times { run_test(Sphinx::FastClient) } }
|
139
|
+
end
|
140
|
+
|
141
|
+
On my MBP I got the following results:
|
142
|
+
|
143
|
+
user system total real
|
144
|
+
pure ruby 0.420000 0.230000 0.650000 ( 14.721659)
|
145
|
+
c wrapper 0.060000 0.090000 0.150000 ( 2.248645)
|
146
|
+
|
147
|
+
== Who are the authors?
|
148
|
+
|
149
|
+
This plugin has been created in Scribd.com for our internal use and then the sources were opened
|
150
|
+
for other people to use. All the code in this package has been developed by Dmytro Shteflyuk
|
151
|
+
for Scribd.com and is released under the MIT license. For more details, see MIT-LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |gemspec|
|
9
|
+
gemspec.name = 'rlibsphinxclient'
|
10
|
+
gemspec.summary = 'A Ruby wrapper for pure C searchd client API library.'
|
11
|
+
gemspec.email = 'kpumuk@kpumuk.info'
|
12
|
+
gemspec.homepage = 'http://github.com/kpumuk/rlibsphinxclient'
|
13
|
+
gemspec.author = 'Dmytro Shteflyuk'
|
14
|
+
gemspec.extensions = ['ext/extconf.rb']
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts 'Jeweler not available. Install it with: sudo gem install jeweler -s http://gemcutter.org'
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Update SWIG wrapper for pure C searchd client API library'
|
22
|
+
task :swig do
|
23
|
+
system 'cd ext && swig -I/opt/local/include -I/opt/sphinx-0.9.9/include -ruby -autorename rlibsphinxclient.i'
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Generate documentation for the rlibsphinxclient gem.'
|
27
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
28
|
+
rdoc.rdoc_dir = 'rdoc'
|
29
|
+
rdoc.title = 'rlibsphinxclient'
|
30
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
31
|
+
rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'MIT-LICENSE')
|
32
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'Builds a gem and installs it to ~/.gem folder. Used only for development purposes.'
|
36
|
+
task :dev do
|
37
|
+
system 'rake package'
|
38
|
+
system 'cd pkg && env ARCHFLAGS="-arch i386" DEBUG=1 gem install rlibsphinxclient --no-rdoc --no-ri -- --with-libsphinxclient-dir=/opt/sphinx-0.9.9'
|
39
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.2
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
$CFLAGS.gsub! /-O\d/, ''
|
4
|
+
|
5
|
+
if ENV['DEBUG']
|
6
|
+
puts "setting debug flags"
|
7
|
+
$CFLAGS << " -O0 -ggdb -DHAVE_DEBUG"
|
8
|
+
else
|
9
|
+
$CFLAGS << " -O3"
|
10
|
+
end
|
11
|
+
|
12
|
+
find_library(*['sphinxclient', 'sphinx_create', '/opt/sphinx/lib'].compact) or
|
13
|
+
find_library(*['sphinxclient', 'sphinx_create', dir_config('libsphinxclient').last].compact) or
|
14
|
+
raise "shared library 'libsphinxclient' not found"
|
15
|
+
|
16
|
+
find_header(*['sphinxclient.h', '/opt/sphinx/include'].compact) or
|
17
|
+
find_header(*['sphinxclient.h', dir_config('libsphinxclient').first].compact) or
|
18
|
+
raise "header file 'sphinxclient.h' not found"
|
19
|
+
|
20
|
+
create_makefile 'rlibsphinxclient'
|
@@ -0,0 +1,314 @@
|
|
1
|
+
%module rlibsphinxclient
|
2
|
+
%{
|
3
|
+
#include <sphinxclient.h>
|
4
|
+
%}
|
5
|
+
|
6
|
+
%include "typemaps.i"
|
7
|
+
|
8
|
+
%newobject sphinx_create;
|
9
|
+
|
10
|
+
/* -----------------------------------------------------------------------------
|
11
|
+
* This section contains generic input parameter type mappings.
|
12
|
+
* ----------------------------------------------------------------------------- */
|
13
|
+
|
14
|
+
// Processing (sphinx_bool) params
|
15
|
+
%typemap(in) sphinx_bool {
|
16
|
+
switch(TYPE($input)) {
|
17
|
+
case T_TRUE:
|
18
|
+
case T_FALSE:
|
19
|
+
$1 = $input == Qtrue ? SPH_TRUE : SPH_FALSE;
|
20
|
+
break;
|
21
|
+
default:
|
22
|
+
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname" "', argument " "$argnum"" of type '" "$1_type""'");
|
23
|
+
break;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
// Processing (sphinx_uint64_t *) params.
|
28
|
+
%typemap(in) sphinx_uint64_t * {
|
29
|
+
int size = RARRAY_LEN($input), i;
|
30
|
+
|
31
|
+
$1 = (sphinx_uint64_t *) malloc(size * sizeof(sphinx_uint64_t));
|
32
|
+
VALUE *ptr = RARRAY_PTR($input);
|
33
|
+
for (i = 0; i < size; i++, ptr++) {
|
34
|
+
$1[i] = NUM2ULL(*ptr);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
// Cleaning up (sphinx_uint64_t *) params.
|
39
|
+
%typemap(freearg) sphinx_uint64_t * {
|
40
|
+
free((char *) $1);
|
41
|
+
}
|
42
|
+
|
43
|
+
// Processing (int *) params.
|
44
|
+
%typemap(in) int * {
|
45
|
+
int size = RARRAY_LEN($input), i;
|
46
|
+
|
47
|
+
$1 = (int *) malloc(size * sizeof(int));
|
48
|
+
VALUE *ptr = RARRAY_PTR($input);
|
49
|
+
for (i = 0; i < size; i++, ptr++) {
|
50
|
+
$1[i] = NUM2INT(*ptr);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
// Cleaning up (int *) params.
|
55
|
+
%typemap(freearg) int * {
|
56
|
+
free((char *) $1);
|
57
|
+
}
|
58
|
+
|
59
|
+
// Processing (char **) params.
|
60
|
+
%typemap(in) char ** {
|
61
|
+
int size = RARRAY_LEN($input), i;
|
62
|
+
|
63
|
+
$1 = (char **) malloc(size * sizeof(char *));
|
64
|
+
VALUE *ptr = RARRAY_PTR($input);
|
65
|
+
for (i = 0; i < size; i++, ptr++) {
|
66
|
+
$1[i] = STR2CSTR(*ptr);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
// Cleaning up (char **) params.
|
71
|
+
%typemap(freearg) char ** {
|
72
|
+
free((char *) $1);
|
73
|
+
}
|
74
|
+
|
75
|
+
/* -----------------------------------------------------------------------------
|
76
|
+
* This section contains sphinx_result return value type mappings
|
77
|
+
* (functions sphinx_query and sphinx_run_queries.)
|
78
|
+
* ----------------------------------------------------------------------------- */
|
79
|
+
|
80
|
+
// Processing sphinx_run_queries return value (array of sphinx_result).
|
81
|
+
%typemap(out) (sphinx_result *) {
|
82
|
+
int num_results = sphinx_get_num_results(arg1), i;
|
83
|
+
|
84
|
+
$result = rb_ary_new();
|
85
|
+
for (i = 0; i < num_results; i++) {
|
86
|
+
rb_ary_store($result, i, convert_sphinx_result(arg1, $1 + i));
|
87
|
+
}
|
88
|
+
}
|
89
|
+
sphinx_result * sphinx_run_queries(sphinx_client * client);
|
90
|
+
|
91
|
+
// Processing sphinx_query return value (single instance of sphinx_result).
|
92
|
+
%typemap(out) (sphinx_result *) {
|
93
|
+
$result = convert_sphinx_result(arg1, $1);
|
94
|
+
}
|
95
|
+
|
96
|
+
/* -----------------------------------------------------------------------------
|
97
|
+
* This section contains type mappings for sphinx_build_excerpts function.
|
98
|
+
* ----------------------------------------------------------------------------- */
|
99
|
+
|
100
|
+
// Processing sphinx_excerpt_options input parameter.
|
101
|
+
%typemap(in) sphinx_excerpt_options * (sphinx_excerpt_options opts, VALUE val) {
|
102
|
+
Check_Type($input, T_HASH);
|
103
|
+
sphinx_init_excerpt_options(&opts);
|
104
|
+
|
105
|
+
// before_match
|
106
|
+
val = rb_hash_aref($input, rb_str_new2("before_match"));
|
107
|
+
if (val != Qnil) {
|
108
|
+
Check_Type($input, T_STRING);
|
109
|
+
opts.before_match = STR2CSTR(val);
|
110
|
+
}
|
111
|
+
|
112
|
+
// after_match
|
113
|
+
val = rb_hash_aref($input, rb_str_new2("after_match"));
|
114
|
+
if (val != Qnil) {
|
115
|
+
Check_Type($input, T_STRING);
|
116
|
+
opts.after_match = STR2CSTR(val);
|
117
|
+
}
|
118
|
+
|
119
|
+
// chunk_separator
|
120
|
+
val = rb_hash_aref($input, rb_str_new2("chunk_separator"));
|
121
|
+
if (val != Qnil) {
|
122
|
+
Check_Type($input, T_STRING);
|
123
|
+
opts.chunk_separator = STR2CSTR(val);
|
124
|
+
}
|
125
|
+
|
126
|
+
// limit
|
127
|
+
val = rb_hash_aref($input, rb_str_new2("limit"));
|
128
|
+
if (val != Qnil) {
|
129
|
+
Check_Type($input, T_FIXNUM);
|
130
|
+
opts.limit = NUM2INT(val);
|
131
|
+
}
|
132
|
+
|
133
|
+
// around
|
134
|
+
val = rb_hash_aref($input, rb_str_new2("around"));
|
135
|
+
if (val != Qnil) {
|
136
|
+
Check_Type($input, T_FIXNUM);
|
137
|
+
opts.around = NUM2INT(val);
|
138
|
+
}
|
139
|
+
|
140
|
+
// exact_phrase
|
141
|
+
val = rb_hash_aref($input, rb_str_new2("exact_phrase"));
|
142
|
+
if (val != Qnil) {
|
143
|
+
opts.around = val == Qtrue ? SPH_TRUE : SPH_FALSE;
|
144
|
+
}
|
145
|
+
|
146
|
+
// single_passage
|
147
|
+
val = rb_hash_aref($input, rb_str_new2("single_passage"));
|
148
|
+
if (val != Qnil) {
|
149
|
+
opts.single_passage = val == Qtrue ? SPH_TRUE : SPH_FALSE;
|
150
|
+
}
|
151
|
+
|
152
|
+
// use_boundaries
|
153
|
+
val = rb_hash_aref($input, rb_str_new2("use_boundaries"));
|
154
|
+
if (val != Qnil) {
|
155
|
+
opts.use_boundaries = val == Qtrue ? SPH_TRUE : SPH_FALSE;
|
156
|
+
}
|
157
|
+
|
158
|
+
// weight_order
|
159
|
+
val = rb_hash_aref($input, rb_str_new2("weight_order"));
|
160
|
+
if (val != Qnil) {
|
161
|
+
opts.weight_order = val == Qtrue ? SPH_TRUE : SPH_FALSE;
|
162
|
+
}
|
163
|
+
|
164
|
+
$1 = &opts;
|
165
|
+
}
|
166
|
+
|
167
|
+
// Processing char ** output parameter.
|
168
|
+
%typemap(out) char ** {
|
169
|
+
int num_docs, i;
|
170
|
+
|
171
|
+
SWIG_AsVal_int(argv[1], &num_docs);
|
172
|
+
|
173
|
+
if ($1) {
|
174
|
+
$result = rb_ary_new();
|
175
|
+
for (i = 0; i < num_docs; i++) {
|
176
|
+
rb_ary_store($result, i, rb_str_new2($1[i]));
|
177
|
+
|
178
|
+
free((char *) $1[i]);
|
179
|
+
}
|
180
|
+
free((char *) $1);
|
181
|
+
} else {
|
182
|
+
$result = Qfalse;
|
183
|
+
}
|
184
|
+
}
|
185
|
+
char ** sphinx_build_excerpts(sphinx_client * client, int num_docs, const char ** docs, const char * index, const char * words, sphinx_excerpt_options * opts);
|
186
|
+
%typemap(in) sphinx_excerpt_options * {}
|
187
|
+
%typemap(out) char ** {}
|
188
|
+
|
189
|
+
/* -----------------------------------------------------------------------------
|
190
|
+
* This section contains type mappings for sphinx_build_keywords function.
|
191
|
+
* ----------------------------------------------------------------------------- */
|
192
|
+
|
193
|
+
// Defining out_num_keywords input parameter (will contain a number of keywords).
|
194
|
+
%typemap(in, numinputs = 0) int * out_num_keywords (int out_num_keywords) {
|
195
|
+
$1 = &out_num_keywords;
|
196
|
+
}
|
197
|
+
|
198
|
+
// Doing nothing because out_num_keywords is a local variable.
|
199
|
+
%typemap(freearg) int * out_num_keywords {
|
200
|
+
}
|
201
|
+
|
202
|
+
// Processing array of sphinx_keyword_info values.
|
203
|
+
%typemap(out) sphinx_keyword_info * {
|
204
|
+
int i;
|
205
|
+
VALUE keyword = Qnil;
|
206
|
+
$result = rb_ary_new();
|
207
|
+
for (i = 0; i < out_num_keywords5; i++) {
|
208
|
+
keyword = rb_hash_new();
|
209
|
+
rb_hash_aset(keyword, rb_str_new2("tokenized"), rb_str_new2($1[i].tokenized));
|
210
|
+
rb_hash_aset(keyword, rb_str_new2("normalized"), rb_str_new2($1[i].normalized));
|
211
|
+
rb_hash_aset(keyword, rb_str_new2("docs"), INT2FIX($1[i].num_docs));
|
212
|
+
rb_hash_aset(keyword, rb_str_new2("hits"), INT2FIX($1[i].num_hits));
|
213
|
+
rb_ary_store($result, i, keyword);
|
214
|
+
|
215
|
+
free((char *) $1[i].tokenized);
|
216
|
+
free((char *) $1[i].normalized);
|
217
|
+
}
|
218
|
+
|
219
|
+
free((char *) $1);
|
220
|
+
}
|
221
|
+
|
222
|
+
/* -----------------------------------------------------------------------------
|
223
|
+
* This section contains some useful helpers for type mappers.
|
224
|
+
* ----------------------------------------------------------------------------- */
|
225
|
+
|
226
|
+
%{
|
227
|
+
static VALUE convert_sphinx_result(sphinx_client *client, sphinx_result *input) {
|
228
|
+
int i, j, k;
|
229
|
+
VALUE result = Qnil, var1 = Qnil, var2 = Qnil, var3 = Qnil, var4 = Qnil;
|
230
|
+
char *msg = (char *) 0;
|
231
|
+
unsigned int *mva = 0;
|
232
|
+
char *time = 0;
|
233
|
+
|
234
|
+
if (!input) {
|
235
|
+
result = Qfalse;
|
236
|
+
} else {
|
237
|
+
result = rb_hash_new();
|
238
|
+
rb_hash_aset(result, rb_str_new2("error"), input->error ? rb_str_new2(input->error) : Qnil);
|
239
|
+
rb_hash_aset(result, rb_str_new2("warning"), input->warning ? rb_str_new2(input->warning) : Qnil);
|
240
|
+
rb_hash_aset(result, rb_str_new2("status"), INT2FIX(input->status));
|
241
|
+
if (input->status != SEARCHD_OK && input->status != SEARCHD_WARNING) {
|
242
|
+
return result;
|
243
|
+
}
|
244
|
+
|
245
|
+
rb_hash_aset(result, rb_str_new2("total"), INT2FIX(input->total));
|
246
|
+
rb_hash_aset(result, rb_str_new2("total_found"), INT2FIX(input->total_found));
|
247
|
+
time = (char *) malloc(20);
|
248
|
+
sprintf(time, "%.3f", input->time_msec / 1000.);
|
249
|
+
rb_hash_aset(result, rb_str_new2("time"), rb_str_new2(time));
|
250
|
+
free(time);
|
251
|
+
|
252
|
+
// fields
|
253
|
+
var1 = rb_ary_new();
|
254
|
+
for (i = 0; i < input->num_fields; i++) {
|
255
|
+
rb_ary_store(var1, i, rb_str_new2(input->fields[i]));
|
256
|
+
}
|
257
|
+
rb_hash_aset(result, rb_str_new2("fields"), var1);
|
258
|
+
|
259
|
+
// attrs
|
260
|
+
var1 = rb_hash_new();
|
261
|
+
for (i = 0; i < input->num_attrs; i++) {
|
262
|
+
rb_hash_aset(var1, rb_str_new2(input->attr_names[i]), INT2NUM(input->attr_types[i]));
|
263
|
+
}
|
264
|
+
rb_hash_aset(result, rb_str_new2("attrs"), var1);
|
265
|
+
|
266
|
+
// words
|
267
|
+
var1 = rb_hash_new();
|
268
|
+
for (i = 0; i < input->num_words; i++) {
|
269
|
+
var2 = rb_hash_new();
|
270
|
+
rb_hash_aset(var2, rb_str_new2("docs"), INT2FIX(input->words[i].docs));
|
271
|
+
rb_hash_aset(var2, rb_str_new2("hits"), INT2FIX(input->words[i].hits));
|
272
|
+
|
273
|
+
rb_hash_aset(var1, rb_str_new2(input->words[i].word), var2);
|
274
|
+
}
|
275
|
+
rb_hash_aset(result, rb_str_new2("words"), var1);
|
276
|
+
|
277
|
+
// matches
|
278
|
+
var1 = rb_ary_new();
|
279
|
+
for (i = 0; i < input->num_matches; i++) {
|
280
|
+
var2 = rb_hash_new();
|
281
|
+
rb_hash_aset(var2, rb_str_new2("id"), ULL2NUM(sphinx_get_id(input, i)));
|
282
|
+
rb_hash_aset(var2, rb_str_new2("weight"), INT2FIX(sphinx_get_weight(input, i)));
|
283
|
+
|
284
|
+
var3 = rb_hash_new();
|
285
|
+
for (j = 0; j < input->num_attrs; j++) {
|
286
|
+
switch (input->attr_types[j]) {
|
287
|
+
case SPH_ATTR_MULTI | SPH_ATTR_INTEGER:
|
288
|
+
mva = (unsigned int *) sphinx_get_mva(input, i, j);
|
289
|
+
var4 = rb_ary_new();
|
290
|
+
for (k = 0; k < (int) mva[0]; k++) {
|
291
|
+
rb_ary_store(var4, k, INT2NUM(mva[k + 1]));
|
292
|
+
}
|
293
|
+
break;
|
294
|
+
case SPH_ATTR_FLOAT:
|
295
|
+
var4 = rb_float_new(sphinx_get_float(input, i, j));
|
296
|
+
break;
|
297
|
+
default:
|
298
|
+
var4 = ULL2NUM(sphinx_get_int(input, i, j));
|
299
|
+
break;
|
300
|
+
}
|
301
|
+
rb_hash_aset(var3, rb_str_new2(input->attr_names[j]), var4);
|
302
|
+
}
|
303
|
+
rb_hash_aset(var2, rb_str_new2("attrs"), var3);
|
304
|
+
|
305
|
+
rb_ary_store(var1, i, var2);
|
306
|
+
}
|
307
|
+
rb_hash_aset(result, rb_str_new2("matches"), var1);
|
308
|
+
}
|
309
|
+
|
310
|
+
return result;
|
311
|
+
}
|
312
|
+
%}
|
313
|
+
|
314
|
+
%include "/opt/sphinx-0.9.9/include/sphinxclient.h"
|