/* * _constant_ を追加し、 _n_arguments_ 個の引数を取る _operation_ を追加する。 * * @overload append_constant(constant, operation=Groonga::Operator::PUSH, n_arguments=1) * @param [Object] constant 追加する _constant_ * @param [Groonga::Operator::XXX] operation 追加する _operation_ * @param [Integer] n_arguments _operation_ の取る引数 * @return [Self] self */ static VALUE rb_grn_expression_append_constant (int argc, VALUE *argv, VALUE self) { VALUE rb_constant, rb_operator, rb_n_arguments; VALUE exception; grn_ctx *context = NULL; grn_obj *expression, *constant = NULL; grn_operator operator = GRN_OP_PUSH; int n_arguments = 1; rb_scan_args(argc, argv, "12", &rb_constant, &rb_operator, &rb_n_arguments); if (!NIL_P(rb_operator)) operator = RVAL2GRNOPERATOR(rb_operator); 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); RVAL2GRNOBJ(rb_constant, context, &constant); grn_expr_append_const(context, expression, constant, operator, n_arguments); exception = rb_grn_context_to_exception(context, self); grn_obj_unlink(context, constant); if (!NIL_P(exception)) rb_exc_raise(exception); return self; }
/* * _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; }
/* * 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; }
/* * _key_ にマッチするレコードのIDがキーに入っている * {Groonga::Hash} を返す。マッチするレコードがない場合は空の * {fGroonga::Hash} が返る。 * _options_ で +:result+ を指定することにより、そのテーブルにマッ * チしたレコードIDがキーのレコードを追加することができる。 * +:result+ にテーブルを指定した場合は、そのテーブルが返る。 * * @example 複数のキーで検索し、結果を1つのテーブルに集める。 * result = nil * keys = ["morita", "gunyara-kun", "yu"] * keys.each do |key| * result = users.search(key, :result => result) * end * result.each do |record| * user = record.key * p user.key # -> "morita"または"gunyara-kun"または"yu" * end * * @overload search(key, options=nil) * @return [Groonga::Hash] * @param key [String] レコードにマッチさせる値 * @param options [::Hash] The name and value * pairs. Omitted names are initialized as the default value. * @option options :result The result * 結果を格納するテーブル。 * @option options :operator (Groonga::Operator::OR) * マッチしたレコードをどのように扱うか。指定可能な値は以 * 下の通り。 * * - Groonga::Operator::OR := * マッチしたレコードを追加。すでにレコードが追加され * ている場合は何もしない。 =: * - Groonga::Operator::AND := * マッチしたレコードのスコアを増加。マッチしなかった * レコードを削除。 =: * - Groonga::Operator::AND_NOT := * マッチしたレコードを削除。 =: * - Groonga::Operator::ADJUST := * マッチしたレコードのスコアを増加。 =: * - +:type+ := * ????? =: * */ static VALUE rb_grn_double_array_trie_search (int argc, VALUE *argv, VALUE self) { grn_rc rc; grn_ctx *context; grn_obj *table; grn_id domain_id; grn_obj *key, *domain, *result; grn_operator operator; grn_search_optarg search_options; grn_bool search_options_is_set = GRN_FALSE; VALUE rb_key, options, rb_result, rb_operator, rb_type; rb_grn_double_array_trie_deconstruct(SELF(self), &table, &context, &key, NULL, &domain_id, &domain, NULL, NULL, NULL, NULL); rb_scan_args(argc, argv, "11", &rb_key, &options); RVAL2GRNKEY(rb_key, context, key, domain_id, domain, self); rb_grn_scan_options(options, "result", &rb_result, "operator", &rb_operator, "type", &rb_type, NULL); if (NIL_P(rb_result)) { result = grn_table_create(context, NULL, 0, NULL, GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC, table, 0); rb_grn_context_check(context, self); rb_result = GRNOBJECT2RVAL(Qnil, context, result, GRN_TRUE); } else { result = RVAL2GRNOBJECT(rb_result, &context); } operator = RVAL2GRNOPERATOR(rb_operator); rc = grn_obj_search(context, table, key, result, operator, search_options_is_set ? &search_options : NULL); rb_grn_rc_check(rc, self); return rb_result; }
/* * _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); if (RB_TYPE_P(rb_object, RUBY_T_HASH)) { RbGrnHashFromRubyHashData data; data.context = context; data.hash = grn_hash_create(context, NULL, GRN_TABLE_MAX_KEY_SIZE, sizeof(grn_obj), GRN_OBJ_KEY_VAR_SIZE | GRN_OBJ_TEMPORARY | GRN_HASH_TINY); grn_expr_take_obj(context, expression, (grn_obj *)(data.hash)); data.rb_hash = rb_object; rb_hash_foreach(rb_object, rb_grn_hash_from_ruby_hash_body, (VALUE)&data); grn_expr_append_obj(context, expression, (grn_obj *)(data.hash), operation, n_arguments); } else { 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; }
/* * _n_arguments_ 個の引数を取る _operation_ を追加する。 * * @overload append_operation(operation, n_arguments) */ static VALUE rb_grn_expression_append_operation (VALUE self, VALUE rb_operation, VALUE rb_n_arguments) { grn_ctx *context = NULL; grn_obj *expression; grn_operator operation; int n_arguments = 0; rb_grn_expression_deconstruct(SELF(self), &expression, &context, NULL, NULL, NULL, NULL, NULL); operation = RVAL2GRNOPERATOR(rb_operation); n_arguments = NUM2INT(rb_n_arguments); grn_expr_append_op(context, expression, operation, n_arguments); rb_grn_context_check(context, self); return Qnil; }
/* * Document-method: indexes * * call-seq: * column.indexes(operator=Groonga::Operator::MATCH) -> [index_column, ...] * * _operation_ を実行できる _column_ のインデックスを返す。 * * @since 1.0.9 */ static VALUE rb_grn_column_get_indexes (int argc, VALUE *argv, VALUE self) { grn_ctx *context; grn_obj *column; grn_obj **indexes = NULL; int i, n_indexes; grn_operator operator = GRN_OP_MATCH; VALUE rb_operator, rb_indexes; rb_scan_args(argc, argv, "01", &rb_operator); rb_grn_column_deconstruct(SELF(self), &column, &context, NULL, NULL, NULL, NULL, NULL); if (!NIL_P(rb_operator)) { operator = RVAL2GRNOPERATOR(rb_operator); } rb_indexes = rb_ary_new(); n_indexes = grn_column_index(context, column, operator, NULL, 0, NULL); if (n_indexes == 0) return rb_indexes; indexes = xmalloc(sizeof(grn_obj *) * n_indexes); n_indexes = grn_column_index(context, column, operator, indexes, n_indexes, NULL); for (i = 0; i < n_indexes; i++) { VALUE rb_index; rb_index = GRNOBJECT2RVAL(Qnil, context, indexes[i], GRN_FALSE); rb_ary_push(rb_indexes, rb_index); grn_obj_unlink(context, indexes[i]); } xfree(indexes); return rb_indexes; }
/* * 文字列 _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_new_from_args(2, self, rb_ary_new_from_values(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; }