コード例 #1
0
ファイル: rb-grn-snippet.c プロジェクト: keitahaga/rroonga
/*
 * スニペットを作成する。
 *
 * @overload new(options={})
 *   @param options [::Hash] The name and value
 *     pairs. Omitted names are initialized as the default value.
 *   @option options :context (Groonga::Context.default)
 *     スキーマ作成時に使用するGroonga::Contextを指定する。
 *   @option options :normalize
 *     キーワード文字列・スニペット元の文字列を正規化するかどうか。
 *     省略した場合は +false+ で正規化しない。
 *   @option options :skip_leading_spaces (false)
 *     先頭の空白を無視するかどうか。省略した場合は +false+ で無視しない。
 *   @option options :width (100)
 *     スニペット文字列の長さ。省略した場合は100文字。
 *   @option options :max_results (3)
 *     生成するスニペットの最大数。省略した場合は3。
 *   @option options :html_escape (false)
 *     スニペット内の +<+ , +>+ , +&+ , +"+ をHTMLエスケープするかどうか。
 *     省略した場合は +false+ で、HTMLエスケープしない。
 *   @option options :default_open_tag ("")
 *     デフォルトの開始タグ。省略した場合は""(空文字列)
 *   @option options :default_close_tag ("")
 *     デフォルトの終了タグ。省略した場合は""(空文字列)
 */
static VALUE
rb_grn_snippet_initialize (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context = NULL;
    grn_snip *snippet = NULL;
    VALUE options;
    VALUE rb_context, rb_normalize, rb_skip_leading_spaces;
    VALUE rb_width, rb_max_results, rb_default_open_tag, rb_default_close_tag;
    VALUE rb_html_escape;
    int flags = GRN_SNIP_COPY_TAG;
    unsigned int width = 100;
    unsigned int max_results = 3;
    char *default_open_tag = NULL;
    unsigned int default_open_tag_length = 0;
    char *default_close_tag = NULL;
    unsigned int default_close_tag_length = 0;
    grn_snip_mapping *mapping = NULL;

    rb_scan_args(argc, argv, "01", &options);

    rb_grn_scan_options(options,
                        "context", &rb_context,
                        "normalize", &rb_normalize,
                        "skip_leading_spaces", &rb_skip_leading_spaces,
                        "width", &rb_width,
                        "max_results", &rb_max_results,
                        "default_open_tag", &rb_default_open_tag,
                        "default_close_tag", &rb_default_close_tag,
                        "html_escape", &rb_html_escape,
                        NULL);

    context = rb_grn_context_ensure(&rb_context);
    if (!grn_ctx_db(context)) {
        rb_raise(rb_eArgError,
                 "Groonga::Context should be associated with a database by "
                 "Groonga::Database#open or #create: %s",
                 rb_grn_inspect(rb_context));
    }

    if (RVAL2CBOOL(rb_normalize))
        flags |= GRN_SNIP_NORMALIZE;
    if (RVAL2CBOOL(rb_skip_leading_spaces))
        flags |= GRN_SNIP_SKIP_LEADING_SPACES;

    if (!NIL_P(rb_width))
        width = NUM2UINT(rb_width);

    if (!NIL_P(rb_max_results))
        max_results = NUM2UINT(rb_max_results);

    if (!NIL_P(rb_default_open_tag)) {
        default_open_tag = StringValuePtr(rb_default_open_tag);
        default_open_tag_length = RSTRING_LEN(rb_default_open_tag);
    }

    if (!NIL_P(rb_default_close_tag)) {
        default_close_tag = StringValuePtr(rb_default_close_tag);
        default_close_tag_length = RSTRING_LEN(rb_default_close_tag);
    }

    if (RVAL2CBOOL(rb_html_escape))
        mapping = (grn_snip_mapping *)-1;

    snippet = grn_snip_open(context, flags, width, max_results,
                            default_open_tag, default_open_tag_length,
                            default_close_tag, default_close_tag_length,
                            mapping);
    rb_grn_context_check(context, rb_ary_new4(argc, argv));

    rb_grn_object_assign(Qnil, self, rb_context, context, (grn_obj *)snippet);
    rb_grn_context_register_floating_object(DATA_PTR(self));

    rb_iv_set(self, "@context", rb_context);

    return Qnil;
}
コード例 #2
0
ファイル: rb-grn-logger.c プロジェクト: kenhys/rroonga
/*
 * Logs a message.
 *
 * @overload log(message, options={})
 *   @param message [String] The log message.
 *   @param options [::Hash]
 *   @option options :context [Groonga::Context] (Groonga::Context.default)
 *     The context for the message.
 *   @option options :level [nil, :none, :emergency, :alert, :critical,
 *     :error, :warning, :notice, :info, :debug, :dump] (:notice)
 *     The level for the message.
 *
 *     `nil` equals to `:notice`.
 *   @option options :file [nil, String] (nil)
 *     The file name where the message is occurred.
 *
 *     If all of `:file`, `:line` and `:function` are nil, these
 *     values are guessed from `Kernel.#caller_locations` result.
 *   @option options :line [nil, Integer] (nil)
 *     The line number where the message is occurred.
 *   @option options :function [nil, String] (nil)
 *     The function or related name such as method name where the
 *     message is occurred.
 *   @return [void]
 *
 * @since 5.0.2
 */
