2016-07-20 12 views
0

私は、Elastic Searchジオの距離のクエリを、関係を持つMySQLデータベースで作成したいと考えています。私は場所のデータと1つのテーブルを持って、私は場所のテーブルとの関係を持っている別のテーブルがあります。私はElastic SearchのようなNoSQLデータベースはこのような関係に最適化されていないことを知っていますが、それは可能ですか?エラスティック検索MySQLの関係を持つジオの距離のクエリ

これは私のデータベーススキーマは、次のようになります。

<?php 
return [ 
    'index' => 'foodie', 
    'body' => [ 
     'mappings' => [ 
      'locations' => [ 
       'properties' => [ 
        'id' => ['type' => 'string', 'index' => 'not_analyzed'], 
        'name' => ['type' => 'string'], 
        'description' => ['type' => 'string'], 
        'location' => ['type' => 'geo_point'], 
       ], 
      ], 
      'posts' => [ 
       'properties' => [ 
        'id' => ['type' => 'string', 'index' => 'not_analyzed'], 
        'author' => ['type' => 'string', 'index' => 'not_analyzed'], 
        'location_id' => ['type' => 'string', 'index' => 'not_analyzed'], 
        'title' => ['type' => 'string'], 
        'text' => ['type' => 'string'], 
       ], 
      ], 
      'comments' => [ 
       'properties' => [ 
        'id' => ['type' => 'string', 'index' => 'not_analyzed'], 
        'author' => ['type' => 'string', 'index' => 'not_analyzed'], 
        'post_id' => ['type' => 'string', 'index' => 'not_analyzed'], 
        'title' => ['type' => 'string'], 
        'text' => ['type' => 'string'], 
       ], 
      ] 
     ], 
     'settings' => [ 
      'analysis' => [ 
       'filter' => [ 
       ], 
       'analyzer' => [ 
       ], 
      ], 
     ], 
    ], 
]; 

私は場所やポスト(上のクエリを作成したいと思います:

CREATE TABLE `locations` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `description` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `lng` decimal(12,8) NOT NULL, 
    `lat` decimal(12,8) NOT NULL, 
    `deleted_at` timestamp NULL DEFAULT NULL, 
    `created_at` timestamp NULL DEFAULT NULL, 
    `updated_at` timestamp NULL DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

CREATE TABLE `posts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `author` int(10) unsigned NOT NULL, 
    `location_id` int(10) unsigned NOT NULL, 
    `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `text` text COLLATE utf8_unicode_ci NOT NULL, 
    `deleted_at` timestamp NULL DEFAULT NULL, 
    `created_at` timestamp NULL DEFAULT NULL, 
    `updated_at` timestamp NULL DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `posts_author_foreign` (`author`), 
    KEY `posts_location_id_foreign` (`location_id`), 
    CONSTRAINT `posts_author_foreign` FOREIGN KEY (`author`) REFERENCES `users` (`id`), 
    CONSTRAINT `posts_location_id_foreign` FOREIGN KEY (`location_id`) REFERENCES `locations` (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=174 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

CREATE TABLE `comments` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `post_id` int(10) unsigned NOT NULL, 
    `author` int(10) unsigned NOT NULL, 
    `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    `text` text COLLATE utf8_unicode_ci NOT NULL, 
    `deleted_at` timestamp NULL DEFAULT NULL, 
    `created_at` timestamp NULL DEFAULT NULL, 
    `updated_at` timestamp NULL DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `comments_author_foreign` (`author`), 
    KEY `comments_post_id_foreign` (`post_id`), 
    CONSTRAINT `comments_author_foreign` FOREIGN KEY (`author`) REFERENCES `users` (`id`), 
    CONSTRAINT `comments_post_id_foreign` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=238 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

ここに私のインデックスマッピングが(私はofficial Elasticsearch client for PHPを使用)です私はフィルタリングして地理的距離で並べ替えることができます。

私はこのようなクエリを試してみました:

[ 
    'index' => 'index_name', 
    'type' => [ 
     0 => 'posts', 
     1 => 'locations', 
     2 => 'comments' 
    ], 
    'body' => [ 
     'from' => 0, 
     'size' => 10, 
     'query' => [ 
      'bool' => [ 
       'must' => [ 
        'multi_match' => [ 
         'query' => 'search string', 
         'fields' => [ 
          0 => 'title', 
          1 => 'text', 
          2 => 'name', 
          3 => 'description', 
         ], 
         'fuzziness' => 'AUTO', 
         'operator' => 'and', 
        ], 
       ], 
       'filter' => [ 
        'geo_distance' => [ 
         'distance' => '100m', 
         'location' => [ 
          'lat' => 79.861, 
          'lon' => 107.31, 
         ], 
        ], 
       ], 
      ], 
     ], 
    ], 
] 

それは動作しますが、明らかに位置データを持っている場所以外のすべてを除外します。どのようにして関連する投稿やコメントをクエリに含めることができますか?

ありがとうございます!

+1

ご存知のように、ほとんどのNoSQLデータストアは、リレーショナルモデルを避ける傾向があります。しかし、とにかく関係モデルをそれらに適用しようとしています。ドキュメントデータストア(MongoDBやElasticsearchなど)はデータを[非正規化](https://en.wikipedia.org/wiki/Denormalization)すると1つの場所しか見ることができません。あなたが効果的にデータの結合を行い、それを単一のドキュメントにダンプした場合(つまり、投稿にはコメントの配列があります)、これにより望ましい動作が得られます。あるいは、親と子の文書を親として、投稿を子としてもよいでしょう。 – pickypg

+0

はい、ありがとうございます。私が行ったようにデータを非正規化すると、私にとっては良い解決策になると思います。 – Pelmered

答えて

0

私はこれを行うには良い解決策を見つけられませんでしたが、記事とコメントの両方に位置フィールドを追加し、それをElasticsearchインデックスにプッシュすると関連する場所の座標を取得するだけで解決しました。

おそらく最適な解決策ではないかもしれませんが、それはうまく機能し、インデックスが完全に平坦に保たれるので非常に高速です。場所の座標の変更が関連する投稿やコメントに伝わることを確認している限り、重複したデータをインデックスに保存するのはあまりクリーンではないという点を除いて、このアプローチでは本当の問題はありません。

関連する問題