123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- "use strict";
- var Promise = require('bluebird'),
- _ = require('lodash'),
- path = require('path'),
- searchIndex = require('search-index'),
- stopWord = require('stopword');
- /**
- * Search Model
- */
- module.exports = {
- _si: null,
- /**
- * Initialize Search model
- *
- * @param {Object} appconfig The application config
- * @return {Object} Search model instance
- */
- init(appconfig) {
- let self = this;
- let dbPath = path.resolve(ROOTPATH, appconfig.datadir.db, 'search-index');
- searchIndex({
- deletable: true,
- fieldedSearch: true,
- indexPath: dbPath,
- logLevel: 'error',
- stopwords: stopWord.getStopwords(appconfig.lang).sort()
- }, (err, si) => {
- if(err) {
- winston.error('Failed to initialize search-index.', err);
- } else {
- self._si = Promise.promisifyAll(si);
- }
- });
- return self;
- },
- find(terms) {
- let self = this;
- terms = _.chain(terms)
- .deburr()
- .toLower()
- .trim()
- .replace(/[^a-z0-9 ]/g, '')
- .value();
- let arrTerms = _.chain(terms)
- .split(' ')
- .filter((f) => { return !_.isEmpty(f); })
- .value();
- return self._si.searchAsync({
- query: {
- AND: [{ '*': arrTerms }]
- },
- pageSize: 10
- }).get('hits').then((hits) => {
- if(hits.length < 5) {
- return self._si.matchAsync({
- beginsWith: terms,
- threshold: 3,
- limit: 5,
- type: 'simple'
- }).then((matches) => {
- return {
- match: hits,
- suggest: matches
- };
- });
- } else {
- return {
- match: hits,
- suggest: []
- };
- }
- });
- },
- /**
- * Add a document to the index
- *
- * @param {Object} content Document content
- * @return {Promise} Promise of the add operation
- */
- add(content) {
- let self = this;
- return self._si.searchAsync({
- query: {
- AND: [{ 'entryPath': [content.entryPath] }]
- }
- }).then((results) => {
- if(results.totalHits > 0) {
- let delIds = _.map(results.hits, 'id');
- return self._si.delAsync(delIds);
- } else {
- return true;
- }
- }).then(() => {
- return self._si.addAsync({
- entryPath: content.entryPath,
- title: content.meta.title,
- subtitle: content.meta.subtitle || '',
- parent: content.parent.title || '',
- content: content.text || ''
- }, {
- fieldOptions: [{
- fieldName: 'entryPath',
- searchable: true,
- weight: 2
- },
- {
- fieldName: 'title',
- nGramLength: [1, 2],
- searchable: true,
- weight: 3
- },
- {
- fieldName: 'subtitle',
- searchable: true,
- weight: 1,
- store: false
- },
- {
- fieldName: 'parent',
- searchable: false,
- },
- {
- fieldName: 'content',
- searchable: true,
- weight: 0,
- store: false
- }]
- }).then(() => {
- winston.info('Entry ' + content.entryPath + ' added/updated to index.');
- return true;
- }).catch((err) => {
- winston.error(err);
- });
- }).catch((err) => {
- winston.error(err);
- });
- }
- };
|