From b3f42e62af698a67c2250533c437569559f1fdf9 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 29 Dec 2016 07:49:51 +0900 Subject: Initial commit :four_leaf_clover: --- src/api/endpoints/posts/search.js | 138 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 src/api/endpoints/posts/search.js (limited to 'src/api/endpoints/posts/search.js') diff --git a/src/api/endpoints/posts/search.js b/src/api/endpoints/posts/search.js new file mode 100644 index 0000000000..0f214ef7ae --- /dev/null +++ b/src/api/endpoints/posts/search.js @@ -0,0 +1,138 @@ +'use strict'; + +/** + * Module dependencies + */ +import * as mongo from 'mongodb'; +import Post from '../../models/post'; +import serialize from '../../serializers/post'; +const escapeRegexp = require('escape-regexp'); + +/** + * Search a post + * + * @param {Object} params + * @param {Object} me + * @return {Promise} + */ +module.exports = (params, me) => + new Promise(async (res, rej) => +{ + // Get 'query' parameter + let query = params.query; + if (query === undefined || query === null || query.trim() === '') { + return rej('query is required'); + } + + // Get 'offset' parameter + let offset = params.offset; + if (offset !== undefined && offset !== null) { + offset = parseInt(offset, 10); + } else { + offset = 0; + } + + // Get 'max' parameter + let max = params.max; + if (max !== undefined && max !== null) { + max = parseInt(max, 10); + + // From 1 to 30 + if (!(1 <= max && max <= 30)) { + return rej('invalid max range'); + } + } else { + max = 10; + } + + // If Elasticsearch is available, search by it + // If not, search by MongoDB + (config.elasticsearch.enable ? byElasticsearch : byNative) + (res, rej, me, query, offset, max); +}); + +// Search by MongoDB +async function byNative(res, rej, me, query, offset, max) { + const escapedQuery = escapeRegexp(query); + + // Search posts + const posts = await Post + .find({ + text: new RegExp(escapedQuery) + }, { + sort: { + _id: -1 + }, + limit: max, + skip: offset + }) + .toArray(); + + // Serialize + res(await Promise.all(posts.map(async post => + await serialize(post, me)))); +} + +// Search by Elasticsearch +async function byElasticsearch(res, rej, me, query, offset, max) { + const es = require('../../db/elasticsearch'); + + es.search({ + index: 'misskey', + type: 'post', + body: { + size: max, + from: offset, + query: { + simple_query_string: { + fields: ['text'], + query: query, + default_operator: 'and' + } + }, + sort: [ + { _doc: 'desc' } + ], + highlight: { + pre_tags: [''], + post_tags: [''], + encoder: 'html', + fields: { + text: {} + } + } + } + }, async (error, response) => { + if (error) { + console.error(error); + return res(500); + } + + if (response.hits.total === 0) { + return res([]); + } + + const hits = response.hits.hits.map(hit => new mongo.ObjectID(hit._id)); + + // Fetxh found posts + const posts = await Post + .find({ + _id: { + $in: hits + } + }, {}, { + sort: { + _id: -1 + } + }) + .toArray(); + + posts.map(post => { + post._highlight = response.hits.hits.filter(hit => post._id.equals(hit._id))[0].highlight.text[0]; + }); + + // Serialize + res(await Promise.all(posts.map(async post => + await serialize(post, me)))); + }); +} -- cgit v1.3.1-freya