简体   繁体   中英

Elastic Search geo distance query with MySQL relationships

I would like to make a Elastic Search geo distance query in my MySQL database with relationships. I have one table with the location data and then I have another tables that have relationships with the locations table. I know that NoSQL databases like Elastic Search is not optimised for relationships like this, but is it possible?

This is what my database schema looks like:

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;

Here's my index mapping(I use the official Elasticsearch client for PHP ):

<?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' => [
                ],
            ],
        ],
    ],
];

I would like to make a query on locations and posts(and comment (= two joins away) as well if that is not too bad for performance) that I can filter and sort by geo distance.

I have tried with a query like this:

[
    '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,
                        ],
                    ],
                ],
            ],
        ],
    ],
]

It works, but obviously filters out everything except locations that has the location data. How can I include the related posts and possibly even comments into the query?

Thanks!

I didn't find any good solutions to do this, but I solved it by simply adding a location field on both posts and comments and then getting the coordinates of the related location when I push it into the Elasticsearch index.

Maybe not an optimal solution, but it works good and it is very fast as the index is kept completely flat. As long as I make sure the changes in the location coordinates propagate to the related posts and comments I don't see any real issues with this approach except that it's not so clean to store duplicated data in the index.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM