/* * call-seq: * patricia_trie.prefix_search(prefix) -> Groonga::Hash * * キーが_prefix_に前方一致するレコードのIDがキーに入っている * Groonga::Hashを返す。マッチするレコードがない場合は空の * Groonga::Hashが返る。 * */ static VALUE rb_grn_patricia_trie_prefix_search (VALUE self, VALUE rb_prefix) { grn_ctx *context; grn_obj *table, *key, *domain, *result; grn_id domain_id; VALUE rb_result; rb_grn_table_key_support_deconstruct(SELF(self), &table, &context, &key, &domain_id, &domain, NULL, NULL, NULL, NULL); result = grn_table_create(context, NULL, 0, NULL, GRN_OBJ_TABLE_HASH_KEY, table, 0); rb_grn_context_check(context, self); rb_result = GRNOBJECT2RVAL(Qnil, context, result, GRN_TRUE); GRN_BULK_REWIND(key); RVAL2GRNKEY(rb_prefix, context, key, domain_id, domain, self); grn_pat_prefix_search(context, (grn_pat *)table, GRN_BULK_HEAD(key), GRN_BULK_VSIZE(key), (grn_hash *)result); rb_grn_context_check(context, self); return rb_result; }
/* * call-seq: * Groonga::Array.create(options={}) -> Groonga::Array * Groonga::Array.create(options={}) {|table| ... } * * キーのないテーブルを生成する。ブロックを指定すると、そのブ * ロックに生成したテーブルが渡され、ブロックを抜けると自動的 * にテーブルが破棄される。 * * @example * #無名一時テーブルを生成する。 * Groonga::Array.create * * #無名永続テーブルを生成する。 * Groonga::Array.create(:path => "/tmp/array.grn") * * #名前付き永続テーブルを生成する。ただし、ファイル名は気にしない。 * Groonga::Array.create(:name => "Bookmarks", * :persistent => true) * * #それぞれのレコードに512バイトの値を格納できる無名一時テーブルを生成する。 * Groonga::Array.create(:value => 512) * * @param [::Hash] options The name and value * pairs. Omitted names are initialized as the default value. * @option options [Grrnga::Context] :context (Groonga::Context.default) The context * テーブルが利用するGrrnga::Context * @option options :name The name * テーブルの名前。名前をつけると、Groonga::Context#[]に名 * 前を指定してテーブルを取得することができる。省略すると * 無名テーブルになり、テーブルIDでのみ取得できる。 * @option options :path The path * テーブルを保存するパス。パスを指定すると永続テーブルとな * り、プロセス終了後もレコードは保持される。次回起動時に * Groonga::Context#[]で保存されたレコードを利用することが * できる。省略すると一時テーブルになり、プロセスが終了する * とレコードは破棄される。 * @option options :persistent The persistent * +true+ を指定すると永続テーブルとなる。 +path+ を省略した * 場合は自動的にパスが付加される。 +:context+ で指定した * Groonga::Contextに結びついているデータベースが一時デー * タベースの場合は例外が発生する。 * @option options :value_type (nil) The value_type * 値の型を指定する。省略すると値のための領域を確保しない。 * 値を保存したい場合は必ず指定すること。 * 参考: Groonga::Type.new * @option options [Groonga::Record#n_sub_records] :sub_records The sub_records * +true+ を指定すると#groupでグループ化したときに、 * Groonga::Record#n_sub_recordsでグループに含まれるレコー * ドの件数を取得できる。 */ static VALUE rb_grn_array_s_create (int argc, VALUE *argv, VALUE klass) { grn_ctx *context = NULL; grn_obj *value_type = NULL, *table; const char *name = NULL, *path = NULL; unsigned name_size = 0; grn_obj_flags flags = GRN_OBJ_TABLE_NO_KEY; VALUE rb_table; VALUE options, rb_context, rb_name, rb_path, rb_persistent; VALUE rb_value_type, rb_sub_records; rb_scan_args(argc, argv, "01", &options); rb_grn_scan_options(options, "context", &rb_context, "name", &rb_name, "path", &rb_path, "persistent", &rb_persistent, "value_type", &rb_value_type, "sub_records", &rb_sub_records, NULL); context = rb_grn_context_ensure(&rb_context); if (!NIL_P(rb_name)) { name = StringValuePtr(rb_name); name_size = RSTRING_LEN(rb_name); flags |= GRN_OBJ_PERSISTENT; } if (!NIL_P(rb_path)) { path = StringValueCStr(rb_path); flags |= GRN_OBJ_PERSISTENT; } if (RVAL2CBOOL(rb_persistent)) flags |= GRN_OBJ_PERSISTENT; if (!NIL_P(rb_value_type)) value_type = RVAL2GRNOBJECT(rb_value_type, &context); if (RVAL2CBOOL(rb_sub_records)) flags |= GRN_OBJ_WITH_SUBREC; table = grn_table_create(context, name, name_size, path, flags, NULL, value_type); if (!table) rb_grn_context_check(context, rb_ary_new4(argc, argv)); rb_table = GRNOBJECT2RVAL(klass, context, table, GRN_TRUE); rb_grn_context_check(context, rb_table); rb_iv_set(rb_table, "@context", rb_context); if (rb_block_given_p()) return rb_ensure(rb_yield, rb_table, rb_grn_object_close, rb_table); else return rb_table; }
/* * Sets a configuration key and value pair. * * @overload config[]=(key, value) * @param [String] key The key. * @param [String] value The value to be assigned. * @return [String] `value`. */ static VALUE rb_grn_config_set (VALUE self, VALUE rb_key, VALUE rb_value) { VALUE rb_value_original = rb_value; VALUE rb_context; grn_ctx *context; const char *key; int key_size; const char *value; int value_size; rb_context = rb_iv_get(self, "@context"); context = rb_grn_context_ensure(&rb_context); rb_key = rb_grn_convert_to_string(rb_key); key = RSTRING_PTR(rb_key); key_size = RSTRING_LEN(rb_key); rb_value = rb_grn_convert_to_string(rb_value); value = RSTRING_PTR(rb_value); value_size = RSTRING_LEN(rb_value); { grn_rc rc; rc = grn_config_set(context, key, key_size, value, value_size); rb_grn_context_check(context, self); rb_grn_rc_check(rc, self); } return rb_value_original; }
/* * Gets a configuration value for key. * * @overload config[](key) * @param [String] key The key. * @return [String, nil] The value associated with `key`. * * @since 5.0.9 */ static VALUE rb_grn_config_get (VALUE self, VALUE rb_key) { VALUE rb_context; VALUE rb_value; grn_ctx *context; const char *key; int key_size; const char *value; uint32_t value_size; rb_context = rb_iv_get(self, "@context"); context = rb_grn_context_ensure(&rb_context); rb_key = rb_grn_convert_to_string(rb_key); key = RSTRING_PTR(rb_key); key_size = RSTRING_LEN(rb_key); { grn_rc rc; rc = grn_config_get(context, key, key_size, &value, &value_size); rb_grn_context_check(context, self); rb_grn_rc_check(rc, self); } if (value_size == 0) { rb_value = Qnil; } else { rb_value = rb_grn_context_rb_string_new(context, value, value_size); } return rb_value; }
static grn_table_cursor * rb_grn_patricia_trie_open_grn_rk_cursor (int argc, VALUE *argv, VALUE self, grn_ctx **context) { grn_obj *table; grn_table_cursor *cursor; void *prefix = NULL; unsigned prefix_size = 0; int offset = 0, limit = -1; int flags = GRN_CURSOR_PREFIX | GRN_CURSOR_RK; VALUE options, rb_prefix, rb_key_bytes, rb_key_bits; VALUE rb_greater_than, rb_less_than, rb_offset, rb_limit; rb_grn_table_deconstruct((RbGrnTable *)SELF(self), &table, context, NULL, NULL, NULL, NULL, NULL, NULL); rb_scan_args(argc, argv, "11", &rb_prefix, &options); rb_grn_scan_options(options, "key_bytes", &rb_key_bytes, "key_bites", &rb_key_bits, "offset", &rb_offset, "limit", &rb_limit, "greater_than", &rb_greater_than, "less_than", &rb_less_than, NULL); prefix = StringValuePtr(rb_prefix); if (!NIL_P(rb_key_bytes) && !NIL_P(rb_key_bits)) { rb_raise(rb_eArgError, "should not specify both :key_bytes and :key_bits once: %s", rb_grn_inspect(rb_ary_new4(argc, argv))); } else if (!NIL_P(rb_key_bytes)) { prefix_size = NUM2UINT(rb_key_bytes); } else if (!NIL_P(rb_key_bits)) { prefix_size = NUM2UINT(rb_key_bits); flags |= GRN_CURSOR_SIZE_BY_BIT; } else { prefix_size = RSTRING_LEN(rb_prefix); } if (!NIL_P(rb_offset)) offset = NUM2INT(rb_offset); if (!NIL_P(rb_limit)) limit = NUM2INT(rb_limit); if (RVAL2CBOOL(rb_greater_than)) flags |= GRN_CURSOR_GT; if (RVAL2CBOOL(rb_less_than)) flags |= GRN_CURSOR_LT; cursor = grn_table_cursor_open(*context, table, prefix, prefix_size, NULL, 0, offset, limit, flags); rb_grn_context_check(*context, self); return cursor; }
/* * Normalizes the @string@. * * @example * # Normalizes "ABC" with the default normalizer * Groonga::Normalizer.normalize("AbC") # => "abc" * * @overload normalize(string) * @return [String] The normalized string * @param [String] string The original string */ static VALUE rb_grn_normalizer_s_normalize (VALUE klass, VALUE rb_string) { VALUE rb_context = Qnil; VALUE rb_encoded_string; VALUE rb_normalized_string; grn_ctx *context = NULL; grn_obj *grn_string; grn_obj *normalizer = GRN_NORMALIZER_AUTO; /* TODO: make customizable */ int flags = GRN_STRING_REMOVE_BLANK; const char *normalized_string; unsigned int normalized_string_length; context = rb_grn_context_ensure(&rb_context); rb_encoded_string = rb_grn_context_rb_string_encode(context, rb_string); grn_string = grn_string_open(context, RSTRING_PTR(rb_encoded_string), RSTRING_LEN(rb_encoded_string), normalizer, flags); rb_grn_context_check(context, rb_string); grn_string_get_normalized(context, grn_string, &normalized_string, &normalized_string_length, NULL); rb_normalized_string = rb_grn_context_rb_string_new(context, normalized_string, normalized_string_length); grn_obj_close(context, grn_string); return rb_normalized_string; }
/* * @overload register(event_source_name, options={}) * * Registers Windows Event Log based logger that uses * `event_source_name` as event source name. * * @param event_source_name [String] The event source name. * @param options [::Hash] * @option options :context [Groonga::Context] (Groonga::Context.default) * The context to be set logger. * * @return [void] * * @since 5.0.5 */ static VALUE rb_grn_windows_event_logger_s_register (int argc, VALUE *argv, VALUE klass) { VALUE rb_event_source_name; VALUE rb_options; VALUE rb_context; const char *event_source_name; grn_ctx *context; grn_rc rc; rb_scan_args(argc, argv, "11", &rb_event_source_name, &rb_options); rb_event_source_name = rb_grn_convert_to_string(rb_event_source_name); event_source_name = StringValueCStr(rb_event_source_name); rb_grn_scan_options(rb_options, "context", &rb_context, NULL); context = rb_grn_context_ensure(&rb_context); rc = grn_windows_event_logger_set(context, event_source_name); rb_grn_context_check(context, rb_event_source_name); rb_grn_rc_check(rc, rb_event_source_name); return Qnil; }
/* * call-seq: * column.sources -> Groonga::Columnの配列 * * インデックス対象となっているカラムの配列を返す。 */ static VALUE rb_grn_index_column_get_sources (VALUE self) { grn_ctx *context = NULL; grn_obj *column; grn_obj sources; grn_id *source_ids; VALUE rb_sources; int i, n; rb_grn_index_column_deconstruct(SELF(self), &column, &context, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); GRN_OBJ_INIT(&sources, GRN_BULK, 0, GRN_ID_NIL); grn_obj_get_info(context, column, GRN_INFO_SOURCE, &sources); rb_grn_context_check(context, self); n = GRN_BULK_VSIZE(&sources) / sizeof(grn_id); source_ids = (grn_id *)GRN_BULK_HEAD(&sources); rb_sources = rb_ary_new2(n); for (i = 0; i < n; i++) { grn_obj *source; VALUE rb_source; source = grn_ctx_at(context, *source_ids); rb_source = GRNOBJECT2RVAL(Qnil, context, source, RB_GRN_FALSE); rb_ary_push(rb_sources, rb_source); source_ids++; } grn_obj_unlink(context, &sources); return rb_sources; }
/* * @overload [](id) * @param id [Integer, Groonga::Record] The record ID for the * column value. * * @return [Object] The value for the record ID. */ static VALUE rb_grn_column_cache_array_reference (VALUE self, VALUE rb_id) { RbGrnColumnCache *rb_grn_column_cache; grn_id id; void *value; size_t value_size = 0; TypedData_Get_Struct(self, RbGrnColumnCache, &data_type, rb_grn_column_cache); if (!rb_grn_column_cache->column_cache) { return Qnil; } id = rb_grn_id_from_ruby_object(rb_id, rb_grn_column_cache->context, rb_grn_column_cache->table, self); value = grn_column_cache_ref(rb_grn_column_cache->context, rb_grn_column_cache->column_cache, id, &value_size); rb_grn_context_check(rb_grn_column_cache->context, self); GRN_TEXT_SET_REF(&(rb_grn_column_cache->buffer), value, value_size); return GRNBULK2RVAL(rb_grn_column_cache->context, &(rb_grn_column_cache->buffer), rb_grn_column_cache->range, self); }
/* * 既存のデータベースを開く。ブロックを指定した場合はブロッ * クに開いたデータベースを渡し、ブロックを抜けるときに閉じ * る。 * * @overload new(path, options=nil) * @!macro [new] database.new.arguments * @param options [::Hash] The name and value * pairs. Omitted names are initialized as the default value. * @option options :context (Groonga::Context.default) * データベースを結びつけるコンテキスト。省略すると * {Groonga::Context.default} を利用する。 * @!macro database.new.arguments * @return [Groonga::Database] * @overload new(path, options=nil) * @!macro database.new.arguments * @yield [database] * @yieldparam [Groonga::Database] database 開いたデータベース */ static VALUE rb_grn_database_initialize (int argc, VALUE *argv, VALUE self) { grn_ctx *context; grn_obj *old_database, *database; const char *path; VALUE rb_path, options, rb_context; rb_scan_args(argc, argv, "11", &rb_path, &options); path = StringValuePtr(rb_path); rb_grn_scan_options(options, "context", &rb_context, NULL); context = rb_grn_context_ensure(&rb_context); old_database = grn_ctx_db(context); if (old_database) grn_obj_unlink(context, old_database); reset_floating_objects(rb_context); database = grn_db_open(context, path); rb_grn_object_assign(Qnil, self, rb_context, context, database); rb_grn_context_check(context, self); rb_iv_set(self, "@context", rb_context); if (!NIL_P(rb_context)) rb_iv_set(rb_context, "database", self); return Qnil; }
/* * Flush memory mapped data to disk. * * @overload flush(options={}) * @param [::Hash] options * @option options [Boolean] :recursive (true) Whether to flush objects * which a target object has recursively. * @return [void] */ static VALUE rb_grn_flushable_flush (int argc, VALUE *argv, VALUE self) { grn_ctx *context = NULL; grn_obj *object = NULL; VALUE rb_recursive_p; VALUE rb_options; rb_scan_args(argc, argv, "01", &rb_options); rb_grn_scan_options(rb_options, "recursive", &rb_recursive_p, NULL); if (NIL_P(rb_recursive_p)) { rb_recursive_p = Qtrue; } rb_grn_object_deconstruct(SELF(self), &object, &context, NULL, NULL, NULL, NULL); if (!object) { rb_raise(rb_eGrnClosed, "can't access already closed Groonga object: <%s>", rb_grn_inspect(self)); } if (RVAL2CBOOL(rb_recursive_p)) { grn_obj_flush_recursive(context, object); } else { grn_obj_flush(context, object); } rb_grn_context_check(context, self); return Qnil; }
/* * _object_ を追加し、 _n_arguments_ 個の引数を取る _operation_ を追加する。 * * @overload append_object(object, operation=Groonga::Operator::PUSH, n_arguments=1) * @param [Object] object 追加するオブジェクト * @param [Groonga::Operator::XXX] operation 追加する _operation_ * @param [Integer] n_arguments _operation_ の取る引数 * @return [Self] self * */ static VALUE rb_grn_expression_append_object (int argc, VALUE *argv, VALUE self) { VALUE rb_object, rb_operation, rb_n_arguments; grn_ctx *context = NULL; grn_obj *expression, *object; grn_operator operation = GRN_OP_PUSH; int n_arguments = 1; rb_scan_args(argc, argv, "12", &rb_object, &rb_operation, &rb_n_arguments); if (!NIL_P(rb_operation)) operation = RVAL2GRNOPERATOR(rb_operation); if (!NIL_P(rb_n_arguments)) n_arguments = NUM2INT(rb_n_arguments); rb_grn_expression_deconstruct(SELF(self), &expression, &context, NULL, NULL, NULL, NULL, NULL); object = RVAL2GRNOBJECT(rb_object, &context); grn_expr_append_obj(context, expression, object, operation, n_arguments); rb_grn_context_check(context, self); rb_ary_push(rb_iv_get(self, "@objects"), rb_object); return self; }
static VALUE rb_grn_expression_initialize (int argc, VALUE *argv, VALUE self) { grn_ctx *context = NULL; grn_obj *expression; VALUE options, rb_context, rb_name; char *name = NULL; unsigned name_size = 0; rb_scan_args(argc, argv, "01", &options); rb_grn_scan_options(options, "context", &rb_context, "name", &rb_name, NULL); context = rb_grn_context_ensure(&rb_context); if (!NIL_P(rb_name)) { name = StringValuePtr(rb_name); name_size = RSTRING_LEN(rb_name); } expression = grn_expr_create(context, name, name_size); rb_grn_context_check(context, self); rb_grn_object_assign(Qnil, self, rb_context, context, expression); rb_grn_context_register_floating_object(DATA_PTR(self)); rb_iv_set(self, "@objects", rb_ary_new()); return Qnil; }
/* * _database_ をロックする。ロックに失敗した場合は * {Groonga::ResourceDeadlockAvoided} 例外が発生する。 * * @overload lock(options={}) * @!macro [new] database.lock.arguments * @param [::Hash] options 利用可能なオプションは以下の通り。 * @option options :timeout * ロックを獲得できなかった場合は _:timeout_ 秒間ロックの獲 * 得を試みる。 _:timeout_ 秒以内にロックを獲得できなかった * 場合は例外が発生する。 * @!macro database.lock.arguments * @overload lock(options={}) * @yield ブロックを指定した場合はブロックを抜けたときにunlockする。 * @!macro database.lock.arguments */ static VALUE rb_grn_database_lock (int argc, VALUE *argv, VALUE self) { grn_ctx *context; grn_obj *database; int timeout = 0; grn_rc rc; VALUE options, rb_timeout; rb_scan_args(argc, argv, "01", &options); rb_grn_database_deconstruct(SELF(self), &database, &context, NULL, NULL, NULL, NULL); rb_grn_scan_options(options, "timeout", &rb_timeout, NULL); if (!NIL_P(rb_timeout)) timeout = NUM2UINT(rb_timeout); rc = grn_obj_lock(context, database, GRN_ID_NIL, timeout); rb_grn_context_check(context, self); rb_grn_rc_check(rc, self); if (rb_block_given_p()) { return rb_ensure(rb_yield, Qnil, rb_grn_database_unlock, self); } else { return Qnil; } }
grn_obj * rb_grn_value_from_ruby_object (VALUE object, grn_ctx *context, grn_obj *value, grn_id type_id, grn_obj *type) { grn_bool string_p, table_type_p; string_p = rb_type(object) == T_STRING; table_type_p = (GRN_TABLE_HASH_KEY <= type->header.type && type->header.type <= GRN_TABLE_NO_KEY); if (!string_p) { return RVAL2GRNBULK_WITH_TYPE(object, context, value, type_id, type); } if (table_type_p && RSTRING_LEN(object) == 0) { if (value) { if (value->header.domain != type_id) { grn_obj_reinit(context, value, type_id, 0); } } else { value = grn_obj_open(context, GRN_BULK, 0, type_id); rb_grn_context_check(context, object); } GRN_RECORD_SET(context, value, GRN_ID_NIL); return value; } return RVAL2GRNBULK(object, context, value); }
static int rb_grn_hash_from_ruby_hash_body (VALUE rb_key, VALUE rb_value, VALUE user_data) { RbGrnHashFromRubyHashData *data = (RbGrnHashFromRubyHashData *)user_data; grn_obj *value; int added; rb_key = rb_grn_convert_to_string(rb_key); grn_hash_add(data->context, data->hash, RSTRING_PTR(rb_key), RSTRING_LEN(rb_key), (void **)&value, &added); rb_grn_context_check(data->context, data->rb_hash); if (added) { GRN_VOID_INIT(value); } RVAL2GRNBULK(rb_value, data->context, value); return ST_CONTINUE; }
/* * Pushes a record to the array. The record should be filled in the * given block. The pushed record can be pulled by * {Groonga::Array#pull}. * * @example A program that pushes a job without error handling * queue = Groonga::Array.create(:name => "CrawlURLQueue") * queue.define_column("url", "ShortText") * urls = ["http://groonga.org/", "http://ranguba.org/"] * urls.each do |url| * queue.push do |record| * record.url = url * end * end * * @example A program that pulls a job without error handling * queue = Groonga::Array.open(:name => "CrawlURLQueue") * loop do * url = nil * queue.pull do |record| * url = record.url * record.delete * end * # Crawl URL * end * * The record that is passed to the given block may be nil. You need * to handle the case. For example, just ignoring it or reports an * error. * * @example A program that pushes a job with error handling * queue = Groonga::Array.create(:name => "CrawlURLQueue") * queue.define_column("url", "ShortText") * urls = ["http://groonga.org/", "http://ranguba.org/"] * urls.each do |url| * queue.push do |record| * record.url = url if record # check record is not nil * end * end * * If an error is occurred in the given block, the pushed record may * not be filled completely. You should handle the case in pull side. * * @example A program that has an error in push block * queue = Groonga::Array.create(:name => "CrawlURLQueue") * queue.define_column("url", "ShortText") * urls = ["http://groonga.org/", "http://ranguba.org/"] * urls.each do |url| * queue.push do |record| * record.url = uri # Typo! It should be ur*l* not ur*i* * # record.url isn't set * end * end * * @example A program that pulls a job with error handling * queue = Groonga::Array.open(:name => "CrawlURLQueue") * loop do * url = nil * queue.pull do |record| * url = record.url # record.url is nil! * record.delete * end * next if url.nil? # Ignore an uncompleted added job * # Crawl URL * end * * @overload push * @yield [record] Filles columns of a pushed record in the given block. * @yieldparam record [Groonga::Record or nil] * A pushed record. It is nil when pushing is failed. * @return [Groonga::Record or nil] A pushed record that is yielded. * */ static VALUE rb_grn_array_push (VALUE self) { grn_ctx *context = NULL; grn_obj *table; YieldRecordCallbackData data; if (!rb_block_given_p()) { rb_raise(rb_eArgError, "tried to call Groonga::Array#push without a block"); } table = SELF(self, &context); data.self = self; data.record = Qnil; data.status = 0; grn_array_push(context, (grn_array *)table, yield_record_callback, &data); if (data.status != 0) { rb_jump_tag(data.status); } rb_grn_context_check(context, self); return data.record; }
/* * Defrags the column. * * @overload defrag(options={}) * @param options [::Hash] The name and value * pairs. Omitted names are initialized as the default value. * @option options [Integer] :threshold (0) the threshold to * determine whether a segment is defraged. Available * values are -4..22. -4 means all segments are defraged. * 22 means no segment is defraged. * @return [Integer] the number of defraged segments * @since 1.2.6 */ static VALUE rb_grn_variable_size_column_defrag (int argc, VALUE *argv, VALUE self) { RbGrnVariableSizeColumn *rb_grn_column; grn_ctx *context = NULL; grn_obj *column; int n_segments; VALUE options, rb_threshold; int threshold = 0; rb_scan_args(argc, argv, "01", &options); rb_grn_scan_options(options, "threshold", &rb_threshold, NULL); if (!NIL_P(rb_threshold)) { threshold = NUM2INT(rb_threshold); } rb_grn_column = SELF(self); rb_grn_object_deconstruct(RB_GRN_OBJECT(rb_grn_column), &column, &context, NULL, NULL, NULL, NULL); n_segments = grn_obj_defrag(context, column, threshold); rb_grn_context_check(context, self); return INT2NUM(n_segments); }
/* * IDが _id_ であるレコードを高速に全文検索するため転置索引を作 * 成する。多くの場合、 {Groonga::Table#define_index_column} で * +:source+ オプションを指定することにより、自動的に全文検索 * 用の索引は更新されるので、明示的にこのメソッドを使うこと * は少ない。 * * @example 記事の段落毎に索引を作成する。 * articles = Groonga::Array.create(:name => "<articles>") * articles.define_column("title", "ShortText") * articles.define_column("content", "Text") * * terms = Groonga::Hash.create(:name => "<terms>", * :default_tokenizer => "TokenBigram") * content_index = terms.define_index_column("content", articles, * :with_section => true) * * content = <<-EOC * groonga は組み込み型の全文検索エンジンライブラリです。 * DBMSやスクリプト言語処理系等に組み込むことによって、その * 全文検索機能を強化することができます。また、リレーショナ * ルモデルに基づくデータストア機能を内包しており、groonga * 単体でも高速なデータストアサーバとして使用することができ * ます。 * * ■全文検索方式 * 転置索引型の全文検索エンジンです。転置索引は圧縮されてファ * イルに格納され、検索時のディスク読み出し量を小さく、かつ * 局所的に抑えるように設計されています。用途に応じて以下の * 索引タイプを選択できます。 * EOC * * groonga = articles.add(:title => "groonga", :content => content) * * content.split(/\n{2,}/).each_with_index do |sentence, i| * content_index[groonga] = {:value => sentence, :section => i + 1} * end * * content_index.search("エンジン").collect do |record| * p record.key["title"] # -> "groonga" * end * * @overload []=(id, value) * @param [String] value 新しい値 * @overload []=(id, options) * _options_ を指定することにより、 _value_ を指定したときよりも索引の作 * 成を制御できる。 * @param [::Hash] options The name and value * pairs. Omitted names are initialized as the default value * @option options :section * 段落番号を指定する。省略した場合は1を指定したとみなされ * る。 * {Groonga::Table#define_index_column} で * @{:with_section => true}@ を指定していなければい * けない。 * @option options :old_value * 以前の値を指定する。省略した場合は現在の値が用いられる。 * 通常は指定する必要はない。 * @option options :value * 新しい値を指定する。 _value_ を指定した場合と _options_ で * @{:value => value}@ を指定した場合は同じ動作とな * る。 * * @deprecated Since 3.0.2. Use {#add}, {#delete} or {#update} instead. */ static VALUE rb_grn_index_column_array_set (VALUE self, VALUE rb_id, VALUE rb_value) { grn_ctx *context = NULL; grn_obj *column, *range; grn_rc rc; grn_id id; unsigned int section; grn_obj *old_value, *new_value; VALUE original_rb_value, rb_section, rb_old_value, rb_new_value; original_rb_value = rb_value; rb_grn_index_column_deconstruct(SELF(self), &column, &context, NULL, NULL, &new_value, &old_value, NULL, &range, NULL, NULL); id = RVAL2GRNID(rb_id, context, range, self); if (!RVAL2CBOOL(rb_obj_is_kind_of(rb_value, rb_cHash))) { VALUE hash_value; hash_value = rb_hash_new(); rb_hash_aset(hash_value, RB_GRN_INTERN("value"), rb_value); rb_value = hash_value; } rb_grn_scan_options(rb_value, "section", &rb_section, "old_value", &rb_old_value, "value", &rb_new_value, NULL); if (NIL_P(rb_section)) section = 1; else section = NUM2UINT(rb_section); if (NIL_P(rb_old_value)) { old_value = NULL; } else { GRN_BULK_REWIND(old_value); RVAL2GRNBULK(rb_old_value, context, old_value); } if (NIL_P(rb_new_value)) { new_value = NULL; } else { GRN_BULK_REWIND(new_value); RVAL2GRNBULK(rb_new_value, context, new_value); } rc = grn_column_index_update(context, column, id, section, old_value, new_value); rb_grn_context_check(context, self); rb_grn_rc_check(rc, self); return original_rb_value; }
/* * Document-method: unlock * * call-seq: * column.unlock(options={}) * * _column_のロックを解除する。 * * 利用可能なオプションは以下の通り。 * * [_:id_] * _:id_で指定したレコードのロックを解除する。(注: * groonga側が未実装のため、現在は無視される) */ static VALUE rb_grn_column_unlock (int argc, VALUE *argv, VALUE self) { grn_id id = GRN_ID_NIL; grn_ctx *context; grn_obj *column; grn_rc rc; VALUE options, rb_id; rb_scan_args(argc, argv, "01", &options); rb_grn_column_deconstruct(SELF(self), &column, &context, NULL, NULL, NULL, NULL, NULL); rb_grn_scan_options(options, "id", &rb_id, NULL); if (!NIL_P(rb_id)) id = NUM2UINT(rb_id); rc = grn_obj_unlock(context, column, id); rb_grn_context_check(context, self); rb_grn_rc_check(rc, self); return Qnil; }
/* * 名前が _name_ の型を作成する。 * * @overload new(name, options={}) * @param name [String] 作成する型の名前 * @param options [::Hash] The name and value * pairs. Omitted names are initialized as the default value * @option options [Symbol] :type (:variable) * :integer(符号付き整数)、:int(:integerの省略 * 形)、:unsigned_integer(符号なし整 * 数)、:uint(:unsigned_integerの省略形)、:float(浮動小数点 * 数)、:variable(可変長文字列)のいずれかを指定する。省略した場 * 合は:variableを指定したものと扱う。 * :variableを指定した場合は必ず +:size+ を指定しなければいけない。 * @option options [Context] :context * 型の作成時に利用するGroonga::Contextを指定する。省略すると * Groonga::Context.defaultを用いる。 * @option options [Integer] :size * +:option+ が:variableの場合は最大長、それ以外の場合は長さを * 指定する(単位:byte)。 */ static VALUE rb_grn_type_initialize (int argc, VALUE *argv, VALUE self) { grn_ctx *context; grn_obj *type; const char *name = NULL; unsigned name_size, size = 0; grn_obj_flags flags = 0; VALUE rb_name, options, rb_context, rb_type, rb_size; rb_scan_args(argc, argv, "11", &rb_name, &options); rb_grn_scan_options(options, "context", &rb_context, "type", &rb_type, "size", &rb_size, NULL); name = StringValuePtr(rb_name); name_size = RSTRING_LEN(rb_name); context = rb_grn_context_ensure(&rb_context); if (NIL_P(rb_type) || rb_grn_equal_option(rb_type, "variable")) { flags = GRN_OBJ_KEY_VAR_SIZE; } else if (rb_grn_equal_option(rb_type, "integer") || rb_grn_equal_option(rb_type, "int")) { flags = GRN_OBJ_KEY_INT; size = sizeof(int); } else if (rb_grn_equal_option(rb_type, "unsigned_integer") || rb_grn_equal_option(rb_type, "uint")) { flags = GRN_OBJ_KEY_UINT; size = sizeof(unsigned int); } else if (rb_grn_equal_option(rb_type, "float")) { flags = GRN_OBJ_KEY_FLOAT; size = sizeof(double); } else { rb_raise(rb_eArgError, ":type should be one of " "[:integer, :int, :unsigned_integer, :uint, " ":float, :variable]: %s", rb_grn_inspect(options)); } if (NIL_P(rb_size)) { if (size == 0) rb_raise(rb_eArgError, "size is missing: %s", rb_grn_inspect(options)); } else { size = NUM2UINT(rb_size); } type = grn_type_create(context, name, name_size, flags, size); rb_grn_object_assign(Qnil, self, rb_context, context, type); rb_grn_context_check(context, rb_ary_new4(argc, argv)); return Qnil; }
static grn_table_cursor * rb_grn_patricia_trie_open_grn_near_cursor (int argc, VALUE *argv, VALUE self, grn_ctx **context, int flags) { grn_obj *table; grn_obj *key_p = NULL, casted_key; grn_table_cursor *cursor; unsigned min_size = 0; int offset = 0, limit = -1; VALUE options, rb_key, rb_min_size; VALUE rb_greater_than, rb_less_than, rb_offset, rb_limit; flags |= GRN_CURSOR_PREFIX; rb_grn_table_deconstruct((RbGrnTable *)SELF(self), &table, context, NULL, NULL, NULL, NULL, NULL, NULL); rb_scan_args(argc, argv, "11", &rb_key, &options); rb_grn_scan_options(options, "size", &rb_min_size, "offset", &rb_offset, "limit", &rb_limit, "greater_than", &rb_greater_than, "less_than", &rb_less_than, NULL); key_p = RVAL2GRNBULK_WITH_TYPE(rb_key, *context, key_p, table->header.domain, grn_ctx_at(*context, table->header.domain)); GRN_OBJ_INIT(&casted_key, GRN_BULK, 0, table->header.domain); if (key_p->header.domain != table->header.domain) { grn_obj_cast(*context, key_p, &casted_key, 0); key_p = &casted_key; } if (!NIL_P(rb_min_size)) min_size = NUM2UINT(rb_min_size); if (!NIL_P(rb_offset)) offset = NUM2INT(rb_offset); if (!NIL_P(rb_limit)) limit = NUM2INT(rb_limit); if (RVAL2CBOOL(rb_greater_than)) flags |= GRN_CURSOR_GT; if (RVAL2CBOOL(rb_less_than)) flags |= GRN_CURSOR_LT; cursor = grn_table_cursor_open(*context, table, NULL, min_size, GRN_BULK_HEAD(key_p), GRN_BULK_VSIZE(key_p), offset, limit, flags); GRN_OBJ_FIN(*context, &casted_key); rb_grn_context_check(*context, self); return cursor; }
/* * 新しくデータベースを作成する。 * _options_ にはハッシュでオプションを指定する。 * * @example * # 一時データベースを作成: * Groonga::Database.create * * # 永続データベースを作成: * Groonga::Database.create(:path => "/tmp/db.groonga") * * @overload create(options=nil) * @return [Groonga::Database] 作成されたデータベースを返す。 * @param [::Hash] options The name and value * pairs. Omitted names are initialized as the default value. * @option options :path * データベースを保存するパス。省略すると一時データベース * となる。 * @option options :context (Groonga::Context.default) * データベースを結びつけるコンテキスト。省略すると * {Groonga::Context.default} を利用する。 */ static VALUE rb_grn_database_s_create (int argc, VALUE *argv, VALUE klass) { grn_ctx *context; grn_obj *old_database, *database; grn_db_create_optarg create_args; const char *path = NULL; VALUE rb_database; VALUE rb_path, options, rb_context, builtin_type_names; grn_bool owner; rb_scan_args(argc, argv, "01", &options); rb_grn_scan_options(options, "path", &rb_path, "context", &rb_context, "builtin_type_names", &builtin_type_names, NULL); if (!NIL_P(rb_path)) path = StringValuePtr(rb_path); context = rb_grn_context_ensure(&rb_context); create_args.builtin_type_names = NULL; create_args.n_builtin_type_names = 0; old_database = grn_ctx_db(context); if (old_database) grn_obj_unlink(context, old_database); reset_floating_objects(rb_context); database = grn_db_create(context, path, &create_args); rb_grn_context_check(context, rb_ary_new_from_values(argc, argv)); owner = (context->flags & GRN_CTX_PER_DB) ? GRN_FALSE : GRN_TRUE; rb_database = GRNOBJECT2RVAL(klass, context, database, owner); rb_iv_set(rb_database, "@context", rb_context); if (!NIL_P(rb_context)) rb_iv_set(rb_context, "database", rb_database); rb_grn_context_check(context, rb_ary_new_from_values(argc, argv)); if (rb_block_given_p()) return rb_ensure(rb_yield, rb_database, rb_grn_database_close, rb_database); else return rb_database; }
/* * Document-method: search * * call-seq: * column.search(query, options={}) -> Groonga::Hash * * _object_から_query_に対応するオブジェクトを検索し、見つかっ * たオブジェクトのIDがキーになっているGroonga::Hashを返す。 * * 利用可能なオプションは以下の通り。 * * [_:result_] * 結果を格納するGroonga::Hash。指定しない場合は新しく * Groonga::Hashを生成し、それに結果を格納して返す。 * [_:operator_] * 以下のどれかの値を指定する。+nil+, <tt>"or"</tt>, <tt>"||"</tt>, * <tt>"and"</tt>, <tt>"+"</tt>, <tt>"&&"</tt>, <tt>"but"</tt>, * <tt>"not"</tt>, <tt>"-"</tt>, <tt>"adjust"</tt>, <tt>">"</tt>。 * それぞれ以下のようになる。(FIXME: 「以下」) * [_:exact_] * +true+を指定すると完全一致で検索する * [_:longest_common_prefix_] * +true+を指定すると_query_と同じ接頭辞をもつエントリのう * ち、もっとも長いエントリを検索する * [_:suffix_] * +true+を指定すると_query_が後方一致するエントリを検索す * る * [_:prefix_] * +true+を指定すると_query_が前方一致するレコードを検索す * る * [_:near_] * +true+を指定すると_query_に指定した複数の語が近傍に含ま * れるレコードを検索する * [...] * ... */ static VALUE rb_grn_index_column_search (int argc, VALUE *argv, VALUE self) { grn_ctx *context; grn_obj *column; grn_obj *range; grn_obj *query = NULL, *id_query = NULL, *string_query = NULL; grn_obj *result; grn_operator operator; grn_rc rc; VALUE rb_query, options, rb_result, rb_operator; rb_grn_index_column_deconstruct(SELF(self), &column, &context, NULL, NULL, NULL, NULL, NULL, &range, &id_query, &string_query); rb_scan_args(argc, argv, "11", &rb_query, &options); if (CBOOL2RVAL(rb_obj_is_kind_of(rb_query, rb_cGrnQuery))) { grn_query *_query; _query = RVAL2GRNQUERY(rb_query); query = (grn_obj *)_query; } else if (CBOOL2RVAL(rb_obj_is_kind_of(rb_query, rb_cInteger))) { grn_id id; id = NUM2UINT(rb_query); GRN_TEXT_SET(context, id_query, &id, sizeof(grn_id)); query = id_query; } else { const char *_query; _query = StringValuePtr(rb_query); GRN_TEXT_SET(context, string_query, _query, RSTRING_LEN(rb_query)); query = string_query; } rb_grn_scan_options(options, "result", &rb_result, "operator", &rb_operator, NULL); if (NIL_P(rb_result)) { result = grn_table_create(context, NULL, 0, NULL, GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC, range, 0); rb_grn_context_check(context, self); rb_result = GRNOBJECT2RVAL(Qnil, context, result, RB_GRN_TRUE); } else { result = RVAL2GRNOBJECT(rb_result, &context); } operator = RVAL2GRNOPERATOR(rb_operator); rc = grn_obj_search(context, column, query, result, operator, NULL); rb_grn_rc_check(rc, self); return rb_result; }
/* * Updates a record that has @new_value@ as new content and * @old_value@ as old content in inverted index. Normally, this method * is not used explicitly. Inverted index for fulltext search is * updated automatically by using @:source@ option of * {Groonga::Table#define_index_column}. * * @example Updates sentences of an article in index * articles = Groonga::Array.create(:name => "Articles") * articles.define_column("title", "ShortText") * articles.define_column("content", "Text") * * terms = Groonga::Hash.create(:name => "Terms", * :key_type => "ShortText", * :default_tokenizer => "TokenBigram") * content_index = terms.define_index_column("content", articles, * :with_position => true, * :with_section => true) * * old_sentence = <<-SENTENCE * Groonga is a fast and accurate full text search engine based on * inverted index. One of the characteristics of groonga is that a * newly registered document instantly appears in search * results. Also, groonga allows updates without read locks. These * characteristics result in superior performance on real-time * applications. * SENTENCE * * new_sentence = <<-SENTENCE * Groonga is also a column-oriented database management system * (DBMS). Compared with well-known row-oriented systems, such as * MySQL and PostgreSQL, column-oriented systems are more suited for * aggregate queries. Due to this advantage, groonga can cover * weakness of row-oriented systems. * SENTENCE * * groonga = articles.add(:title => "groonga", :content => old_sentence) * * content_index.add(groonga, old_sentence, :section => 1) * p content_index.search("engine").size # -> 1 * p content_index.search("MySQL").size # -> 0 * * groonga[:content] = new_sentence * content_index.update(groonga, old_sentence, new_sentence, :section => 1) * p content_index.search("engine").size # -> 0 * p content_index.search("MySQL").size # -> 1 * * @overload update(record, old_value, new_value, options={}) * @param [Groonga::Record, Integer] record * The record that has a @new_value@ as its new value and * @old_value@ as its old value. It can be Integer as record id. * @param [String] old_value * The old value of the @record@. * @param [String] new_value * The new value of the @record@. * @param [::Hash] options * The options. * @option options [Integer] :section (1) * The section number. It is one-origin. * * You must specify @{:with_section => true}@ in * {Groonga::Table#define_index_column} to use this option. * @return [void] * * @since 3.0.2 */ static VALUE rb_grn_index_column_update (int argc, VALUE *argv, VALUE self) { grn_ctx *context = NULL; grn_obj *column, *range; grn_rc rc; grn_id id; unsigned int section; grn_obj *old_value, *new_value; VALUE rb_record, rb_old_value, rb_new_value, rb_options, rb_section; rb_scan_args(argc, argv, "31", &rb_record, &rb_old_value, &rb_new_value, &rb_options); rb_grn_index_column_deconstruct(SELF(self), &column, &context, NULL, NULL, &new_value, &old_value, NULL, &range, NULL, NULL); id = RVAL2GRNID(rb_record, context, range, self); if (NIL_P(rb_old_value)) { old_value = NULL; } else { GRN_BULK_REWIND(old_value); RVAL2GRNBULK(rb_old_value, context, old_value); } if (NIL_P(rb_new_value)) { new_value = NULL; } else { GRN_BULK_REWIND(new_value); RVAL2GRNBULK(rb_new_value, context, new_value); } rb_grn_scan_options(rb_options, "section", &rb_section, NULL); if (NIL_P(rb_section)) { section = 1; } else { section = NUM2UINT(rb_section); } rc = grn_column_index_update(context, column, id, section, old_value, new_value); rb_grn_context_check(context, self); rb_grn_rc_check(rc, self); return self; }
/* * Sends reopen request to the current query logger. It is useful for * rotating log file. * * @overload reopen * @return void */ static VALUE rb_grn_query_logger_s_reopen (VALUE klass) { VALUE rb_context = Qnil; grn_ctx *context; context = rb_grn_context_ensure(&rb_context); grn_query_logger_reopen(context); rb_grn_context_check(context, klass); return Qnil; }
static VALUE rb_grn_logger_s_reopen_with_related_object (VALUE klass, VALUE related_object) { VALUE rb_context = Qnil; grn_ctx *context; context = rb_grn_context_ensure(&rb_context); rb_grn_logger_reset_with_error_check(klass, context); grn_logger_reopen(context); rb_grn_context_check(context, related_object); return Qnil; }
/* * call-seq: * column.table -> Groonga::Table * * カラムが所属するテーブルを返す。 */ static VALUE rb_grn_column_get_table (VALUE self) { grn_ctx *context = NULL; grn_obj *column; grn_obj *table; rb_grn_object_deconstruct((RbGrnObject *)(SELF(self)), &column, &context, NULL, NULL, NULL, NULL); table = grn_column_table(context, column); rb_grn_context_check(context, self); return GRNOBJECT2RVAL(Qnil, context, table, RB_GRN_FALSE); }
/* * @overload unmap() * * Unmaps all mapped tables and columns in database. * * It frees resources for them. * * Normally, you don't need to unmap explicitly. Because OS manages * resourced for mapped tables and columns cleverly. * * @return [void] * * @since 5.0.5 */ static VALUE rb_grn_database_unmap (VALUE self) { grn_rc rc; grn_ctx *context; grn_obj *database; rb_grn_database_deconstruct(SELF(self), &database, &context, NULL, NULL, NULL, NULL); rc = grn_db_unmap(context, database); rb_grn_context_check(context, self); rb_grn_rc_check(rc, self); return Qnil; }
/* * call-seq: * context.receive -> [ID, String] * * groongaサーバからクエリ実行結果文字列を受信する。 */ static VALUE rb_grn_context_receive (VALUE self) { grn_ctx *context; char *string; unsigned string_size; int flags = 0; unsigned int query_id; context = SELF(self); query_id = grn_ctx_recv(context, &string, &string_size, &flags); rb_grn_context_check(context, self); return rb_ary_new3(2, UINT2NUM(query_id), rb_str_new(string, string_size)); }