static VALUE
rb_grn_logger_s_log (int argc, VALUE *argv, VALUE klass)
{
    VALUE rb_message;
    const char *message;
    VALUE rb_context = Qnil;
    grn_ctx *context;
    VALUE rb_level;
    grn_log_level level = GRN_LOG_DEFAULT_LEVEL;
    VALUE rb_file;
    const char *file = NULL;
    VALUE rb_line;
    int line = 0;
    VALUE rb_function;
    const char *function = NULL;
    VALUE rb_options;

    rb_scan_args(argc, argv, "11", &rb_message, &rb_options);

    message = StringValueCStr(rb_message);

    rb_grn_scan_options(rb_options,
                        "context",  &rb_context,
                        "level",    &rb_level,
                        "file",     &rb_file,
                        "line",     &rb_line,
                        "function", &rb_function,
                        NULL);

    context = rb_grn_context_ensure(&rb_context);

    if (!NIL_P(rb_level)) {
        level = RVAL2GRNLOGLEVEL(rb_level);
    }

    if (NIL_P(rb_file) && NIL_P(rb_line) && NIL_P(rb_function)) {
        VALUE rb_locations;
        VALUE rb_location;
        rb_locations = rb_funcall(rb_cObject,
                                  id_caller_locations,
                                  2,
                                  INT2NUM(1), INT2NUM(1));
        rb_location = RARRAY_PTR(rb_locations)[0];
        rb_file = rb_funcall(rb_location, id_path, 0);
        rb_line = rb_funcall(rb_location, id_lineno, 0);
        rb_function = rb_funcall(rb_location, id_label, 0);
    }

    if (!NIL_P(rb_file)) {
        file = StringValueCStr(rb_file);
    }
    if (!NIL_P(rb_line)) {
        line = NUM2INT(rb_line);
    }
    if (!NIL_P(rb_function)) {
        function = StringValueCStr(rb_function);
    }

    grn_logger_put(context, level, file, line, function, "%s", message);

    return Qnil;
}
コード例 #3
0
ファイル: rb-grn-logger.c プロジェクト: kenhys/rroonga
/*
 * groongaがログを出力する度に呼び出されるブロックを登録する。
 *
 * @overload register(options={})
 *   @yield [event, level, time, title, message, location]
 *     _event_ と _level_ はSymbol、それ以外は全て文字列で渡される。
 *     _event_ と _level_ 以外
 *     の4つについては _options_ で +false+ を指定することでブロックに
 *     渡さないようにすることができ、その場合は空文字列が実際には渡される。
 *   @param options [::Hash] The name and value
 *     pairs. Omitted names are initialized as the default value.
 *   @option options :max_level (:notice)
 *     ログのレベルを +:none+ ,  +:emergency+ ,  +:alert+ ,
 *     +:critical+ , +:error+ , +:warning+ , +:notice+ , +:info+ ,
 *     +:debug+ ,  +:dump+ のいずれかで指定する。それより重要度が
 *     低いログはブロックに渡されなくなる。デフォルトでは +:notice+ 。
 *   @option options :time
 *     ログが出力された時間をブロックに渡したいなら +true+ を指
 *     定する。デフォルトでは渡す。
 *   @option options :title
 *     ログのタイトルをブロックに渡したいなら +true+ を指定す
 *     る。デフォルトでは渡す。
 *     (FIXME: groongaで実装されていない?)
 *   @option options :message
 *     ログのメッセージをブロックに渡したいなら +true+ を指定す
 *     る。デフォルトでは渡す。
 *   @option options :location
 *     ログの発生元のプロセスIDとgroongaのソースコードのファイ
 *     ル名、行番号、関数名をブロックに渡したいなら +true+ を指
 *     定する。デフォルトでは渡す。
 */
static VALUE
rb_grn_logger_s_register (int argc, VALUE *argv, VALUE klass)
{
    VALUE rb_context = Qnil;
    grn_ctx *context;
    VALUE rb_logger, rb_callback;
    VALUE rb_options, rb_max_level;
    VALUE rb_time, rb_title, rb_message, rb_location;
    VALUE rb_flags;
    grn_log_level max_level = GRN_LOG_DEFAULT_LEVEL;
    int flags = 0;

    rb_scan_args(argc, argv, "02&", &rb_logger, &rb_options, &rb_callback);

    if (rb_block_given_p()) {
        if (!NIL_P(rb_logger)) {
            rb_options = rb_logger;
        }
        rb_logger = rb_funcall(rb_cGrnCallbackLogger, id_new, 1, rb_callback);
    }

    rb_grn_scan_options(rb_options,
                        "max_level", &rb_max_level,
                        "time",      &rb_time,
                        "title",     &rb_title,
                        "message",   &rb_message,
                        "location",  &rb_location,
                        "flags",     &rb_flags,
                        NULL);
    if (!NIL_P(rb_max_level)) {
        max_level = RVAL2GRNLOGLEVEL(rb_max_level);
    }

    if (NIL_P(rb_time) || CBOOL2RVAL(rb_time)) {
        flags |= GRN_LOG_TIME;
    }
    if (NIL_P(rb_title) || CBOOL2RVAL(rb_title)) {
        flags |= GRN_LOG_TITLE;
    }
    if (NIL_P(rb_message) || CBOOL2RVAL(rb_message)) {
        flags |= GRN_LOG_MESSAGE;
    }
    if (NIL_P(rb_location) || CBOOL2RVAL(rb_location)) {
        flags |= GRN_LOG_LOCATION;
    }
    if (!NIL_P(rb_flags)) {
        flags = rb_funcall(rb_mGrnLoggerFlags, id_parse, 2,
                           INT2NUM(flags), rb_flags);
    }

    rb_grn_logger.max_level = max_level;
    rb_grn_logger.flags = flags;
    rb_grn_logger.user_data = (void *)rb_logger;

    context = rb_grn_context_ensure(&rb_context);
    grn_logger_set(context, &rb_grn_logger);
    rb_grn_context_check(context, rb_logger);
    rb_cv_set(klass, "@@current_logger", rb_logger);

    return Qnil;
}
コード例 #4
0
ファイル: rb-grn-hash.c プロジェクト: genki/rroonga
/*
 * 各レコードをキーで管理するテーブルを生成する。ブロックを指
 * 定すると、そのブロックに生成したテーブルが渡され、ブロック
 * を抜けると自動的にテーブルが破棄される。
 *
 * @example
 *   #無名一時テーブルを生成する。
 *   Groonga::Hash.create
 *
 *   #無名永続テーブルを生成する。
 *   Groonga::Hash.create(:path => "/tmp/hash.grn")
 *
 *   #名前付き永続テーブルを生成する。ただし、ファイル名は気にしない。
 *   Groonga::Hash.create(:name => "Bookmarks",
 *                        :persistent => true)
 *
 *   #それぞれのレコードに512バイトの値を格納できる無名一時テーブルを生成する。
 *   Groonga::Hash.create(:value => 512)
 *
 *   #キーとして文字列を使用する無名一時テーブルを生成する。
 *   Groonga::Hash.create(:key_type => Groonga::Type::SHORT_TEXT)
 *
 *   #キーとして文字列を使用する無名一時テーブルを生成する。
 *   (キーの種類を表すオブジェクトは文字列で指定。)
 *   Groonga::Hash.create(:key_type => "ShortText")
 *
 *   #キーとしてBookmarksテーブルのレコードを使用す
 *   る無名一時テーブルを生成する。
 *   bookmarks = Groonga::Hash.create(:name => "Bookmarks")
 *   Groonga::Hash.create(:key_type => bookmarks)
 *
 *   #キーとしてBookmarksテーブルのレコードを使用す
 *   #る無名一時テーブルを生成する。(テーブルは文字列で指定。)
 *   Groonga::Hash.create(:name => "Bookmarks")
 *   Groonga::Hash.create(:key_type => "Bookmarks")
 *
 *   #全文検索用のトークンをバイグラムで切り出す無名一時テーブ
 *   #ルを生成する。
 *   bookmarks = Groonga::Hash.create(:name => "Bookmarks")
 *   bookmarks.define_column("comment", "Text")
 *   terms = Groonga::Hash.create(:name => "Terms",
 *                                :default_tokenizer => "TokenBigram")
 *   terms.define_index_column("content", bookmarks,
 *                             :source => "Bookmarks.comment")
 *
 * @overload create(options={})
 *   @return [Groonga::Hash]
 *   @!macro hash.create.options
 *     @param [::Hash] options The name and value
 *       pairs. Omitted names are initialized as the default value
 *     @option options [Groonga::Context] :context (Groonga::Context.default)
 *       テーブルが利用する {Groonga::Context} 。省略すると
 *       {Groonga::Context.default} を用いる。
 *     @option options [Groonga::Context#[]] :name
 *       テーブルの名前。名前をつけると、 {Groonga::Context#[]} に名
 *       前を指定してテーブルを取得することができる。省略すると
 *       無名テーブルになり、テーブルIDでのみ取得できる。
 *     @option options [Groonga::Context#[]] :path
 *       テーブルを保存するパス。パスを指定すると永続テーブルとな
 *       り、プロセス終了後もレコードは保持される。次回起動時に
 *       {Groonga::Context#[]} で保存されたレコードを利用することが
 *       できる。省略すると一時テーブルになり、プロセスが終了する
 *       とレコードは破棄される。
 *     @option options :persistent
 *       +true+ を指定すると永続テーブルとなる。 +path+ を省略した
 *       場合は自動的にパスが付加される。 +:context+ で指定した
 *       {Groonga::Context} に結びついているデータベースが一時デー
 *       タベースの場合は例外が発生する。
 *
 *     @option options :key_normalize (false) Keys are normalized
 *       if this value is @true@.
 *
 *       @deprecated Use @:normalizer => "NormalizerAuto"@ instead.
 *
 *     @option options :key_type
 *       キーの種類を示すオブジェクトを指定する。キーの種類には型
 *       名("Int32"や"ShortText"など)または {Groonga::Type} または
 *       テーブル( {Groonga::Array} 、 {Groonga::Hash} 、
 *       {Groonga::PatriciaTrie} のどれか)を指定する。
 *
 *       {Groonga::Type} を指定した場合は、その型が示す範囲の値をキー
 *       として使用する。ただし、キーの最大サイズは4096バイトで
 *       あるため、 {Groonga::Type::TEXT} や {Groonga::Type::LONG_TEXT}
 *       は使用できない。
 *
 *       テーブルを指定した場合はレコードIDをキーとして使用する。
 *       指定したテーブルの {Groonga::Record} をキーとして使用するこ
 *       ともでき、その場合は自動的に {Groonga::Record} からレコード
 *       IDを取得する。
 *
 *       省略した場合はShortText型をキーとして使用する。この場合、
 *       4096バイトまで使用可能である。
 *     @option options :value_type
 *       値の型を指定する。省略すると値のための領域を確保しない。
 *       値を保存したい場合は必ず指定すること。
 *
 *       参考: {Groonga::Type.new}
 *     @option options [Groonga::IndexColumn] :default_tokenizer
 *       {Groonga::IndexColumn} で使用するトークナイザを指定する。
 *       デフォルトでは何も設定されていないので、テーブルに
 *       {Groonga::IndexColumn} を定義する場合は
 *       @"TokenBigram"@ などを指定する必要がある。
 *
 *     @option options [::Array<String, Groonga::Procedure>, nil]
 *       :token_filters (nil) The token filters to be used in the
 *       table.
 *
 *     @option options [Groonga::Record#n_sub_records] :sub_records
 *       +true+ を指定すると {#group} でグループ化したときに、
 *       {Groonga::Record#n_sub_records} でグループに含まれるレコー
 *       ドの件数を取得できる。
 *
 *     @option options [String, Groonga::Procedure, nil] :normalizer
 *       The normalizer that is used by {Groonga::IndexColumn}. You
 *       can specify this by normalizer name as String such as
 *       @"NormalizerAuto"@ or normalizer object.
 *
 *   @!macro hash.create.options
 * @overload create(options={})
 *   @yield [table]
 *   @!macro hash.create.options
 */
