Два разных подхода для работы c tags
Добавлено: 2018.01.01, 14:22
ЧТО НУЖНО:
ЕСТЬ модель Sale, для нее нужно хранить tags для SMART поиска и отображения информации. класс Tags имеет основные свойства id, name, color, type.
ПРЕДЫСТОРИЯ:
viewtopic.php?f=19&t=45265&hilit=tags
Мне было рекомендовано хранить tags в связанной таблице при помощи связи один-ко-многим. Я так и сделал.
МЕТОД ПЕРВЫЙ (КЛАССИЧЕСКИЙ):
1 . создаем Class RealTags хранит именно соответствие записи id основной таблице и id Tags;
ВНИМАНИЕ: НЕ ИСПОЛЬЗУЮ ее как промежуточную таблицу (т.к. записей Tags немного (порядка 100)) я его кеширую (ON CHANGE) и использую как CONSTANT массив [ 1 => ['name', 'color,'type'], 2=> и т.д.] в итоге вместо tag->name имею $tag['name'];
МИНУСЫ: т.к. одной Sale соответствует в среднем 5 tags, то если sale->id = 10.000.000; то realtags->id = 5*10000000.
в итоге записи будут выглядеть так:
Сейчас, когда количество записей sale 30.000, tags 130.000 (даже если я буду удалять sale и связанные tags, AUTO_INCREMENT будет все равно выставлять большие индексы, которые хранятся в базе и имеют свой (увеличивающийся) вес).
2. Поиск по Tags
МЕТОД ВТОРОЙ:
1. Храним tags, как текстовое поле $sale->tags_id = ",2,6,11,56,99,";
для упаковки и распаковки использовать простые методы
запихнуть в beforeSave и afterFind (или магические getTags и setTags) и работать, как с массивом.
2. Поиск:
МИНУСЫ: пока не нашел(сравнивал в основном время запроса с join И без JOIN).
ПЛЮСЫ:
1.нет минусов первого метода, разница в размерах таблицы Sale c tags_id и без нее 0,2Mб. ( но модели RealTags нет и таблицы Mysql весом 8.5 Mб.)
2. возможно поиск будет гораздо быстрее с elasticsearch.
Ваши комментарии?
ЕСТЬ модель Sale, для нее нужно хранить tags для SMART поиска и отображения информации. класс Tags имеет основные свойства id, name, color, type.
ПРЕДЫСТОРИЯ:
viewtopic.php?f=19&t=45265&hilit=tags
Мне было рекомендовано хранить tags в связанной таблице при помощи связи один-ко-многим. Я так и сделал.
МЕТОД ПЕРВЫЙ (КЛАССИЧЕСКИЙ):
1 . создаем Class RealTags хранит именно соответствие записи id основной таблице и id Tags;
Код: Выделить всё
public function getTags()
{
return $this->hasMany(RealTags::className(), ['sale_id' => 'id']);
}
МИНУСЫ: т.к. одной Sale соответствует в среднем 5 tags, то если sale->id = 10.000.000; то realtags->id = 5*10000000.
в итоге записи будут выглядеть так:
Код: Выделить всё
id | sale_id | tag_id
50.000.000 10.000.000 2
50.000.001 10.000.000 6
50.000.002 10.000.000 11
50.000.003 10.000.000 56
50.000.004 10.000.000 99
2. Поиск по Tags
Код: Выделить всё
$query->andWhere([RealTags::tableName() . '.tag_id' => $tags_array]);
$query->groupBy("s.id");
$query->having(new Expression("count(*)=".count($tags_array)));
1. Храним tags, как текстовое поле $sale->tags_id = ",2,6,11,56,99,";
для упаковки и распаковки использовать простые методы
Код: Выделить всё
class Tags extends Activerecord
{ ...
public static function convertToString(array $arr)
{
return ",".implode(",", $arr).",";
}
public static function convertToArray($string)
{
if ($string) return explode(",", preg_replace("/^,|,$/", "", $string));
}
}
2. Поиск:
Код: Выделить всё
foreach ($tags_sale as $tag) {
$query->andWhere(['like', 's.tags_id', "," . $tag . ","]);
}
ПЛЮСЫ:
1.нет минусов первого метода, разница в размерах таблицы Sale c tags_id и без нее 0,2Mб. ( но модели RealTags нет и таблицы Mysql весом 8.5 Mб.)
2. возможно поиск будет гораздо быстрее с elasticsearch.
Ваши комментарии?