GroongaのC APIでソートする方法

# table構成
```bash
groonga test.grn select data --output_pretty yes
[
  [
    0,
    1462590957.809856,
    0.007364749908447266
  ],
  [
    [
      [
        2
      ],
      [
        [
          "_id",
          "UInt32"
        ],
        [
          "_key",
          "ShortText"
        ],
        [
          "column",
          "Text"
        ]
      ],
      [
        1,
        "groonga",
        "groonga world"
      ],
      [
        2,
        "droonga",
        "distributed groonga"
      ]
    ]
  ]
]
```

このテーブルの_keyをC APIを使ってアルファベット昇順に並び替えます。

``grn_p``を使うと、テーブルの詳細を見ることができます。``data``テーブルはShortText型のキーで２つのキーが登録されています。

```
#<table:hash data key:ShortText value:(nil) size:2
 columns:[column]
 default_tokenizer:(nil) normalizer:(nil)
 keys:["groonga", "droonga"] subrec:none>
```

# tableをスクリプト構文で絞り込む
まず、``result``という一時テーブルにスクリプト構文で適当に絞り込んだ結果をセットします。

```c
grn_obj *
table_select_by_filter(grn_ctx *ctx, grn_obj *table, char *filter)
{
  grn_obj *v, *cond;
  grn_obj *result = NULL;

  GRN_EXPR_CREATE_FOR_QUERY(ctx, table, cond, v);
  grn_expr_parse(ctx, cond,
                 filter,
                 strlen(filter),
                 NULL,
                 GRN_OP_MATCH,
                 GRN_OP_AND,
                 GRN_EXPR_SYNTAX_SCRIPT);

  result = grn_table_create(ctx, NULL, 0, NULL,
                            GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
                            table, NULL);
  if (result) {
    grn_table_select(ctx, table, cond, result, GRN_OP_OR);
  }
  printf("hits: %d\n", grn_table_size(ctx, result));

  return result;
}

---
  result = table_select_by_filter(&ctx, table, "column @ \"groonga\"");
---
```

この場合、2つのレコードがヒットします。``data``テーブルをキーの型とする一時テーブル``result``に2つのヒットレコードが格納されています。

```
#<table:hash (nil) key:data value:(nil) size:2
 columns:[]
 default_tokenizer:(nil) normalizer:(nil)
 keys:[#<record:hash:data id:1 key:"groonga" column:"groonga world">, #<record:hash:data id:2 key:"droonga" column:"distributed groonga">]
 subrec:document:none>
```

# 一時テーブル``result``をソートする

```c
grn_obj *
table_sort(grn_ctx *ctx, grn_obj *table, const char *sortby)
{
  grn_obj *sorted = NULL;
  grn_table_sort_key *sort_keys = NULL;
  uint32_t n_sort_keys;
  if (sortby) {
    sort_keys = grn_table_sort_key_from_str(ctx,
                                            sortby,
                                            strlen(sortby),
                                            table, &n_sort_keys);
    if (sort_keys) {
      sorted = grn_table_create(ctx, NULL, 0, NULL, GRN_OBJ_TABLE_NO_KEY,
                                 NULL, table);
      if (sorted) {
        grn_table_sort(ctx, table, 0, -1,
                       sorted, sort_keys, n_sort_keys);
      }
      grn_table_sort_key_close(ctx, sort_keys, n_sort_keys);
    }
  }
  return sorted;
}

---
  {
    grn_obj *sorted;
    sorted = table_sort(&ctx, result, "_key");
    if (sorted) {
      grn_obj_unlink(&ctx, sorted);
    }
  }
---
```

こんな感じで``_key``の昇順でソートします。ソート結果テーブル``sorted``を``grn_p``すると以下のようになっています。キーなしのarray型で結果テーブル``result``のidがソートされて入っています。

```
#<table:no_key (nil) value:(nil) size:2
 columns:[] ids:[1, 2] subrec:none>
```

# ソート結果テーブル``sorted``を出力する

```c
void
dump_records(grn_ctx *ctx, grn_obj *table, const char *column_name)
{
  grn_table_cursor *cur;
  grn_obj *key_accessor;
  grn_obj *column_accessor;
  grn_obj buf;

  key_accessor = grn_obj_column(ctx, table, GRN_COLUMN_NAME_KEY, GRN_COLUMN_NAME_KEY_LEN);
  column_accessor = grn_obj_column(ctx, table, column_name, strlen(column_name));
  GRN_TEXT_INIT(&buf, 0);
  if ((cur = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1,
                                   GRN_CURSOR_BY_ID))) {
    grn_id id;
    while ((id = grn_table_cursor_next(ctx, cur)) != GRN_ID_NIL) {
      GRN_BULK_REWIND(&buf);
      grn_obj_get_value(ctx, key_accessor, id, &buf);
      printf("%.*s:", (int)GRN_TEXT_LEN(&buf), GRN_TEXT_VALUE(&buf));
      GRN_BULK_REWIND(&buf);
      grn_obj_get_value(ctx, column_accessor, id, &buf);
      printf("%.*s\n", (int)GRN_TEXT_LEN(&buf), GRN_TEXT_VALUE(&buf));
    }
  }
  GRN_OBJ_FIN(ctx, &buf);
  grn_obj_unlink(ctx, key_accessor);
  grn_obj_unlink(ctx, column_accessor);
  grn_table_cursor_close(ctx, cur);
}

---
    if (sorted) {
      dump_records(&ctx, sorted, "column");
      grn_obj_unlink(&ctx, sorted);
    }
---
```

こんな感じでソート済み結果テーブルを出力することができます。

ポイントは``grn_table_get_key``などで直接keyとidで取り出すのではなく、ソート済み結果テーブル``sorted``に対して``grn_obj_column``でaccessorを設定して``grn_obj_get_value``で取り出すことです。

他の方法として、頑張れば、``grn_table_cursor_next``で得たidで``sorted``からvalueを取得し、取得したvalueで``result``に対して``grn_table_get_key``をし、さらに、``data``テーブルに対して``grn_table_get``すれば、もとのテーブルの``_key``が辿れると思います。

なぜならば、``sorted``はarray型のテーブルで``result``のidが入っており、``result``のキーには``data``テーブルのidが入っているからです。

しかし、これはめんどくさすぎですね。わけがわからないと思います。

そこで、上記のようにaccessorを使えば、簡単に参照関係を解決してくれます。

# サンプル

https://github.com/naoa/groonga-api-sample