Kouhei Sutou
null+****@clear*****
Sun Nov 16 19:33:45 JST 2014
Kouhei Sutou 2014-11-16 19:33:45 +0900 (Sun, 16 Nov 2014) New Revision: da7a5b92d4a528bc4a03620370c621fa7c7767f8 https://github.com/groonga/groonga/commit/da7a5b92d4a528bc4a03620370c621fa7c7767f8 Message: select: support multiple drilldowns It's experimental feature. Here is the syntax: select \ --drilldown[LABEL1].keys '...' \ --drilldown[LABEL1].sortby '...' \ --drilldown[LABEL1].output_columns '...' \ --drilldown[LABEL1].offset '...' \ --drilldown[LABEL1].limit '...' \ --drilldown[LABEL2].keys '...' \ --drilldown[LABEL2].sortby '...' \ --drilldown[LABEL2].output_columns '...' \ --drilldown[LABEL2].offset '...' \ --drilldown[LABEL2].limit '...' \ ... Return format: [ GENERAL_HEADER, [ [N_HITS] COLUMNS, RECORD1, RECORD2, ... ], { "LABEL1": [ [N_HITS], COLUMNS, RECORD1, RECORD2, ... ], "LABEL2": [ [N_HITS], COLUMNS, RECORD1, RECORD2, ... ], ... } ] The new syntax supports multiple drilldown keys. --drilldown[LABEL1].keys COLUMN1,COLUMN2 drilldowns by combination of COLUMN1 and COLUMN2. You can't get each value by the default output columns: --drilldown[LABEL1].output_columns _key,_nsubrecs Because _key is a ShortText value created by combining COLUMN1 and COLUMN2 values. You need to use the following output columns to get COLUMN1 and COLUMN2 values because you can access the first drilldowned sub record by _value: --drilldown[LABEL1].output_columns _value.COLUMN1,_value.COLUMN2,_nsubrecs TODO: * Document me. Added files: test/command/suite/select/drilldown/labeled/keys/multiple.expected test/command/suite/select/drilldown/labeled/keys/multiple.test test/command/suite/select/drilldown/labeled/keys/one.expected test/command/suite/select/drilldown/labeled/keys/one.test Modified files: lib/proc.c Modified: lib/proc.c (+322 -45) =================================================================== --- lib/proc.c 2014-11-16 19:31:03 +0900 (2eef3e3) +++ lib/proc.c 2014-11-16 19:33:45 +0900 (ac1b547) @@ -539,6 +539,71 @@ grn_select_apply_adjuster(grn_ctx *ctx, grn_obj *table, grn_obj *res, } } +typedef struct { + const char *label; + unsigned int label_len; + const char *keys; + unsigned int keys_len; + const char *sortby; + unsigned int sortby_len; + const char *output_columns; + unsigned int output_columns_len; + int offset; + int limit; +} drilldown_info; + +static void +drilldown_info_fill(grn_ctx *ctx, + drilldown_info *drilldown, + grn_obj *keys, + grn_obj *sortby, + grn_obj *output_columns, + grn_obj *offset, + grn_obj *limit) +{ + if (keys) { + drilldown->keys = GRN_TEXT_VALUE(keys); + drilldown->keys_len = GRN_TEXT_LEN(keys); + } else { + drilldown->keys = NULL; + drilldown->keys_len = 0; + } + + if (sortby) { + drilldown->sortby = GRN_TEXT_VALUE(sortby); + drilldown->sortby_len = GRN_TEXT_LEN(sortby); + } else { + drilldown->sortby = NULL; + drilldown->sortby_len = 0; + } + + if (output_columns) { + drilldown->output_columns = GRN_TEXT_VALUE(output_columns); + drilldown->output_columns_len = GRN_TEXT_LEN(output_columns); + } else { + drilldown->output_columns = NULL; + drilldown->output_columns_len = 0; + } + if (!drilldown->output_columns_len) { + drilldown->output_columns = DEFAULT_DRILLDOWN_OUTPUT_COLUMNS; + drilldown->output_columns_len = strlen(DEFAULT_DRILLDOWN_OUTPUT_COLUMNS); + } + + if (offset && GRN_TEXT_LEN(offset)) { + drilldown->offset = + grn_atoi(GRN_TEXT_VALUE(offset), GRN_BULK_CURR(offset), NULL); + } else { + drilldown->offset = 0; + } + + if (limit && GRN_TEXT_LEN(limit)) { + drilldown->limit = + grn_atoi(GRN_TEXT_VALUE(limit), GRN_BULK_CURR(limit), NULL); + } else { + drilldown->limit = DEFAULT_DRILLDOWN_LIMIT; + } +} + static void grn_select_drilldown(grn_ctx *ctx, grn_obj *table, grn_table_sort_key *keys, uint32_t n_keys, @@ -609,6 +674,110 @@ grn_select_drilldown(grn_ctx *ctx, grn_obj *table, } } +static void +grn_select_drilldowns(grn_ctx *ctx, grn_obj *table, + drilldown_info *drilldowns, unsigned int n_drilldowns) +{ + unsigned int i; + + /* TODO: Remove invalid key drilldowns from the count. */ + GRN_OUTPUT_MAP_OPEN("DRILLDOWNS", n_drilldowns); + for (i = 0; i < n_drilldowns; i++) { + drilldown_info *drilldown = &(drilldowns[i]); + grn_table_sort_key *keys = NULL; + unsigned int n_keys; + uint32_t n_hits; + int offset; + int limit; + grn_table_group_result result = { + NULL, 0, 0, 1, GRN_TABLE_GROUP_CALC_COUNT, 0 + }; + + keys = grn_table_sort_key_from_str(ctx, + drilldown->keys, + drilldown->keys_len, + table, &n_keys); + if (!keys) { + continue; + } + + if (n_keys == 1) { + result.table = grn_table_create_for_group(ctx, NULL, 0, NULL, + keys[0].key, table, 0); + } else { + result.table = grn_table_create_for_group(ctx, NULL, 0, NULL, + NULL, table, 1); + } + + if (!result.table) { + grn_table_sort_key_close(ctx, keys, n_keys); + continue; + } + + GRN_OUTPUT_STR(drilldown->label, drilldown->label_len); + + result.key_begin = 0; + result.key_end = n_keys; + grn_table_group(ctx, table, keys, n_keys, &result, 1); + n_hits = grn_table_size(ctx, result.table); + + offset = drilldown->offset; + limit = drilldown->limit; + grn_normalize_offset_and_limit(ctx, n_hits, &offset, &limit); + + if (drilldown->sortby_len) { + grn_table_sort_key *sort_keys; + uint32_t n_sort_keys; + sort_keys = grn_table_sort_key_from_str(ctx, + drilldown->sortby, + drilldown->sortby_len, + result.table, &n_sort_keys); + if (sort_keys) { + grn_obj *sorted; + sorted = grn_table_create(ctx, NULL, 0, NULL, GRN_OBJ_TABLE_NO_KEY, + NULL, result.table); + if (sorted) { + grn_obj_format format; + grn_table_sort(ctx, result.table, offset, limit, + sorted, sort_keys, n_sort_keys); + GRN_OBJ_FORMAT_INIT(&format, n_hits, 0, limit, offset); + format.flags = + GRN_OBJ_FORMAT_WITH_COLUMN_NAMES| + GRN_OBJ_FORMAT_XML_ELEMENT_NAVIGATIONENTRY; + grn_obj_columns(ctx, sorted, + drilldown->output_columns, + drilldown->output_columns_len, + &format.columns); + GRN_OUTPUT_OBJ(sorted, &format); + GRN_OBJ_FORMAT_FIN(ctx, &format); + grn_obj_unlink(ctx, sorted); + } + grn_table_sort_key_close(ctx, sort_keys, n_sort_keys); + } + } else { + grn_obj_format format; + GRN_OBJ_FORMAT_INIT(&format, n_hits, offset, limit, offset); + format.flags = + GRN_OBJ_FORMAT_WITH_COLUMN_NAMES| + GRN_OBJ_FORMAT_XML_ELEMENT_NAVIGATIONENTRY; + grn_obj_columns(ctx, result.table, + drilldown->output_columns, + drilldown->output_columns_len, + &format.columns); + GRN_OUTPUT_OBJ(result.table, &format); + GRN_OBJ_FORMAT_FIN(ctx, &format); + } + + grn_table_sort_key_close(ctx, keys, n_keys); + grn_obj_unlink(ctx, result.table); + + GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE, + ":", "drilldown(%d)[%.*s]", n_hits, + (int)(drilldown->label_len), drilldown->label); + } + GRN_OUTPUT_MAP_CLOSE(); +} + static grn_rc grn_select(grn_ctx *ctx, const char *table, unsigned int table_len, const char *match_columns, unsigned int match_columns_len, @@ -618,10 +787,8 @@ grn_select(grn_ctx *ctx, const char *table, unsigned int table_len, const char *sortby, unsigned int sortby_len, const char *output_columns, unsigned int output_columns_len, int offset, int limit, - const char *drilldown, unsigned int drilldown_len, - const char *drilldown_sortby, unsigned int drilldown_sortby_len, - const char *drilldown_output_columns, unsigned int drilldown_output_columns_len, - int drilldown_offset, int drilldown_limit, + drilldown_info *drilldowns, + unsigned int n_drilldowns, const char *cache, unsigned int cache_len, const char *match_escalation_threshold, unsigned int match_escalation_threshold_len, const char *query_expander, unsigned int query_expander_len, @@ -636,14 +803,26 @@ grn_select(grn_ctx *ctx, const char *table, unsigned int table_len, grn_content_type output_type = ctx->impl->output_type; grn_obj *table_, *match_columns_ = NULL, *cond = NULL, *scorer_, *res = NULL, *sorted; char cache_key[GRN_TABLE_MAX_KEY_SIZE]; - uint32_t cache_key_size = table_len + 1 + match_columns_len + 1 + query_len + 1 + - filter_len + 1 + scorer_len + 1 + sortby_len + 1 + output_columns_len + 1 + - drilldown_len + 1 + drilldown_sortby_len + 1 + - drilldown_output_columns_len + 1 + match_escalation_threshold_len + 1 + - query_expander_len + 1 + query_flags_len + 1 + adjuster_len + 1 + - sizeof(grn_content_type) + sizeof(int) * 4; + uint32_t cache_key_size; long long int threshold, original_threshold = 0; grn_cache *cache_obj = grn_cache_current_get(ctx); + + cache_key_size = table_len + 1 + match_columns_len + 1 + query_len + 1 + + filter_len + 1 + scorer_len + 1 + sortby_len + 1 + output_columns_len + 1 + + match_escalation_threshold_len + 1 + + query_expander_len + 1 + query_flags_len + 1 + adjuster_len + 1 + + sizeof(grn_content_type) + sizeof(int) * 2; + { + unsigned int i; + for (i = 0; i < n_drilldowns; i++) { + drilldown_info *drilldown = &(drilldowns[i]); + cache_key_size += + drilldown->keys_len + 1 + + drilldown->sortby_len + 1 + + drilldown->output_columns_len + 1 + + sizeof(int) * 2; + } + } if (cache_key_size <= GRN_TABLE_MAX_KEY_SIZE) { grn_obj *cache_value; char *cp = cache_key; @@ -661,12 +840,18 @@ grn_select(grn_ctx *ctx, const char *table, unsigned int table_len, cp += sortby_len; *cp++ = '\0'; memcpy(cp, output_columns, output_columns_len); cp += output_columns_len; *cp++ = '\0'; - memcpy(cp, drilldown, drilldown_len); - cp += drilldown_len; *cp++ = '\0'; - memcpy(cp, drilldown_sortby, drilldown_sortby_len); - cp += drilldown_sortby_len; *cp++ = '\0'; - memcpy(cp, drilldown_output_columns, drilldown_output_columns_len); - cp += drilldown_output_columns_len; *cp++ = '\0'; + { + unsigned int i; + for (i = 0; i < n_drilldowns; i++) { + drilldown_info *drilldown = &(drilldowns[i]); + memcpy(cp, drilldown->keys, drilldown->keys_len); + cp += drilldown->keys_len; *cp++ = '\0'; + memcpy(cp, drilldown->sortby, drilldown->sortby_len); + cp += drilldown->sortby_len; *cp++ = '\0'; + memcpy(cp, drilldown->output_columns, drilldown->output_columns_len); + cp += drilldown->output_columns_len; *cp++ = '\0'; + } + } memcpy(cp, match_escalation_threshold, match_escalation_threshold_len); cp += match_escalation_threshold_len; *cp++ = '\0'; memcpy(cp, query_expander, query_expander_len); @@ -678,8 +863,14 @@ grn_select(grn_ctx *ctx, const char *table, unsigned int table_len, memcpy(cp, &output_type, sizeof(grn_content_type)); cp += sizeof(grn_content_type); memcpy(cp, &offset, sizeof(int)); cp += sizeof(int); memcpy(cp, &limit, sizeof(int)); cp += sizeof(int); - memcpy(cp, &drilldown_offset, sizeof(int)); cp += sizeof(int); - memcpy(cp, &drilldown_limit, sizeof(int)); cp += sizeof(int); + { + unsigned int i; + for (i = 0; i < n_drilldowns; i++) { + drilldown_info *drilldown = &(drilldowns[i]); + memcpy(cp, &(drilldown->offset), sizeof(int)); cp += sizeof(int); + memcpy(cp, &(drilldown->limit), sizeof(int)); cp += sizeof(int); + } + } cache_value = grn_cache_fetch(ctx, cache_obj, cache_key, cache_key_size); if (cache_value) { GRN_TEXT_PUT(ctx, outbuf, @@ -781,12 +972,17 @@ grn_select(grn_ctx *ctx, const char *table, unsigned int table_len, uint32_t ngkeys; grn_table_sort_key *gkeys = NULL; int result_size = 1; - if (!ctx->rc && drilldown_len) { - gkeys = grn_table_sort_key_from_str(ctx, - drilldown, drilldown_len, - res, &ngkeys); - if (gkeys) { - result_size += ngkeys; + if (!ctx->rc && n_drilldowns > 0) { + if (n_drilldowns == 1 && !drilldowns[0].label) { + gkeys = grn_table_sort_key_from_str(ctx, + drilldowns[0].keys, + drilldowns[0].keys_len, + res, &ngkeys); + if (gkeys) { + result_size += ngkeys; + } + } else { + result_size += 1; } } @@ -903,12 +1099,17 @@ grn_select(grn_ctx *ctx, const char *table, unsigned int table_len, } GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE, ":", "output(%d)", limit); - if (!ctx->rc && gkeys) { - grn_select_drilldown(ctx, res, gkeys, ngkeys, - drilldown_offset, drilldown_limit, - drilldown_sortby, drilldown_sortby_len, - drilldown_output_columns, - drilldown_output_columns_len); + if (!ctx->rc) { + if (gkeys) { + drilldown_info *drilldown = &(drilldowns[0]); + grn_select_drilldown(ctx, res, gkeys, ngkeys, + drilldown->offset, drilldown->limit, + drilldown->sortby, drilldown->sortby_len, + drilldown->output_columns, + drilldown->output_columns_len); + } else if (n_drilldowns > 0) { + grn_select_drilldowns(ctx, res, drilldowns, n_drilldowns); + } } if (gkeys) { grn_table_sort_key_close(ctx, gkeys, ngkeys); @@ -941,9 +1142,46 @@ exit: return ctx->rc; } +static void +proc_select_find_all_drilldown_labels(grn_ctx *ctx, grn_user_data *user_data, + grn_obj *labels) +{ + grn_obj *vars = GRN_PROC_GET_VARS(); + grn_table_cursor *cursor; + cursor = grn_table_cursor_open(ctx, vars, NULL, 0, NULL, 0, 0, -1, 0); + if (cursor) { + const char *prefix = "drilldown["; + int prefix_len = strlen(prefix); + const char *suffix = "].keys"; + int suffix_len = strlen(suffix); + while (grn_table_cursor_next(ctx, cursor)) { + void *key; + char *name; + int name_len; + name_len = grn_table_cursor_get_key(ctx, cursor, &key); + name = key; + if (name_len < (prefix_len + 1 + suffix_len)) { + continue; + } + if (strncmp(prefix, name, prefix_len) != 0) { + continue; + } + if (strncmp(suffix, name + name_len - suffix_len, suffix_len) != 0) { + continue; + } + grn_vector_add_element(ctx, labels, + name + prefix_len, + name_len - prefix_len - suffix_len, + 0, GRN_ID_NIL); + } + grn_table_cursor_close(ctx, cursor); + } +} + static grn_obj * proc_select(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data) { +#define MAX_N_DRILLDOWNS 10 int offset = GRN_TEXT_LEN(VAR(7)) ? grn_atoi(GRN_TEXT_VALUE(VAR(7)), GRN_BULK_CURR(VAR(7)), NULL) : 0; @@ -952,27 +1190,66 @@ proc_select(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data) : DEFAULT_LIMIT; const char *output_columns = GRN_TEXT_VALUE(VAR(6)); uint32_t output_columns_len = GRN_TEXT_LEN(VAR(6)); - const char *drilldown_output_columns = GRN_TEXT_VALUE(VAR(11)); - uint32_t drilldown_output_columns_len = GRN_TEXT_LEN(VAR(11)); - int drilldown_offset = GRN_TEXT_LEN(VAR(12)) - ? grn_atoi(GRN_TEXT_VALUE(VAR(12)), GRN_BULK_CURR(VAR(12)), NULL) - : 0; - int drilldown_limit = GRN_TEXT_LEN(VAR(13)) - ? grn_atoi(GRN_TEXT_VALUE(VAR(13)), GRN_BULK_CURR(VAR(13)), NULL) - : DEFAULT_DRILLDOWN_LIMIT; + drilldown_info drilldowns[MAX_N_DRILLDOWNS]; + unsigned int n_drilldowns = 0; + grn_obj drilldown_labels; grn_obj *query_expansion = VAR(16); grn_obj *query_expander = VAR(18); grn_obj *adjuster = VAR(19); + if (GRN_TEXT_LEN(query_expander) == 0 && GRN_TEXT_LEN(query_expansion) > 0) { query_expander = query_expansion; } + if (!output_columns_len) { output_columns = DEFAULT_OUTPUT_COLUMNS; output_columns_len = strlen(DEFAULT_OUTPUT_COLUMNS); } - if (!drilldown_output_columns_len) { - drilldown_output_columns = DEFAULT_DRILLDOWN_OUTPUT_COLUMNS; - drilldown_output_columns_len = strlen(DEFAULT_DRILLDOWN_OUTPUT_COLUMNS); + + GRN_TEXT_INIT(&drilldown_labels, GRN_OBJ_VECTOR); + if (GRN_TEXT_LEN(VAR(9))) { + drilldown_info *drilldown = &(drilldowns[0]); + drilldown->label = NULL; + drilldown->label_len = 0; + drilldown_info_fill(ctx, drilldown, + VAR(9), VAR(10), VAR(11), VAR(12), VAR(13)); + n_drilldowns++; + } else { + unsigned int i; + proc_select_find_all_drilldown_labels(ctx, user_data, &drilldown_labels); + n_drilldowns = grn_vector_size(ctx, &drilldown_labels); + for (i = 0; i < n_drilldowns; i++) { + drilldown_info *drilldown = &(drilldowns[i]); + const char *label; + int label_len; + char key_name[GRN_TABLE_MAX_KEY_SIZE]; + grn_obj *keys; + grn_obj *sortby; + grn_obj *output_columns; + grn_obj *offset; + grn_obj *limit; + + label_len = grn_vector_get_element(ctx, &drilldown_labels, i, + &label, NULL, NULL); + drilldown->label = label; + drilldown->label_len = label_len; + +#define GET_VAR(name)\ + snprintf(key_name, GRN_TABLE_MAX_KEY_SIZE,\ + "drilldown[%.*s]." # name, label_len, label);\ + name = GRN_PROC_GET_VAR(key_name); + + GET_VAR(keys); + GET_VAR(sortby); + GET_VAR(output_columns); + GET_VAR(offset); + GET_VAR(limit); + +#undef GET_VAR + + drilldown_info_fill(ctx, drilldown, + keys, sortby, output_columns, offset, limit); + } } if (grn_select(ctx, GRN_TEXT_VALUE(VAR(0)), GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(1)), GRN_TEXT_LEN(VAR(1)), @@ -982,16 +1259,16 @@ proc_select(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data) GRN_TEXT_VALUE(VAR(5)), GRN_TEXT_LEN(VAR(5)), output_columns, output_columns_len, offset, limit, - GRN_TEXT_VALUE(VAR(9)), GRN_TEXT_LEN(VAR(9)), - GRN_TEXT_VALUE(VAR(10)), GRN_TEXT_LEN(VAR(10)), - drilldown_output_columns, drilldown_output_columns_len, - drilldown_offset, drilldown_limit, + drilldowns, n_drilldowns, GRN_TEXT_VALUE(VAR(14)), GRN_TEXT_LEN(VAR(14)), GRN_TEXT_VALUE(VAR(15)), GRN_TEXT_LEN(VAR(15)), GRN_TEXT_VALUE(query_expander), GRN_TEXT_LEN(query_expander), GRN_TEXT_VALUE(VAR(17)), GRN_TEXT_LEN(VAR(17)), GRN_TEXT_VALUE(adjuster), GRN_TEXT_LEN(adjuster))) { } + GRN_OBJ_FIN(ctx, &drilldown_labels); +#undef MAX_N_DRILLDOWNS + return NULL; } Added: test/command/suite/select/drilldown/labeled/keys/multiple.expected (+121 -0) 100644 =================================================================== --- /dev/null +++ test/command/suite/select/drilldown/labeled/keys/multiple.expected 2014-11-16 19:33:45 +0900 (862ac7c) @@ -0,0 +1,121 @@ +table_create Tags TABLE_PAT_KEY ShortText +[[0,0.0,0.0],true] +table_create Memos TABLE_HASH_KEY ShortText +[[0,0.0,0.0],true] +column_create Memos tag COLUMN_SCALAR Tags +[[0,0.0,0.0],true] +column_create Memos date COLUMN_SCALAR Time +[[0,0.0,0.0],true] +load --table Memos +[ +{"_key": "Groonga is fast!", "tag": "Groonga", "date": "2014-11-16 00:00:00"}, +{"_key": "Mroonga is fast!", "tag": "Mroonga", "date": "2014-11-16 00:00:00"}, +{"_key": "Groonga sticker!", "tag": "Groonga", "date": "2014-11-16 00:00:00"}, +{"_key": "Rroonga is fast!", "tag": "Rroonga", "date": "2014-11-17 00:00:00"}, +{"_key": "Groonga is good!", "tag": "Groonga", "date": "2014-11-17 00:00:00"} +] +[[0,0.0,0.0],5] +select Memos --drilldown[tag].keys tag,date --drilldown[tag].output_columns _value.tag,_value.date,_nsubrecs +[ + [ + 0, + 0.0, + 0.0 + ], + [ + [ + [ + 5 + ], + [ + [ + "_id", + "UInt32" + ], + [ + "_key", + "ShortText" + ], + [ + "date", + "Time" + ], + [ + "tag", + "Tags" + ] + ], + [ + 1, + "Groonga is fast!", + 1416063600.0, + "Groonga" + ], + [ + 2, + "Mroonga is fast!", + 1416063600.0, + "Mroonga" + ], + [ + 3, + "Groonga sticker!", + 1416063600.0, + "Groonga" + ], + [ + 4, + "Rroonga is fast!", + 1416150000.0, + "Rroonga" + ], + [ + 5, + "Groonga is good!", + 1416150000.0, + "Groonga" + ] + ], + { + "tag": [ + [ + 4 + ], + [ + [ + "tag", + "Tags" + ], + [ + "date", + "Time" + ], + [ + "_nsubrecs", + "Int32" + ] + ], + [ + "Groonga", + 1416063600.0, + 2 + ], + [ + "Mroonga", + 1416063600.0, + 1 + ], + [ + "Rroonga", + 1416150000.0, + 1 + ], + [ + "Groonga", + 1416150000.0, + 1 + ] + ] + } + ] +] Added: test/command/suite/select/drilldown/labeled/keys/multiple.test (+18 -0) 100644 =================================================================== --- /dev/null +++ test/command/suite/select/drilldown/labeled/keys/multiple.test 2014-11-16 19:33:45 +0900 (3495239) @@ -0,0 +1,18 @@ +table_create Tags TABLE_PAT_KEY ShortText + +table_create Memos TABLE_HASH_KEY ShortText +column_create Memos tag COLUMN_SCALAR Tags +column_create Memos date COLUMN_SCALAR Time + +load --table Memos +[ +{"_key": "Groonga is fast!", "tag": "Groonga", "date": "2014-11-16 00:00:00"}, +{"_key": "Mroonga is fast!", "tag": "Mroonga", "date": "2014-11-16 00:00:00"}, +{"_key": "Groonga sticker!", "tag": "Groonga", "date": "2014-11-16 00:00:00"}, +{"_key": "Rroonga is fast!", "tag": "Rroonga", "date": "2014-11-17 00:00:00"}, +{"_key": "Groonga is good!", "tag": "Groonga", "date": "2014-11-17 00:00:00"} +] + +select Memos \ + --drilldown[tag].keys tag,date \ + --drilldown[tag].output_columns _value.tag,_value.date,_nsubrecs Added: test/command/suite/select/drilldown/labeled/keys/one.expected (+92 -0) 100644 =================================================================== --- /dev/null +++ test/command/suite/select/drilldown/labeled/keys/one.expected 2014-11-16 19:33:45 +0900 (ffcde1a) @@ -0,0 +1,92 @@ +table_create Tags TABLE_PAT_KEY ShortText +[[0,0.0,0.0],true] +table_create Memos TABLE_HASH_KEY ShortText +[[0,0.0,0.0],true] +column_create Memos tag COLUMN_SCALAR Tags +[[0,0.0,0.0],true] +load --table Memos +[ +{"_key": "Groonga is fast!", "tag": "Groonga"}, +{"_key": "Mroonga is fast!", "tag": "Mroonga"}, +{"_key": "Groonga sticker!", "tag": "Groonga"}, +{"_key": "Rroonga is fast!", "tag": "Rroonga"} +] +[[0,0.0,0.0],4] +select Memos --drilldown[tag].keys tag +[ + [ + 0, + 0.0, + 0.0 + ], + [ + [ + [ + 4 + ], + [ + [ + "_id", + "UInt32" + ], + [ + "_key", + "ShortText" + ], + [ + "tag", + "Tags" + ] + ], + [ + 1, + "Groonga is fast!", + "Groonga" + ], + [ + 2, + "Mroonga is fast!", + "Mroonga" + ], + [ + 3, + "Groonga sticker!", + "Groonga" + ], + [ + 4, + "Rroonga is fast!", + "Rroonga" + ] + ], + { + "tag": [ + [ + 3 + ], + [ + [ + "_key", + "ShortText" + ], + [ + "_nsubrecs", + "Int32" + ] + ], + [ + "Groonga", + 2 + ], + [ + "Mroonga", + 1 + ], + [ + "Rroonga", + 1 + ] + ] + } + ] +] Added: test/command/suite/select/drilldown/labeled/keys/one.test (+14 -0) 100644 =================================================================== --- /dev/null +++ test/command/suite/select/drilldown/labeled/keys/one.test 2014-11-16 19:33:45 +0900 (fff8052) @@ -0,0 +1,14 @@ +table_create Tags TABLE_PAT_KEY ShortText + +table_create Memos TABLE_HASH_KEY ShortText +column_create Memos tag COLUMN_SCALAR Tags + +load --table Memos +[ +{"_key": "Groonga is fast!", "tag": "Groonga"}, +{"_key": "Mroonga is fast!", "tag": "Mroonga"}, +{"_key": "Groonga sticker!", "tag": "Groonga"}, +{"_key": "Rroonga is fast!", "tag": "Rroonga"} +] + +select Memos --drilldown[tag].keys tag -------------- next part -------------- HTML����������������������������... Download