static VALUE
rb_grn_hash_s_create (int argc, VALUE *argv, VALUE klass)
{
    grn_ctx *context;
    grn_obj *key_type = NULL, *value_type = NULL, *table;
    const char *name = NULL, *path = NULL;
    unsigned name_size = 0;
    grn_obj_flags flags = GRN_OBJ_TABLE_HASH_KEY;
    VALUE rb_table;
    VALUE options, rb_context, rb_name, rb_path, rb_persistent;
    VALUE rb_key_normalize, rb_key_type, rb_value_type, rb_default_tokenizer;
    VALUE rb_token_filters;
    VALUE rb_sub_records;
    VALUE rb_normalizer;

    rb_scan_args(argc, argv, "01", &options);

    rb_grn_scan_options(options,
                        "context", &rb_context,
                        "name", &rb_name,
                        "path", &rb_path,
                        "persistent", &rb_persistent,
                        "key_normalize", &rb_key_normalize,
                        "key_type", &rb_key_type,
                        "value_type", &rb_value_type,
                        "default_tokenizer", &rb_default_tokenizer,
                        "token_filters", &rb_token_filters,
                        "sub_records", &rb_sub_records,
                        "normalizer", &rb_normalizer,
                        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 (RVAL2CBOOL(rb_key_normalize))
        flags |= GRN_OBJ_KEY_NORMALIZE;

    if (NIL_P(rb_key_type)) {
        key_type = grn_ctx_at(context, GRN_DB_SHORT_TEXT);
    } else {
        key_type = RVAL2GRNOBJECT(rb_key_type, &context);
    }

    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, key_type, value_type);
    if (!table)
        rb_grn_context_check(context, rb_ary_new_from_values(argc, argv));
    rb_table = GRNOBJECT2RVAL(klass, context, table, GRN_TRUE);

    if (!NIL_P(rb_default_tokenizer))
        rb_funcall(rb_table, rb_intern("default_tokenizer="), 1,
                   rb_default_tokenizer);
    if (!NIL_P(rb_token_filters))
        rb_funcall(rb_table, rb_intern("token_filters="), 1,
                   rb_token_filters);
    if (!NIL_P(rb_normalizer))
        rb_funcall(rb_table, rb_intern("normalizer="), 1,
                   rb_normalizer);

    if (rb_block_given_p())
        return rb_ensure(rb_yield, rb_table, rb_grn_object_close, rb_table);
    else
        return rb_table;
}
コード例 #5
0
ファイル: rb-grn-view.c プロジェクト: iwaim/rroonga
/* FIXME: DON'T WORK!!! */
static VALUE
rb_grn_view_sort (int argc, VALUE *argv, VALUE self)
{
    VALUE rb_result = Qnil;

#ifdef WIN32
    rb_raise(rb_eNotImpError, "grn_view_add() isn't available on Windows.");
#else
    grn_ctx *context = NULL;
    grn_obj *view;
    grn_obj *result;
    grn_table_sort_key *keys;
    int i, n_keys;
    int offset = 0, limit = -1;
    VALUE rb_keys, options;
    VALUE rb_offset, rb_limit;
    VALUE *rb_sort_keys;
    grn_table_cursor *cursor;
    VALUE exception;
    grn_obj id;

    rb_grn_table_deconstruct(SELF(self), &view, &context,
			     NULL, NULL,
			     NULL, NULL, NULL,
			     NULL);

    rb_scan_args(argc, argv, "11", &rb_keys, &options);

    if (!RVAL2CBOOL(rb_obj_is_kind_of(rb_keys, rb_cArray)))
	rb_raise(rb_eArgError, "keys should be an array of key: <%s>",
		 rb_grn_inspect(rb_keys));

    n_keys = RARRAY_LEN(rb_keys);
    rb_sort_keys = RARRAY_PTR(rb_keys);
    keys = ALLOCA_N(grn_table_sort_key, n_keys);
    for (i = 0; i < n_keys; i++) {
	VALUE rb_sort_options, rb_key, rb_resolved_key, rb_order;

	if (RVAL2CBOOL(rb_obj_is_kind_of(rb_sort_keys[i], rb_cHash))) {
	    rb_sort_options = rb_sort_keys[i];
	} else if (RVAL2CBOOL(rb_obj_is_kind_of(rb_sort_keys[i], rb_cArray))) {
	    rb_sort_options = rb_hash_new();
	    rb_hash_aset(rb_sort_options,
			 RB_GRN_INTERN("key"),
			 rb_ary_entry(rb_sort_keys[i], 0));
	    rb_hash_aset(rb_sort_options,
			 RB_GRN_INTERN("order"),
			 rb_ary_entry(rb_sort_keys[i], 1));
	} else {
	    rb_sort_options = rb_hash_new();
	    rb_hash_aset(rb_sort_options,
			 RB_GRN_INTERN("key"),
			 rb_sort_keys[i]);
	}
	rb_grn_scan_options(rb_sort_options,
			    "key", &rb_key,
			    "order", &rb_order,
			    NULL);
	if (RVAL2CBOOL(rb_obj_is_kind_of(rb_key, rb_cString))) {
	    rb_resolved_key = rb_grn_table_get_column(self, rb_key);
	} else {
	    rb_resolved_key = rb_key;
	}
	keys[i].key = RVAL2GRNOBJECT(rb_resolved_key, &context);
	if (!keys[i].key) {
	    rb_raise(rb_eGrnNoSuchColumn,
		     "no such column: <%s>: <%s>",
		     rb_grn_inspect(rb_key), rb_grn_inspect(self));
	}
	if (NIL_P(rb_order)) {
	    keys[i].flags = 0;
	} else if (rb_grn_equal_option(rb_order, "desc") ||
		   rb_grn_equal_option(rb_order, "descending")) {
	    keys[i].flags = GRN_TABLE_SORT_DESC;
	} else if (rb_grn_equal_option(rb_order, "asc") ||
		   rb_grn_equal_option(rb_order, "ascending")) {
	    keys[i].flags = GRN_TABLE_SORT_ASC;
	} else {
	    rb_raise(rb_eArgError,
		     "order should be one of "
		     "[nil, :desc, :descending, :asc, :ascending]: %s",
		     rb_grn_inspect(rb_order));
	}
    }

    rb_grn_scan_options(options,
			"offset", &rb_offset,
			"limit", &rb_limit,
			NULL);

    if (!NIL_P(rb_offset))
	offset = NUM2INT(rb_offset);
    if (!NIL_P(rb_limit))
	limit = NUM2INT(rb_limit);

    result = grn_table_create(context, NULL, 0, NULL, GRN_TABLE_VIEW,
			      NULL, NULL);
    /* use n_records that is return value from
       grn_table_sort() when rroonga user become specifying
       output table. */
    grn_table_sort(context, view, offset, limit, result, keys, n_keys);
    exception = rb_grn_context_to_exception(context, self);
    if (!NIL_P(exception)) {
        grn_obj_unlink(context, result);
        rb_exc_raise(exception);
    }

    rb_result = rb_ary_new();
    cursor = grn_table_cursor_open(context, result, NULL, 0, NULL, 0,
				   0, -1, GRN_CURSOR_ASCENDING);
    GRN_TEXT_INIT(&id, 0);
    while (grn_table_cursor_next_o(context, cursor, &id) == GRN_SUCCESS) {
	rb_ary_push(rb_result, rb_grn_view_record_new(self, &id));
    }
    GRN_OBJ_FIN(context, &id);
    grn_table_cursor_close(context, cursor);
    grn_obj_unlink(context, result);
#endif

    return rb_result;
}
コード例 #6
0
ファイル: rb-grn-column.c プロジェクト: mallowlabs/rroonga
/*
 * call-seq:
 *   column.select(options) {|record| ...} -> Groonga::Hash
 *   column.select(query, options) -> Groonga::Hash
 *   column.select(expression, options) -> Groonga::Hash
 *
 * カラムが所属するテーブルからブロックまたは文字列で指定し
 * た条件にマッチするレコードを返す。返されたテーブルには
 * +expression+という特異メソッドがあり、指定した条件を表し
 * ているGroonga::Expressionを取得できる。
 * Groonga::Expression#snippetを使うことにより、指定した条件
 * 用のスニペットを簡単に生成できる。
 *
 *   results = description_column.select do |column|
 *     column =~ "groonga"
 *   end
 *   snippet = results.expression.snippet([["<em>", "</em>"]])
 *   results.each do |record|
 *     puts "#{record['name']}の説明文の中で「groonga」が含まれる部分"
 *     snippet.execute(record["description"].each do |snippet|
 *       puts "---"
 *       puts "#{snippet}..."
 *       puts "---"
 *     end
 *   end
 *
 * 出力例
 *   Ruby/groongaの説明文の中で「groonga」が含まれる部分
 *   ---
 *   Ruby/<em>groonga</em>は<em>groonga</em>のいわゆるDB-APIの層の...
 *   ---
 *
 * _query_には「[カラム名]:[演算子][値]」という書式で条件を
 * 指定する。演算子は以下の通り。
 *
 * [なし]
 *   [カラム値] == [値]
 * [<tt>!</tt>]
 *   [カラム値] != [値]
 * [<tt><</tt>]
 *   [カラム値] < [値]
 * [<tt>></tt>]
 *   [カラム値] > [値]
 * [<tt><=</tt>]
 *   [カラム値] <= [値]
 * [<tt>>=</tt>]
 *   [カラム値] >= [値]
 * [<tt>@</tt>]
 *   [カラム値]が[値]を含んでいるかどうか
 *
 * 例:
 *   "groonga" # _column_カラムの値が"groonga"のレコードにマッチ
 *   "name:daijiro" # _column_カラムが属しているテーブルの
 *                  # "name"カラムの値が"daijiro"のレコードにマッチ
 *   "description:@groonga" # _column_カラムが属しているテーブルの
 *                          # "description"カラムが
 *                          # "groonga"を含んでいるレコードにマッチ
 *
 * _expression_には既に作成済みのGroonga::Expressionを渡す
 *
 * ブロックで条件を指定する場合は
 * Groonga::ColumnExpressionBuilderを参照。
 *
 * _options_に指定可能な値は以下の通り。
 *
 * [+:operator+]
 *   マッチしたレコードをどのように扱うか。指定可能な値は以
 *   下の通り。省略した場合はGroonga::Operator::OR。
 *
 *   [Groonga::Operator::OR]
 *     マッチしたレコードを追加。すでにレコードが追加され
 *     ている場合は何もしない。
 *   [Groonga::Operator::AND]
 *     マッチしたレコードのスコアを増加。マッチしなかった
 *     レコードを削除。
 *   [Groonga::Operator::BUT]
 *     マッチしたレコードを削除。
 *   [Groonga::Operator::ADJUST]
 *     マッチしたレコードのスコアを増加。
 *
 * [+:result+]
 *   検索結果を格納するテーブル。マッチしたレコードが追加さ
 *   れていく。省略した場合は新しくテーブルを作成して返す。
 *
 * [+:name+]
 *   条件の名前。省略した場合は名前を付けない。
 *
 * [+:syntax+]
 *   _query_の構文。省略した場合は+:query+。
 *
 *   参考: Groonga::Expression#parse.
 *
 * [+:allow_pragma+]
 *   query構文時にプラグマを利用するかどうか。省略した場合は
 *   利用する。
 *
 *   参考: Groonga::Expression#parse.
 *
 * [+:allow_column+]
 *   query構文時にカラム指定を利用するかどうか。省略した場合
 *   は利用する。
 *
 *   参考: Groonga::Expression#parse.
 *
 * [+:allow_update+]
 *   script構文時に更新操作を利用するかどうか。省略した場合
 *   は利用する。
 *
 *   参考: Groonga::Expression#parse.
 */
