[Groonga-commit] groonga/groonga [master] Added grn_geo_search().

Back to archive index

null+****@clear***** null+****@clear*****
2010年 7月 1日 (木) 10:25:34 JST


Daijiro MORI	2010-07-01 01:25:34 +0000 (Thu, 01 Jul 2010)

  New Revision: 5ecfba725e61d32d872b5e279f5ae103250e483a

  Log:
    Added grn_geo_search().

  Modified files:
    lib/db.c
    lib/expr.c
    lib/proc.c

  Modified: lib/db.c (+1 -0)
===================================================================
--- lib/db.c    2010-06-30 01:34:55 +0000 (3cf15d9)
+++ lib/db.c    2010-07-01 01:25:34 +0000 (d15ba14)
@@ -6672,6 +6672,7 @@ grn_column_index(grn_ctx *ctx, grn_obj *obj, grn_operator op,
     case GRN_OP_GREATER :
     case GRN_OP_LESS_EQUAL :
     case GRN_OP_GREATER_EQUAL :
+    case GRN_OP_CALL :
       for (hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
         default_set_value_hook_data *data = (void *)NEXT_ADDR(hooks);
         grn_obj *target = grn_ctx_at(ctx, data->target);

  Modified: lib/expr.c (+20 -5)
===================================================================
--- lib/expr.c    2010-06-30 01:34:55 +0000 (cd07427)
+++ lib/expr.c    2010-07-01 01:25:34 +0000 (671f271)
@@ -3582,21 +3582,25 @@ scan_info_build(grn_ctx *ctx, grn_obj *expr, int *n,
         si->op = c->op;
         si->end = c - e->codes;
         sis[i++] = si;
-        /* index may be applicable occasionaly
+        /* better index resolving framework for functions should be implemented */
         {
-          grn_obj **p = si->args, **pe = si->args + si->nargs;
+          uint32_t sid;
+          grn_obj *index, **p = si->args, **pe = si->args + si->nargs;
           for (; p < pe; p++) {
             if (GRN_DB_OBJP(*p)) {
-              grn_column_index(ctx, *p, c->op, &si->index, 1, &sid);
+              if (grn_column_index(ctx, *p, c->op, &index, 1, &sid)) {
+                scan_info_put_index(ctx, si, index, sid, 1);
+              }
             } else if (GRN_ACCESSORP(*p)) {
               si->flags |= SCAN_ACCESSOR;
-              grn_column_index(ctx, *p, c->op, &si->index, 1, &sid);
+              if (grn_column_index(ctx, *p, c->op, &index, 1, &sid)) {
+                scan_info_put_index(ctx, si, index, sid, 1);
+              }
             } else {
               si->query = *p;
             }
           }
         }
-        */
         si = NULL;
       } else {
         stat = SCAN_COL2;
@@ -3760,6 +3764,9 @@ grn_view_select(grn_ctx *ctx, grn_obj *table, grn_obj *expr,
   GRN_LOG(ctx, GRN_LOG_NONE, "%08x|:%012llu %s", (intptr_t)ctx, et, msg);\
 }
 
+grn_rc grn_geo_search(grn_ctx *ctx, grn_obj *obj, grn_obj **args, int nargs,
+                      grn_obj *res, grn_operator op);
+
 grn_obj *
 grn_table_select(grn_ctx *ctx, grn_obj *table, grn_obj *expr,
                  grn_obj *res, grn_operator op)
@@ -3973,6 +3980,14 @@ grn_table_select(grn_ctx *ctx, grn_obj *table, grn_obj *expr,
                 }
               }
               break;
+            case GRN_OP_CALL :
+              /* geo_in_circle only */
+              if (si->flags & SCAN_ACCESSOR) {
+              } else {
+                grn_geo_search(ctx, index, si->args, si->nargs, res, si->logical_op);
+                done++;
+              }
+              break;
             default :
               /* todo : implement */
               /* todo : handle SCAN_PRE_CONST */

  Modified: lib/proc.c (+83 -0)
===================================================================
--- lib/proc.c    2010-06-30 01:34:55 +0000 (048395f)
+++ lib/proc.c    2010-07-01 01:25:34 +0000 (cf23748)
@@ -22,6 +22,7 @@
 #include <sys/stat.h>
 #include "proc.h"
 #include "ql.h"
+#include "ii.h"
 #include "db.h"
 #include "util.h"
 #include "output.h"
@@ -1929,6 +1930,88 @@ exit :
   return obj;
 }
 
+grn_rc
+grn_geo_search(grn_ctx *ctx, grn_obj *obj, grn_obj **args, int nargs,
+               grn_obj *res, grn_operator op)
+{
+  grn_id domain;
+  double lng0, lat0, lng1, lat1, lng2, lat2, x, y, d;
+  grn_obj *pos1 = args[1], *pos2 = args[2], pos1_, pos2_;
+  grn_obj *pat = grn_ctx_at(ctx, obj->header.domain);
+  if (nargs != 3) { goto exit; }
+  domain = pat->header.domain;
+  if (domain != GRN_DB_TOKYO_GEO_POINT && domain != GRN_DB_WGS84_GEO_POINT) { goto exit; }
+  if (pos1->header.domain != domain) {
+    GRN_OBJ_INIT(&pos1_, GRN_BULK, 0, domain);
+    if (grn_obj_cast(ctx, pos1, &pos1_, 0)) { goto exit; }
+    pos1 = &pos1_;
+  }
+  lng1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(pos1))->longitude);
+  lat1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(pos1))->latitude);
+  switch (pos2->header.domain) {
+  case GRN_DB_INT32 :
+    d = GRN_INT32_VALUE(pos2);
+    d = d * d / GEO_RADIOUS;
+    break;
+  case GRN_DB_UINT32 :
+    d = GRN_UINT32_VALUE(pos2);
+    d = d * d / GEO_RADIOUS;
+    break;
+  case GRN_DB_INT64 :
+    d = GRN_INT64_VALUE(pos2);
+    d = d * d / GEO_RADIOUS;
+    break;
+  case GRN_DB_UINT64 :
+    d = GRN_UINT64_VALUE(pos2);
+    d = d * d / GEO_RADIOUS;
+    break;
+  case GRN_DB_FLOAT :
+    d = GRN_FLOAT_VALUE(pos2);
+    d = d * d / GEO_RADIOUS;
+    break;
+  case GRN_DB_SHORT_TEXT :
+  case GRN_DB_TEXT :
+  case GRN_DB_LONG_TEXT :
+    GRN_OBJ_INIT(&pos2_, GRN_BULK, 0, domain);
+    if (grn_obj_cast(ctx, pos2, &pos2_, 0)) { goto exit; }
+    pos2 = &pos2_;
+    /* fallthru */
+  case GRN_DB_TOKYO_GEO_POINT :
+  case GRN_DB_WGS84_GEO_POINT :
+    if (domain != pos2->header.domain) { /* todo */ goto exit; }
+    lng2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(pos2))->longitude);
+    lat2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(pos2))->latitude);
+    x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5);
+    y = (lat2 - lat1);
+    d = ((x * x) + (y * y));
+    break;
+  default :
+    goto exit;
+  }
+  {
+    grn_id tid;
+    grn_geo_point pos;
+    grn_table_cursor *tc = grn_table_cursor_open(ctx, pat, NULL, 0,
+                                                 GRN_BULK_HEAD(pos1),
+                                                 sizeof(grn_geo_point),
+                                                 0, -1, GRN_CURSOR_PREFIX);
+    while ((tid = grn_table_cursor_next(ctx, tc))) {
+      grn_table_get_key(ctx, pat, tid, &pos, sizeof(grn_geo_point));
+      lng0 = GEO_INT2RAD(pos.longitude);
+      lat0 = GEO_INT2RAD(pos.latitude);
+      x = (lng1 - lng0) * cos((lat0 + lat1) * 0.5);
+      y = (lat1 - lat0);
+      if (((x * x) + (y * y)) <= d) {
+        grn_ii_at(ctx, (grn_ii *)index, tid, (grn_hash *)res, op);
+      }
+    }
+    grn_table_cursor_close(ctx, tc);
+  }
+exit :
+  grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+  return ctx->rc;
+}
+
 static grn_obj *
 func_geo_in_rectangle(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
 {




Groonga-commit メーリングリストの案内
Back to archive index