$topLeftLat = $_POST['topLeftLat'];
$topLefiLng = $_POST['topLeftLng'];
$bottomRightLat = $_POST['bottomRightLat'];
$bottomRightLng = $_POST['bottomRightLng'];
$zoom = $_POST['zoom'];
$params['bool']['filter'][]['bool']['must']=
[
[
"exists" => [
"field" => "location"
]
],
[
"geo_bounding_box" => [
"location" => [
"top_left" => $topLeftLat.','.$topLefiLng,
"bottom_right" => $bottomRightLat.','.$bottomRightLng
]
]
]
];
$query = ElasticObj::find();
$p = ($zoom > 10 )? 10 : 8-(6-$zoom);
$query->addAggregate('gridSplit', [
'geotile_grid' => [
'bounds' => [
"top_left" => $topLeftLat.','.$topLefiLng,
"bottom_right" => $bottomRightLat.','.$bottomRightLng
],
"field" => "location",
"precision" => $p,
"size" => 65535,
"shard_size" => 65535
],
'aggs' => [
'gridCentroid' => [
'geo_centroid' => [
'field' => 'location'
]
]
]
]);
$query->query($params);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$aggregations = $dataProvider->getAggregations();
SELECT s.* ,st.`name` AS type_name , group_concat(DISTINCT benefits.name SEPARATOR ' ') as concat_bn, st.alias as spot_type_alias, benefits.alias as benefit_alias, CONCAT(" ", group_concat(DISTINCT benefits.id SEPARATOR ' ') ," ") as concat_bn_id,
// для полей s.name , s.track, st.name , st.alias ,benefits.name , benefits.alias в каждой таблице создаем полнотекстовый индекс.
//
// тут считаем релевантность запроса
MATCH(s.name , s.track) AGAINST('+$query') as score,
MATCH(st.name , st.alias) AGAINST('+$query') as stcore,
MATCH(benefits.name , benefits.alias) AGAINST('+$query') as bncore,
( // тут считаем расстояние до точки (тк я ищу точки ) (опционально)
6371 *
acos(cos(radians($lat)) *
cos(radians(s.lat)) *
cos(radians(s.lng) -
radians($lng)) +
sin(radians($lat)) *
sin(radians(s.lat)))
) AS distance
FROM `spots` s
// прикручиваем связь один к одному для поиска по типу из другой таблицы
JOIN `spot_type` st ON s.id_spot_type = st.id
// прикручиваем сводную таблицу для связи многие ко многим для поиска по типам плюшек на точке
join spots_benefits
on spots_benefits.spot = s.id
join benefits
on benefits.id = spots_benefits.benefit
where
//собственно сам поиск
MATCH(s.name, s.track) AGAINST('+$query')
OR MATCH(st.name, st.alias) AGAINST('+$query')
OR MATCH(benefits.name, benefits.alias) AGAINST('+$query')
// групируем элементы из сводных таблиц в одно поле груп_конкат
group by s.id
// ищем по только те что были добавлены в фильтр (опционально) типов
HAVING concat_bn_id like "% 1 %" AND concat_bn_id like '% 2 %' AND s.id_spot_type = 2
// сортируем сначала по релевантности, а потом уже по расстоянию
ORDER BY (score + stcore + bncore) DESC, distance ASC
SET @home = ST_GeomFromText('LINESTRING(
//Список наших точек через которые идет маршрут
53.862263 27.483486,
53.871521 27.493636,
53.875594 27.496447,
53.880938 27.500744,
53.882699 27.505121,
53.884246 27.504435,
53.891446 27.500293,
53.896630 27.497375,
53.905348 27.496302,
53.912531 27.495487,
53.918726 27.496882)');
SELECT *, ST_AsText(geo) as Coord,
// Дистанция считается странно получается вроде правильно , но не уверен насчет точности .
// В оригинале в доках написано умножать ее на .001 для км и .00067... для миль
// но у меня так не работало и показывало до объекта 0,003км хотя по факту до него 300м вот я решил
умножать ее на 100 (хотя хз может оно там сантиметрах считает)
ST_DISTANCE(@home, geo) * 100 AS dist
FROM dots
// дистанция от маршрута в радиусе которой нам нужны точки (в км )
HAVING dist < 1
ORDER BY dist
LIMIT 30