12

GWTとAppEngineを使用してWebアプリケーションを作成しています。私のアプリケーションは、緯度、経度に基づいてアイテムを投稿およびクエリする必要があります。

グーグルの分散データベース設計の結果として、不等式のセットを単純に照会することはできません。代わりに、彼らはジオハッシュを行うことを提案しています。このページでその方法を説明します。

http://code.google.com/appengine/articles/geosearch.html

基本的に、バウンディングボックスでタグ付けされたアイテムをクエリできるように、バウンディングボックスを事前に計算します。

私が理解していないプロセスの一部があります。「スライス」属性はどういう意味ですか?

ご協力いただきありがとうございます!

4

8 に答える 8

7

Geomodelの完全なJavaPortageについては、http: //code.google.com/p/javageomodel/を参照してください。

使い方を説明するデモクラスがあります。

于 2010-02-26T16:21:27.243 に答える
6

自分でジオハッシュを実装するのではなく、GoogleAppEngineにジオハッシュのようなシステムを実装するGeoModelオープンソースプロジェクトに興味があるかもしれません。すべての詳細を理解するのではなく、このライブラリをインポートして、やのような呼び出しを行うことができproximity_fetch()ますbounding_box_fetch()

この最近の記事では、それがどのように機能するかを説明し、それを使用する例を提供します。

于 2010-01-15T09:32:11.803 に答える
3

バウンディングボックスを4つの座標(最小および最大の緯度、最小および最大の経度)で定義する代わりに、ボックスの北西の角の座標と、解像度とスライスの2つのパラメーターで定義できます。解像度はボックスのスケールを定義し、小数点以下の桁数として実装されます。スライスはボックスの幅と高さであり、最下位の数字を単位として使用します。

geobox.pyのコメントは、これをより詳細に説明し、良い例を示しています。

バウンディングボックスのメンバーを照会するには、lat = 37.78452 long = -122.39532(両方の解像度5)のようないくつかの入力座標から始めます。次に、これらの座標を最も近い「スライス」に上下に丸めて、ジオボックスを生成します。「スライス」とは、ジオボックスの解像度の各レベルをどれだけ細かく分割するかです。最小スライスサイズは1です。最大スライスには制限がありません。これは、スライスが大きいほど解像度が低くなるためです(例で説明できるといいのですが)。

いくつかの例:

解像度=5、スライス= 2、および緯度= 37.78452長さ=-122.39532: "37.78452 | -122.39532 | 37.78450 | -122.39530"

解像度=5、スライス= 10、および緯度= 37.78452長さ=-122.39532: "37.78460 | -122.39540 | 37.78450 | -122.39530"

解像度=5、スライス= 25、緯度= 37.78452長さ=-122.39532: "37.78475 | -122.39550 | 37.78450 | -122.39525"

于 2010-01-14T08:06:49.227 に答える
3

私はGWT/GAEプロジェクトに取り組んでいますが、同じ問題がありました。私の解決策は、GWTに対応するように少し変更したGeohashクラスを使用することでした。近接検索のニーズに最適です。

Geohashesの動作を一度も見たことがない場合は、DaveTroyJSデモページをご覧ください。

于 2010-01-23T03:20:57.937 に答える
1

App Engineで地理空間検索を行う代わりに、SearchApiを使用できます。ジオハッシュや実装の詳細について心配する必要はなく、ジオポイントに近い要素を検索できます。

https://developers.google.com/appengine/docs/python/search/overview#Performing_Location-Based_Searches

于 2013-05-20T05:31:31.650 に答える
0

また、GeoModelのJavaバージョンも必要でした。以前はGeohashを使用していたため、特定の境界ボックス内の場所を取得できました。ただし、並べ替えに関しては、これにはかなりの制限があります。BigTableでのようなフィルタを受け入れるにはgeohash > '" + bottomLeft + "' && geohash < '" + topRight + "'"、リストgeohashも並べ替える必要があります。これにより、他の条件で並べ替えることができなくなります(特に、ページネーションを使用)。同時に、Javaコード以外では、結果を距離(特定のユーザー位置、つまりバウンディングボックスの中心から)で並べ替える解決策を考えることはできません。繰り返しますが、ページネーションが必要な場合、これは機能しません。

これらの問題のために、私は別のアプローチを使用する必要があり、GeoModel/Geoboxesがその方法のようでした。そこで、PythonコードをJavaに移植しましたが、正常に機能しています。結果は次のとおりです。

public class Geobox {

    private static double roundSlicedown(double coord, double slice) {
        double remainder = coord % slice;
        if (remainder == Double.NaN) {
            return coord;
        }
        if (coord > 0) {
            return coord - remainder + slice;
        } else {
            return coord - remainder;
        }
    }

    private static double[] computeTuple(double lat, double lng,
            int resolution, double slice) {
        slice = slice * Math.pow(10, -resolution);
        double adjustedLat = roundSlicedown(lat, slice);
        double adjustedLng = roundSlicedown(lng, slice);
        return new double[] { adjustedLat, adjustedLng - slice,
                adjustedLat - slice, adjustedLng };
    }

