【问题标题】:Elastic Search geo distance query with MySQL relationships具有 MySQL 关系的 Elastic Search 地理距离查询
【发布时间】:2016-11-24 01:28:58
【问题描述】:

我想在我的 MySQL 数据库中使用关系进行 Elastic Search 地理距离查询。我有一个包含位置数据的表,然后我有另一个与位置表有关系的表。我知道像 Elastic Search 这样的 NoSQL 数据库并没有针对这种关系进行优化,但有可能吗?

这是我的数据库架构的样子:

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):

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

我想查询位置和帖子(以及评论(= 两个连接),如果这对性能来说还不错的话),我可以按地理距离进行过滤和排序。

我尝试过这样的查询:

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

它有效,但显然会过滤掉除具有位置数据的位置之外的所有内容。如何将相关帖子甚至可能包括 cmets 包含到查询中?

谢谢!

【问题讨论】:

  • 如您所述,大多数 NoSQL 数据存储倾向于避免使用关系模型。但是,无论如何,您都在尝试对它们应用关系模型。文档数据存储(例如 MongoDB 和 Elasticsearch)因denormalizing 数据而蓬勃发展,因此只有一个地方可以查看。如果您有效地对数据进行了连接并将其转储到单个文档中(因此帖子将包含一个 cmets 数组),那么这将提供所需的行为。或者,您可能希望将帖子作为父级,将 cmets 作为子级的父/子文档。
  • 是的,谢谢您的意见。我认为像我所做的那样对数据进行非规范化是一个很好的解决方案。

标签: php mysql database elasticsearch


【解决方案1】:

我没有找到任何好的解决方案来解决这个问题,但我通过简单地在帖子和 cmets 上添加一个位置字段,然后在我将其推送到 Elasticsearch 索引时获取相关位置的坐标来解决它。

也许不是最佳解决方案,但它工作得很好,而且速度非常快,因为索引完全保持平坦。只要我确保位置坐标的更改传播到相关的帖子和​​ cmets,我就看不出这种方法有任何实际问题,只是在索引中存储重复数据不太干净。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-27
    • 2019-05-30
    • 2012-09-11
    • 2012-12-12
    • 1970-01-01
    • 2019-06-13
    相关资源
    最近更新 更多