static VALUE
rb_grn_column_select (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context;
    grn_obj *table, *column, *result, *expression;
    grn_operator operator = GRN_OP_OR;
    VALUE options;
    VALUE rb_query, condition_or_options;
    VALUE rb_name, rb_operator, rb_result, rb_syntax;
    VALUE rb_allow_pragma, rb_allow_column, rb_allow_update;
    VALUE builder;
    VALUE rb_expression = Qnil;

    rb_query = Qnil;

    rb_scan_args(argc, argv, "02", &condition_or_options, &options);

    rb_grn_column_deconstruct(SELF(self), &column, &context,
                              NULL, NULL,
                              NULL, NULL, NULL);
    table = grn_column_table(context, column);

    if (RVAL2CBOOL(rb_obj_is_kind_of(condition_or_options, rb_cString))) {
        rb_query = condition_or_options;
    } else if (RVAL2CBOOL(rb_obj_is_kind_of(condition_or_options,
                                            rb_cGrnExpression))) {
        rb_expression = condition_or_options;
    } else {
        if (!NIL_P(options))
            rb_raise(rb_eArgError,
                     "should be [query_string, option_hash], "
                     "[expression, option_hash] "
                     "or [option_hash]: %s",
                     rb_grn_inspect(rb_ary_new4(argc, argv)));
        options = condition_or_options;
    }

    rb_grn_scan_options(options,
                        "operator", &rb_operator,
                        "result", &rb_result,
                        "name", &rb_name,
                        "syntax", &rb_syntax,
                        "allow_pragma", &rb_allow_pragma,
                        "allow_column", &rb_allow_column,
                        "allow_update", &rb_allow_update,
                        NULL);

    if (!NIL_P(rb_operator))
        operator = NUM2INT(rb_operator);

    if (NIL_P(rb_result)) {
        result = grn_table_create(context, NULL, 0, NULL,
                                  GRN_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
                                  table,
                                  0);
        rb_result = GRNTABLE2RVAL(context, result, GRN_TRUE);
    } else {
        result = RVAL2GRNTABLE(rb_result, &context);
    }

    if (NIL_P(rb_expression)) {
        builder = rb_grn_column_expression_builder_new(self, rb_name, rb_query);
        rb_funcall(builder, rb_intern("syntax="), 1, rb_syntax);
        rb_funcall(builder, rb_intern("allow_pragma="), 1, rb_allow_pragma);
        rb_funcall(builder, rb_intern("allow_column="), 1, rb_allow_column);
        rb_funcall(builder, rb_intern("allow_update="), 1, rb_allow_update);
        rb_expression = rb_grn_column_expression_builder_build(builder);
    }
    rb_grn_object_deconstruct(RB_GRN_OBJECT(DATA_PTR(rb_expression)),
                              &expression, NULL,
                              NULL, NULL, NULL, NULL);

    grn_table_select(context, table, expression, result, operator);
    rb_grn_context_check(context, self);

    rb_attr(rb_singleton_class(rb_result),
            rb_intern("expression"),
            GRN_TRUE, GRN_FALSE, GRN_FALSE);
    rb_iv_set(rb_result, "@expression", rb_expression);

    return rb_result;
}
コード例 #7
0
ファイル: rb-grn-expression.c プロジェクト: ohai/rroonga
/*
 * _expression_ から {Groonga::Snippet} を生成する。 _tags_ には
 * キーワードの前後に挿入するタグの配列を以下のような形式で指定
 * する。
 *
 * <pre>
 * !!!ruby
 *   [
 *    ["キーワード前に挿入する文字列1", "キーワード後に挿入する文字列1"],
 *    ["キーワード前に挿入する文字列2", "キーワード後に挿入する文字列2"],
 *    # ...,
 *   ]
 * </pre>
 *
 * もし、1つのスニペットの中に _tags_ で指定したタグより多くの
 * キーワードが含まれている場合は、以下のように、また、先頭
 * のタグから順番に使われる。
 *
 * <pre>
 * !!!ruby
 *   expression.parse("Ruby groonga 検索")
 *   tags = [["<tag1>", "</tag1>"], ["<tag2>", "</tag2>"]]
 *   snippet = expression.snippet(tags)
 *   p snippet.execute("Rubyでgroonga使って全文検索、高速検索。")
 *      # => ["<tag1>Ruby</tag1>で<tag2>groonga</tag2>"
 *      # =>  "使って全文<tag1>検索</tag1>、高速<tag2>検索</tag2>。"]
 * </pre>
 *
 * @overload snippet(tags, options)
 *   @param tags [Array<string>] キーワードの前後に挿入するタグの配列
 *     (詳細は上記を参照)
 *   @param options [::Hash] The name and value
 *     pairs. Omitted names are initialized as the default value.
 *   @option options :normalize (false)
 *     キーワード文字列・スニペット元の文字列を正規化するかど
 *     うか。省略した場合は +false+ で正規化しない。
 *   @option options :skip_leading_spaces (false)
 *     先頭の空白を無視するかどうか。省略した場合は +false+ で無
 *     視しない。
 *   @option options :width (100)
 *     スニペット文字列の長さ。省略した場合は100文字。
 *   @option options :max_results (3)
 *     生成するスニペットの最大数。省略した場合は3。
 *   @option options :html_escape (false)
 *     スニペット内の +<+, +>+, +&+, +"+ をHTMLエスケープするか
 *     どうか。省略した場合は +false+ で、HTMLエスケープしない。
 * @return [Groonga::Snippet]
 */