    private static String formatTuple(double[] values, int resolution) {
        StringBuffer s = new StringBuffer();
        String format = String.format("%%.%df", resolution);
        for (int i = 0; i < values.length; i++) {
            s.append(String.format(format, values[i]).replace(',','.'));
            if (i < values.length - 1) {
                s.append("|");
            }
        }
        return s.toString();
    }

    public static String compute(double lat, double lng, int resolution,
            int slice) {
        return formatTuple(computeTuple(lat, lng, resolution, slice),
                resolution);
    }

    public static List<String> computeSet(double lat, double lng,
            int resolution, double slice) {
        double[] primaryBox = computeTuple(lat, lng, resolution, slice);
        slice = slice * Math.pow(10, -resolution);
        List<String> set = new ArrayList<String>();
        for (int i = -1; i < 2; i++) {
            double latDelta = slice * i;
            for (int j = -1; j < 2; j++) {
                double lngDelta = slice * j;
                double[] adjustedBox = new double[] { primaryBox[0] + latDelta,
                        primaryBox[1] + lngDelta, primaryBox[2] + latDelta,
                        primaryBox[3] + lngDelta };
                set.add(formatTuple(adjustedBox, resolution));
            }
        }
        return set;
    }
}
于 2010-02-01T02:17:21.663 に答える
0

私はジオハッシュを使用してGAEプロジェクトに取り組んでいましたが、このPythonライブラリが私に代わってトリックを行いました:http://mappinghacks.com/code/geohash.py.txt

于 2010-02-01T03:00:09.673 に答える
-1

回答が遅れて申し訳ありませんが、しばらくこのページに戻りませんでした。Geoboxアプローチを使用したGeoDaoの実装は、次のようになります。

public class GeoDaoImpl extends DaoImpl<T extends GeoModel> {

    // geobox configs are: resolution, slice, use set (1 = true)
    private final static int[][] GEOBOX_CONFIGS = 
        { { 4, 5, 1 },
          { 3, 2, 1 },
          { 3, 8, 0 },
          { 3, 16, 0 },
          { 2, 5, 0 } };

    public GeoDaoImpl(Class<T> persistentClass) {
        super(persistentClass);
    }

    public List<T> findInGeobox(double lat, double lng, int predefinedBox, String filter, String ordering, int offset, int limit) {
        return findInGeobox(lat, lng, GEOBOX_CONFIGS[predefinedBox][0], GEOBOX_CONFIGS[predefinedBox][1], filter, ordering, offset, limit);     
    }

    public List<T> findInGeobox(double lat, double lng, int resolution, int slice, String filter, String ordering, int offset, int limit) {
        String box = Geobox.compute(lat, lng, resolution, slice);
        if (filter == null) {
            filter = "";
        } else {
            filter += " && ";
        }
        filter += "geoboxes=='" + box + "'";        
        return super.find(persistentClass, filter, ordering, offset, limit);
    }

    public List<T> findNearest(final double lat, final double lng, String filter, String ordering, int offset, int limit) {
        LinkedHashMap<String, T> uniqueList = new LinkedHashMap<String, T>();
        int length = offset + limit;
        for (int i = 0; i < GEOBOX_CONFIGS.length; i++) {       
            List<T> subList = findInGeobox(lat, lng, i, filter, ordering, 0, limit);
            for (T model : subList) {
                uniqueList.put(model.getId(), model);
            }
            if (uniqueList.size() >= length) {
                break;
            }
        }

        List<T> list = new ArrayList<T>();
        int i = 0;
        for (String key : uniqueList.keySet()) {
            if (i >= offset && i <= length) {
                list.add(uniqueList.get(key));
            }
            i++;
        }

        Collections.sort(list, new Comparator<T>() {
            public int compare(T model1, T model2) {                
                double distance1 = Geoutils.distFrom(model1.getLatitude(), model1.getLongitude(), lat, lng);
                double distance2 = Geoutils.distFrom(model2.getLatitude(), model2.getLongitude(), lat, lng);
                return Double.compare(distance1, distance2);
            }
        });

        return list;
    }

    @Override
    public void save(T model) {
        preStore(model);
        super.save(model);
    }

    private void preStore(T model) {
        // geoboxes are needed to find the nearest entities and sort them by distance
        List<String> geoboxes = new ArrayList<String>();
        for (int[] geobox : GEOBOX_CONFIGS) {
             // use set
             if (geobox[2] == 1) {
                 geoboxes.addAll(Geobox.computeSet(model.getLatitude(), model.getLongitude(), geobox[0], geobox[1]));
             } else {
                 geoboxes.add(Geobox.compute(model.getLatitude(), model.getLongitude(), geobox[0], geobox[1]));
             }
        }
        model.setGeoboxes(geoboxes);
    }

}
于 2010-02-24T22:12:55.013 に答える