search.js 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. "use strict";
  2. var Promise = require('bluebird'),
  3. _ = require('lodash'),
  4. path = require('path'),
  5. searchIndex = require('search-index'),
  6. stopWord = require('stopword');
  7. /**
  8. * Search Model
  9. */
  10. module.exports = {
  11. _si: null,
  12. /**
  13. * Initialize Search model
  14. *
  15. * @param {Object} appconfig The application config
  16. * @return {Object} Search model instance
  17. */
  18. init(appconfig) {
  19. let self = this;
  20. let dbPath = path.resolve(ROOTPATH, appconfig.datadir.db, 'search-index');
  21. searchIndex({
  22. deletable: true,
  23. fieldedSearch: true,
  24. indexPath: dbPath,
  25. logLevel: 'error',
  26. stopwords: stopWord.getStopwords(appconfig.lang).sort()
  27. }, (err, si) => {
  28. if(err) {
  29. winston.error('Failed to initialize search-index.', err);
  30. } else {
  31. self._si = Promise.promisifyAll(si);
  32. }
  33. });
  34. return self;
  35. },
  36. find(terms) {
  37. let self = this;
  38. terms = _.chain(terms)
  39. .deburr()
  40. .toLower()
  41. .trim()
  42. .replace(/[^a-z0-9 ]/g, '')
  43. .split(' ')
  44. .filter((f) => { return !_.isEmpty(f); })
  45. .value();
  46. return self._si.searchAsync({
  47. query: {
  48. AND: [{ '*': terms }]
  49. },
  50. pageSize: 10
  51. }).get('hits');
  52. },
  53. /**
  54. * Add a document to the index
  55. *
  56. * @param {Object} content Document content
  57. * @return {Promise} Promise of the add operation
  58. */
  59. add(content) {
  60. let self = this;
  61. return self._si.addAsync({
  62. entryPath: content.entryPath,
  63. title: content.meta.title,
  64. subtitle: content.meta.subtitle || '',
  65. parent: content.parent.title || '',
  66. content: content.text || ''
  67. }, {
  68. fieldOptions: [{
  69. fieldName: 'entryPath',
  70. searchable: true,
  71. weight: 2
  72. },
  73. {
  74. fieldName: 'title',
  75. nGramLength: [1, 2],
  76. searchable: true,
  77. weight: 3
  78. },
  79. {
  80. fieldName: 'subtitle',
  81. searchable: true,
  82. weight: 1,
  83. store: false
  84. },
  85. {
  86. fieldName: 'subtitle',
  87. searchable: false,
  88. },
  89. {
  90. fieldName: 'content',
  91. searchable: true,
  92. weight: 0,
  93. store: false
  94. }]
  95. }).then(() => {
  96. winston.info('Entry ' + content.entryPath + ' added to index.');
  97. }).catch((err) => {
  98. winston.error(err);
  99. });
  100. }
  101. };