static VALUE
rb_grn_expression_snippet (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context = NULL;
    grn_obj *expression;
    grn_obj *snippet;
    VALUE options;
    VALUE rb_normalize, rb_skip_leading_spaces;
    VALUE rb_width, rb_max_results, rb_tags;
    VALUE rb_html_escape;
    VALUE *rb_tag_values;
    VALUE related_object;
    unsigned int i;
    int flags = GRN_SNIP_COPY_TAG;
    unsigned int width = 100;
    unsigned int max_results = 3;
    unsigned int n_tags = 0;
    char **open_tags = NULL;
    unsigned int *open_tag_lengths = NULL;
    char **close_tags = NULL;
    unsigned int *close_tag_lengths = NULL;
    grn_snip_mapping *mapping = NULL;

    rb_grn_expression_deconstruct(SELF(self), &expression, &context,
                                  NULL, NULL,
                                  NULL, NULL, NULL);

    rb_scan_args(argc, argv, "11", &rb_tags, &options);

    rb_grn_scan_options(options,
                        "normalize", &rb_normalize,
                        "skip_leading_spaces", &rb_skip_leading_spaces,
                        "width", &rb_width,
                        "max_results", &rb_max_results,
                        "html_escape", &rb_html_escape,
                        NULL);

    if (TYPE(rb_tags) != T_ARRAY) {
        rb_raise(rb_eArgError,
                 "tags should be "
                 "[\"open_tag\", \"close_tag\"] or "
                 "[[\"open_tag1\", \"close_tag1\"], ...]: %s",
                 rb_grn_inspect(rb_tags));
    }

    if (TYPE(RARRAY_PTR(rb_tags)[0]) == T_STRING) {
        rb_tags = rb_ary_new3(1, rb_tags);
    }

    rb_tag_values = RARRAY_PTR(rb_tags);
    n_tags = RARRAY_LEN(rb_tags);
    open_tags = ALLOCA_N(char *, n_tags);
    open_tag_lengths = ALLOCA_N(unsigned int, n_tags);
    close_tags = ALLOCA_N(char *, n_tags);
    close_tag_lengths = ALLOCA_N(unsigned int, n_tags);
    for (i = 0; i < n_tags; i++) {
        VALUE *tag_pair;

        if (TYPE(rb_tag_values[i]) != T_ARRAY ||
            RARRAY_LEN(rb_tag_values[i]) != 2) {
            rb_raise(rb_eArgError,
                     "tags should be "
                     "[\"open_tag\", \"close_tag\"] or"
                     "[[\"open_tag1\", \"close_tag1\"], ...]: %s",
                     rb_grn_inspect(rb_tags));
        }
        tag_pair = RARRAY_PTR(rb_tag_values[i]);
        open_tags[i] = StringValuePtr(tag_pair[0]);
        open_tag_lengths[i] = RSTRING_LEN(tag_pair[0]);
        close_tags[i] = StringValuePtr(tag_pair[1]);
        close_tag_lengths[i] = RSTRING_LEN(tag_pair[1]);
    }

    if (RVAL2CBOOL(rb_normalize))
        flags |= GRN_SNIP_NORMALIZE;
    if (RVAL2CBOOL(rb_skip_leading_spaces))
        flags |= GRN_SNIP_SKIP_LEADING_SPACES;

    if (!NIL_P(rb_width))
        width = NUM2UINT(rb_width);

    if (!NIL_P(rb_max_results))
        max_results = NUM2UINT(rb_max_results);

    if (RVAL2CBOOL(rb_html_escape))
        mapping = (grn_snip_mapping *)-1;

    snippet = grn_expr_snip(context, expression, flags, width, max_results,
                            n_tags,
                            (const char **)open_tags, open_tag_lengths,
                            (const char **)close_tags, close_tag_lengths,
                            mapping);
    related_object = rb_ary_new3(2, self, rb_ary_new4(argc, argv));
    rb_grn_context_check(context, related_object);

    return GRNOBJECT2RVAL(Qnil, context, snippet, GRN_TRUE);
}
コード例 #8
0
ファイル: rb-grn-expression.c プロジェクト: ohai/rroonga
/*
 * 文字列 _query_ をパースする。
 * @overload parse(query, options={})
 *   @param [String] query パースする文字列
 *   @param [::Hash] options The name and value
 *     pairs. Omitted names are initialized as the default value.
 *   @option options :default_column
 *     "column_name:hoge"ではなく"hoge"のようにcolumn_nameが指
 *     定されない条件の検索対象となるカラムを指定する。
 *   @option options :default_operator (Groonga::Operator::AND)
 *     "+"や"OR"で繋がれず、ただ列挙された複数の条件があった時、
 *     _expression_ 全体として各レコードをヒットとみなすかの論理
 *     条件を指定する。省略した場合はGroonga::Operator::AND。
 *
 *     - Groonga::Operator::OR :=
 *       レコードはいずれかの条件にマッチすればいい。 =:
 *     - Groonga::Operator::AND :=
 *       レコードは全ての条件にマッチしなければならない。 =:
 *     - Groonga::Operator::AND_NOT :=
 *       最初の条件にレコードはマッチし、残りの条件にレコードは
 *       マッチしてはならない。 =:
 *
 *   @option options :default_mode (Groonga::Operator::MATCH)
 *     検索時のモードを指定する。省略した場合はGroonga::Operator::MATCH。
 *     (FIXME: モードによってどういう動作になるかを書く。)
 *   @option options :syntax (:query)
 *     _query_ の構文を指定する。指定可能な値は以下の通り。省略
 *     した場合は +:query+ 。
 *
 *     - +:query+ :=
 *       「文字列1 OR 文字列2」で「"文字列1"あるいは"文字列2"
 *       にマッチという検索エンジンで利用できるような構文を使
 *       う。
 *       参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html =:
 *     - +nil+ :=
 *       +:query+と同様 =:
 *     - +:script+ :=
 *       「[カラム名] == [値]」というようにECMAScript風の構文を使う。
 *       参考: "Groongaのscript構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/script_syntax.html =:
 *   @option options :allow_pragma
 *     _query_ の構文に query を用いているとき( +:syntax+
 *     オプション参照)、「*E-1」というようにクエリの先頭で
 *     pragmaを利用できるようにする。script構文を用いている
 *     ときはこのオプションを利用できない。
 *
 *     デフォルトではプラグマを利用できる。
 *
 *     参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html
 *   @option options :allow_column
 *     _query_ の構文にqueryを用いているとき( +:syntax+ オプショ
 *     ン参照)、「カラム名:値」というようにカラム名を指定した
 *     条件式を利用できるようにする。script構文を用いていると
 *     きはこのオプションを利用できない。
 *
 *     デフォルトではカラム名を指定した条件式を利用できる。
 *
 *     参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html
 *   @option options :allow_update
 *     _query_ の構文にscriptを用いているとき( +:syntax+ オプショ
 *     ン参照)、「カラム名 = 値」というように更新操作を利用で
 *     きるようにする。query構文を用いているときはこのオプショ
 *     ンを利用できない。
 *
 *     デフォルトでは更新操作を利用できる。
 *
 *     参考: "Groongaのクエリ構文のドキュメント":http://groonga.org/ja/docs/reference/grn_expr/query_syntax.html
 */
