ms-dred
@ms-dred
Вечно что то не то и что то не так...

Как сократить время выполнения сложного текстового запроса?

Чего уже только не перепробывал =(
Есть коллекция со следующей структурой
var schema = new Schema({
	public: 			{ type: Number,	default: 1 },
	createdAt: 		{ type: Date,		default: Date.now },
	updatedAt: 		{ type: Date,		default: Date.now },
	indexAt: 			{ type: Date,		default: Date.now },
	owner: 			{ type: mongoose.Schema.Types.ObjectId, ref: 'Users', required: !0 },
	allow:			{ type: Number, 	default: 0 },
	stats: {
		like: 			{ type: Number, 	default: 0 },
		view: 		{ type: Number, 	default: 0 }
	},
	pixels: 			{ type: Array },
	exif:				{ type: Object },
	likes: 			[{ type: mongoose.Schema.Types.ObjectId, ref: 'Users'}], 

	comments: [{
		owner: 		{ type: mongoose.Schema.Types.ObjectId, ref: 'Users' },
		post: 		{ type: String, trim: !0 },
		public: 		{ type: Number, default: 0 },
		createdAt: 	{ type: Date, default: Date.now }
	}],

	catalog: 			{ type: mongoose.Schema.Types.ObjectId, ref: 'Catalogs', required: !0 },
	size: {
		width: 		{ type: Number, 	required: !0 },
		height: 		{ type: Number, 	required: !0 }
	},
	tags: 			{ type: Array, 		required: !0 },

	tagsRu:			{ type: Array, 		required: !1 },
	tagsEn:			{ type: Array, 		required: !1 },
	
	subscribe:		{ type: String },
	image: 			{ type: String, 	required: !0 },
	domain: 			{ type: String, 	default: config.domain.photos },
	title: 			{ type: String,		trim: !0 },
	url: 				{ type: String, 	trim: !0, required: !0, unique: !0 }
})


Важное поле subscribe, в него помещаются все теги и по нему же находятся документы
Создан индекс
schema.index({ subscribe: 'text', title: 'text', url: 'text' })


Жизнено необходимо выплюнуть документ с уже готовой структурой и поэтому приходится формировать ее при aggregate
Вот такой запрос получился
return Documents
        .aggregate([
            { $match: { public: { $gte: 2 }, $text: { $search: 'сам запрос' } }},
            { $sort: { score: { $meta: "textScore" } } },
            { $skip: request.skip },
            { $limit: request.limit },
            {
                $lookup: {
                    from: 'users',
                    localField: 'owner',
                    foreignField: '_id',
                    as: 'owner'
                }
            }, {
                $project: {
                    _id: 1,
                    image: { $concat: ['$domain', 'o/', '$image', '?route=thumb&h=350'] },
                    large: { $concat: ['$domain', 'o/', '$image', '?route=mid&h=750'] },
                    href: { $concat: [request.CONST.href, 'photo/', '$url', '.html'] },
                    hrefClass: config.hrefAddClass,
                    tags: { $slice: ['$tags', 12] },
                    size: {
                        width: { $trunc: { $multiply: [ { $divide: ['$size.width', '$size.height'] }, 350] } },
                        height: { $trunc: 350 }
                    },
                    style: {
                        $concat: [
                            'background-color: rgb(',
                            { $toLower: { $arrayElemAt: [ '$pixels.rgb.r', 0 ] } }, ',',
                            { $toLower: { $arrayElemAt: [ '$pixels.rgb.g', 0 ] } }, ',',
                            { $toLower: { $arrayElemAt: [ '$pixels.rgb.b', 0 ] } }, ')'
                        ]
                    },
                    owner: { $arrayElemAt: [ '$owner', 0 ] },
                    likes: 1,
                    indexAt: 1,
                    title: 1
                }
                
            }, {
                $group: {
                    _id: "$_id",
                    image: { $first: '$image' },
                    large: { $first: '$large' },
                    href: { $first: '$href' },
                    hrefClass: { $first: '$hrefClass' },
                    tags: { $first: '$tags' },
                    size: { $first: '$size' },
                    style: { $first: '$style' },
                    owner: { $first: {
                        _id: '$owner._id',
                        name: '$owner.name',
                        avatar: { $concat: ['background-image:url(', '$owner.avatar', ')'] },
                        href: { $concat: [request.CONST.href, '$owner.username', '/'] }
                    } },
                    likes: { $first: '$likes' },
                    indexAt: { $first: '$indexAt' },
                    title: { $first: '$title' }
                }
            },
            { $sort: { score: { $meta: "textScore" } } } // Дожимаю результаты, так как после $group бывает сверху шлак вылазит
        ])
        .then()


Так вот, в коллекции с документами где "Запрос" встречается редко (к примеру таких домументов 50-100) все просто замечательно работает, а вот там где тысячи результатов в которых присутствует "Запрос", выборка работает просто адово долго, 5-6 секунд, но уверен что есть и более долгие запросы. К тому же все это очень сильно нагружает ВПС.
Если делать эту же выборку, но сортировать по полю indexAt, все работает отлично что там что здесь, но сами результаты оставляют желать лучшего, потому что, то что ищет человек может находиться в самом низу, а в верху получить схожие записи по его запросу.

Что же делать? Может со структурой что то не так? Или может отдельную коллекцию под запросы выделить (хотя даже не уверен что, что то изменится). Может разбить на два запроса? Любая помощь пойдет на пользу! Я уже пол года мучаюсь.
  • Вопрос задан
  • 178 просмотров
Решения вопроса 1
ms-dred
@ms-dred Автор вопроса
Вечно что то не то и что то не так...
При разбитии запроса на два, получилось сократить время, но не на столько на сколько хотелось бы.
Был взять запрос выполняющийся за 4.9ms и удалось сократить его до 1.1ms
return Wallpapers
        .aggregate([
            { $match: { public: { $gte: 2 }, $text: { $search: 'сам запрос' } } },
            { $project: { _id: 1, score: { $meta: "textScore" } } },
            { $sort: request.sort },
            { $skip: request.skip },
            { $limit: request.limit },
            { $group: { _id: null, uid: { $push: '$_id' }}}
        ]).then(e => {
            return e.length ? Wallpapers.aggregate([
                { $match: { _id: { $in: e[0].uid }} },
                {
                    $lookup: {
                        from: 'users',
                        localField: 'owner',
                        foreignField: '_id',
                        as: 'owner'
                    }
                },
                { $project: {
                    _id: 1,
                    image: { $concat: ['$domain', 'o/', '$image', '?route=thumb&h=350'] },
                    large: { $concat: ['$domain', 'o/', '$image', '?route=mid&h=750'] },
                    href: { $concat: [request.CONST.href, 'wallpaper/', '$url', '.html'] },
                    hrefClass: config.hrefAddClass,
                    tags: { $slice: ['$tags', 12] },
                    size: {
                        width: { $trunc: { $multiply: [ { $divide: ['$size.width', '$size.height'] }, 350] } },
                        height: { $trunc: 350 }
                    },
                    style: {
                        $concat: [
                            'background-color: rgb(',
                            { $toLower: { $arrayElemAt: [ '$pixels.rgb.r', 0 ] } }, ',',
                            { $toLower: { $arrayElemAt: [ '$pixels.rgb.g', 0 ] } }, ',',
                            { $toLower: { $arrayElemAt: [ '$pixels.rgb.b', 0 ] } }, ')'
                        ]
                    },
                    owner: { $arrayElemAt: [ '$owner', 0 ] },
                    likes: 1,
                    indexAt: 1,
                    title: 1,
                }}, {
                    $group: {
                        _id: "$_id",
                        image: { $first: '$image' },
                        large: { $first: '$large' },
                        href: { $first: '$href' },
                        hrefClass: { $first: '$hrefClass' },
                        tags: { $first: '$tags' },
                        size: { $first: '$size' },
                        style: { $first: '$style' },
                        owner: { $first: {
                            _id: '$owner._id',
                            name: '$owner.name',
                            avatar: { $concat: ['background-image:url(', '$owner.avatar', ')'] },
                            href: { $concat: [request.CONST.href, '$owner.username', '/'] }
                        } },
                        likes: { $first: '$likes' },
                        indexAt: { $first: '$indexAt' },
                        title: { $first: '$title' }
                    }
                }
            ]).then() : []
        })


Если будут у кого другие варианты, напишите пожалуйста =)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через TM ID
Похожие вопросы
ANY.RUN Ульяновск
от 50 000 до 70 000 руб.
BP Mobile Москва
До 250 000 руб.
Suntegy Санкт-Петербург
от 100 000 руб.
21 сент. 2018, в 16:29
1000 руб./в час
21 сент. 2018, в 16:05
6000 руб./за проект