static VALUE
rb_grn_expression_parse (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context = NULL;
    grn_obj *expression, *default_column;
    grn_bool default_column_is_created = GRN_FALSE;
    grn_operator default_operator = GRN_OP_AND;
    grn_operator default_mode = GRN_OP_MATCH;
    grn_rc rc;
    char *query = NULL;
    unsigned query_size = 0;
    grn_expr_flags flags = 0;
    VALUE options, rb_query, rb_default_column, rb_default_operator;
    VALUE rb_default_mode, rb_syntax;
    VALUE rb_allow_pragma, rb_allow_column, rb_allow_update, rb_allow_leading_not;
    VALUE exception = Qnil;

    rb_scan_args(argc, argv, "11", &rb_query, &options);
    rb_grn_scan_options(options,
                        "default_column", &rb_default_column,
                        "default_operator", &rb_default_operator,
                        "default_mode", &rb_default_mode,
                        "syntax", &rb_syntax,
                        "allow_pragma", &rb_allow_pragma,
                        "allow_column", &rb_allow_column,
                        "allow_update", &rb_allow_update,
                        "allow_leading_not", &rb_allow_leading_not,
                        NULL);

    query = StringValuePtr(rb_query);
    query_size = RSTRING_LEN(rb_query);

    rb_grn_expression_deconstruct(SELF(self), &expression, &context,
                                  NULL, NULL,
                                  NULL, NULL, NULL);

    if (NIL_P(rb_default_column)) {
        default_column = NULL;
    } else if (RVAL2CBOOL(rb_obj_is_kind_of(rb_default_column, rb_cGrnObject))) {
        default_column = RVAL2GRNOBJECT(rb_default_column, &context);
    } else {
        default_column = RVAL2GRNBULK(rb_default_column, context, NULL);
        default_column_is_created = GRN_TRUE;
    }

    if (!NIL_P(rb_default_mode))
        default_mode = RVAL2GRNOPERATOR(rb_default_mode);
    if (!NIL_P(rb_default_operator))
        default_operator = RVAL2GRNSETOPERATOR(rb_default_operator);

    if (NIL_P(rb_syntax) ||
        rb_grn_equal_option(rb_syntax, "query")) {
        flags = GRN_EXPR_SYNTAX_QUERY;
    } else if (rb_grn_equal_option(rb_syntax, "script")) {
        flags = GRN_EXPR_SYNTAX_SCRIPT;
    } else {
        rb_raise(rb_eArgError,
                 "syntax should be one of "
                 "[nil, :query, :script]: %s",
                 rb_grn_inspect(rb_syntax));
    }

    if (NIL_P(rb_allow_pragma)) {
        if (!(flags & GRN_EXPR_SYNTAX_SCRIPT))
            flags |= GRN_EXPR_ALLOW_PRAGMA;
    } else {
        if ((flags & GRN_EXPR_SYNTAX_SCRIPT))
            rb_raise(rb_eArgError,
                     ":allow_pragma isn't allowed in script syntax");
        if (RVAL2CBOOL(rb_allow_pragma))
            flags |= GRN_EXPR_ALLOW_PRAGMA;
    }

    if (NIL_P(rb_allow_column)) {
        if (!(flags & GRN_EXPR_SYNTAX_SCRIPT))
            flags |= GRN_EXPR_ALLOW_COLUMN;
    } else {
        if ((flags & GRN_EXPR_SYNTAX_SCRIPT))
            rb_raise(rb_eArgError,
                     ":allow_column isn't allowed in script syntax");
        if (RVAL2CBOOL(rb_allow_column))
            flags |= GRN_EXPR_ALLOW_COLUMN;
    }

    if (NIL_P(rb_allow_update)) {
        flags |= GRN_EXPR_ALLOW_UPDATE;
    } else {
        if (RVAL2CBOOL(rb_allow_update))
            flags |= GRN_EXPR_ALLOW_UPDATE;
    }

    if (!NIL_P(rb_allow_leading_not)) {
        if (RVAL2CBOOL(rb_allow_leading_not))
            flags |= GRN_EXPR_ALLOW_LEADING_NOT;
    }

    rc = grn_expr_parse(context, expression, query, query_size,
                        default_column, default_mode, default_operator,
                        flags);
    if (rc != GRN_SUCCESS) {
        VALUE related_object;

        related_object = rb_ary_new3(2, self, rb_ary_new4(argc, argv));
        exception = rb_grn_context_to_exception(context, related_object);
    }
    if (default_column_is_created)
        grn_obj_unlink(context, default_column);

    if (!NIL_P(exception))
        rb_exc_raise(exception);

    return Qnil;
}
コード例 #9
0
/*
 * It updates a value of variable size column value for the record
 * that ID is _id_.
 *
 * Weight vector column is a special variable size column. This
 * description describes only weight vector column. Other variable
 * size column works what you think.
 *
 * @example Use weight vector as matrix search result weight
 *    Groonga::Schema.define do |schema|
 *      schema.create_table("Products",
 *                          :type => :patricia_trie,
 *                          :key_type => "ShortText") do |table|
 *        # This is weight vector.
 *        # ":with_weight => true" is important for matrix search result weight.
 *        table.short_text("tags",
 *                         :type => :vector,
 *                         :with_weight => true)
 *      end
 *
 *      schema.create_table("Tags",
 *                          :type => :hash,
 *                          :key_type => "ShortText") do |table|
 *        # This is inverted index. It also needs ":with_weight => true".
 *        table.index("Products.tags", :with_weight => true)
 *      end
 *    end
 *
 *    products = Groonga["Products"]
 *    groonga = products.add("Groonga")
 *    groonga.tags = [
 *      {
 *        :value  => "groonga",
 *        :weight => 100,
 *      },
 *    ]
 *    rroonga = products.add("Rroonga")
 *    rroonga.tags = [
 *      {
 *        :value  => "ruby",
 *        :weight => 100,
 *      },
 *      {
 *        :value  => "groonga",
 *        :weight => 10,
 *      },
 *    ]
 *
 *    result = products.select do |record|
 *      # Search by "groonga"
 *      record.match("groonga") do |match_target|
 *        match_target.tags
 *      end
 *    end
 *
 *    result.each do |record|
 *      p [record.key.key, record.score]
 *    end
 *    # Matches all records with weight.
 *    # => ["Groonga", 101]
 *    #    ["Rroonga", 11]
 *
 *    # Increases score for "ruby" 10 times
 *    products.select(# The previous search result. Required.
 *                    :result => result,
 *                    # It just adds score to existing records in the result. Required.
 *                    :operator => Groonga::Operator::ADJUST) do |record|
 *      record.match("ruby") do |target|
 *        target.tags * 10 # 10 times
 *      end
 *    end
 *
 *    result.each do |record|
 *      p [record.key.key, record.score]
 *    end
 *    # Weight is used for increasing score.
 *    # => ["Groonga", 101]  <- Not changed.
 *    #    ["Rroonga", 1021] <- 1021 (= 101 * 10 + 1) increased.
 *
 * @overload []=(id, elements)
 *   This description is for weight vector column.
 *
 *   @param [Integer, Record] id The record ID.
 *   @param [Array<Hash<Symbol, String>>] elements An array of values
 *     for weight vector.
 *     Each value is a Hash like the following form:
 *
 *     <pre>
 *     {
 *       :value  => [KEY],
 *       :weight => [WEIGHT],
 *     }
 *     </pre>
 *
 *     @[KEY]@ must be the same type of the key of the table that is
 *     specified as range on creating the weight vector.
 *
 *     @[WEIGHT]@ must be an positive integer. Note that search
 *     becomes @weight + 1@. It means that You want to get 10 as
 *     score, you should set 9 as weight.
 *
 * @overload []=(id, value)
 *   This description is for variable size columns except weight
 *   vector column.
 *
 *   @param [Integer, Record] id The record ID.
 *   @param [::Object] value A new value.
 *   @see Groonga::Object#[]=
 *
 * @since 4.0.1
 */
static VALUE
rb_grn_variable_size_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;
    grn_obj *value, *element_value;
    int flags = GRN_OBJ_SET;

    rb_grn_variable_size_column_deconstruct(SELF(self), &column, &context,
                                            NULL, NULL, &value, &element_value,
                                            NULL, &range);

    if (!(column->header.flags & GRN_OBJ_WITH_WEIGHT)) {
        VALUE args[2];
        args[0] = rb_id;
        args[1] = rb_value;
        return rb_call_super(2, args);
    }

    id = RVAL2GRNID(rb_id, context, range, self);

    grn_obj_reinit(context, value,
                   value->header.domain,
                   value->header.flags | GRN_OBJ_VECTOR);
    value->header.flags |= GRN_OBJ_WITH_WEIGHT;
    if (RVAL2CBOOL(rb_obj_is_kind_of(rb_value, rb_cArray))) {
        int i, n;
        n = RARRAY_LEN(rb_value);
        for (i = 0; i < n; i++) {
            unsigned int weight = 0;
            VALUE rb_element_value, rb_weight;

            rb_grn_scan_options(RARRAY_PTR(rb_value)[i],
                                "value", &rb_element_value,
                                "weight", &rb_weight,
                                NULL);

            if (!NIL_P(rb_weight)) {
                weight = NUM2UINT(rb_weight);
            }

            if (value->header.type == GRN_UVECTOR) {
                grn_id id = RVAL2GRNID(rb_element_value, context, range, self);
                grn_uvector_add_element(context, value, id, weight);
            } else {
                GRN_BULK_REWIND(element_value);
                if (!NIL_P(rb_element_value)) {
                    RVAL2GRNBULK(rb_element_value, context, element_value);
                }

                grn_vector_add_element(context, value,
                                       GRN_BULK_HEAD(element_value),
                                       GRN_BULK_VSIZE(element_value),
                                       weight,
                                       element_value->header.domain);
            }
        }
    } else if (RVAL2CBOOL(rb_obj_is_kind_of(rb_value, rb_cHash))) {
        HashElementToVectorElementData data;
        data.self = self;
        data.context = context;
        data.vector = value;
        data.element_value = element_value;
        data.range = range;
        rb_hash_foreach(rb_value, hash_element_to_vector_element, (VALUE)&data);
    } else {
        rb_raise(rb_eArgError,
                 "<%s>: "
                 "weight vector value must be an array of index value or "
                 "a hash that key is vector value and value is vector weight: "
                 "<%s>",
                 rb_grn_inspect(self),
                 rb_grn_inspect(rb_value));
    }

    rc = grn_obj_set_value(context, column, id, value, flags);
    rb_grn_context_check(context, self);
    rb_grn_rc_check(rc, self);

    return rb_value;
}
コード例 #10
0
static grn_table_cursor *
rb_grn_patricia_trie_open_grn_prefix_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;
    VALUE options, rb_prefix, rb_key_bytes, rb_key_bits;
    VALUE rb_order, rb_order_by;
    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,
			"order", &rb_order,
			"order_by", &rb_order_by,
			"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 (NIL_P(rb_order)) {
    } else if (rb_grn_equal_option(rb_order, "asc") ||
	       rb_grn_equal_option(rb_order, "ascending")) {
	flags |= GRN_CURSOR_ASCENDING;
    } else if (rb_grn_equal_option(rb_order, "desc") ||
	       rb_grn_equal_option(rb_order, "descending")) {
	flags |= GRN_CURSOR_DESCENDING;
    } else {
	rb_raise(rb_eArgError,
		 "order should be one of "
		 "[:asc, :ascending, :desc, :descending]: %s",
		 rb_grn_inspect(rb_order));
    }
    if (NIL_P(rb_order_by)) {
    } else if (rb_grn_equal_option(rb_order_by, "id")) {
	flags |= GRN_CURSOR_BY_ID;
    } else if (rb_grn_equal_option(rb_order_by, "key")) {
	if (table->header.type != GRN_TABLE_PAT_KEY) {
	    rb_raise(rb_eArgError,
		     "order_by => :key is available "
		     "only for Groonga::PatriciaTrie: %s",
		     rb_grn_inspect(self));
	}
	flags |= GRN_CURSOR_BY_KEY;
    } else {
	rb_raise(rb_eArgError,
		 "order_by should be one of [:id%s]: %s",
		 table->header.type == GRN_TABLE_PAT_KEY ? ", :key" : "",
		 rb_grn_inspect(rb_order_by));
    }

    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;
}