search.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /**
  2. * Search
  3. */
  4. var elasticsearch = require('elasticsearch'),
  5. debug = require('debug')('crowi:lib:search');
  6. function SearchClient(crowi, esUri) {
  7. this.esUri = esUri;
  8. this.crowi = crowi;
  9. var uri = this.parseUri(this.esUri);
  10. this.host = uri.host;
  11. this.index_name = uri.index_name;
  12. this.client = new elasticsearch.Client({
  13. host: this.host,
  14. });
  15. this.mappingFile = crowi.resourceDir + 'search/mappings.json';
  16. //this.Page = crowi.model('Page');
  17. //this.Config = crowi.model('Config');
  18. //this.config = crowi.getConfig();
  19. }
  20. SearchClient.prototype.parseUri = function(uri) {
  21. if (!(m = uri.match(/^elasticsearch:\/\/([^:]+):([^\/]+)\/(.+)$/))) {
  22. throw new Error('Invalid ELASTICSEARCH_URI format. Should be elasticsearch://host:port/index_name');
  23. }
  24. return {
  25. host: m[1] + ':' + m[2],
  26. index_name: m[3],
  27. };
  28. };
  29. SearchClient.prototype.buildIndex = function(uri) {
  30. return this.client.indices.create({
  31. index: this.index_name,
  32. body: require(this.mappingFile)
  33. });
  34. };
  35. SearchClient.prototype.prepareBodyForCreate = function(body, page) {
  36. if (!Array.isArray(body)) {
  37. throw new Error('Body must be an array.');
  38. }
  39. var command = {
  40. index: {
  41. _index: this.index_name,
  42. _type: 'page',
  43. _id: page._id.toString(),
  44. }
  45. };
  46. var document = {
  47. path: page.path,
  48. body: page.revision.body,
  49. username: page.creator.username,
  50. comment_count: page.commentCount,
  51. like_count: page.liker.length || 0,
  52. created_at: page.createdAt,
  53. updated_at: page.updatedAt,
  54. };
  55. body.push(command);
  56. body.push(document);
  57. };
  58. SearchClient.prototype.addPages = function(pages)
  59. {
  60. var self = this;
  61. var body = [];
  62. pages.map(function(page) {
  63. self.prepareBodyForCreate(body, page);
  64. });
  65. return this.client.bulk({
  66. body: body,
  67. });
  68. };
  69. SearchClient.prototype.addAllPages = function()
  70. {
  71. var self = this;
  72. var offset = 0;
  73. var Page = this.crowi.model('Page');
  74. var stream = Page.getStreamOfFindAll();
  75. var body = [];
  76. return new Promise(function(resolve, reject) {
  77. stream.on('data', function (doc) {
  78. if (!doc.creator || !doc.revision) {
  79. debug('Skipped', doc.path);
  80. return ;
  81. }
  82. debug('Prepare', doc);
  83. self.prepareBodyForCreate(body, doc);
  84. //debug('Data received: ', doc.path, doc.liker.length, doc.revision.body);
  85. }).on('error', function (err) {
  86. debug('Error stream:', err);
  87. // handle err
  88. }).on('close', function () {
  89. // all done
  90. debug('Close');
  91. debug('SEnd', body);
  92. // 最後に送信
  93. self.client.bulk({ body: body, })
  94. .then(function(res) {
  95. debug('Reponse from es:', res);
  96. return resolve(res);
  97. }).catch(function(err) {
  98. debug('Err from es:', err);
  99. return reject(err);
  100. });
  101. });
  102. });
  103. };
  104. module.exports = SearchClient;
  105. /*
  106. SearchClient.prototype.deleteIndex = function() {
  107. };
  108. */
  109. /*
  110. module.exports = function(crowi) {
  111. var elasticsearch = require('elasticsearch'),
  112. debug = require('debug')('crowi:lib:search'),
  113. Page = crowi.model('Page'),
  114. Config = crowi.model('Config'),
  115. config = crowi.getConfig(),
  116. TYPE_PAGE = 'page',
  117. SLOW_INTERVAL = 200, // 200ms interval.
  118. lib = {};
  119. // TODO: configurable
  120. var host = '127.0.0.1:9200';
  121. var index_name = 'crowi';
  122. var default_mapping_file = crowi.resourceDir + 'search/mappings.json';
  123. var client = new elasticsearch.Client({
  124. host: host,
  125. });
  126. lib.deleteIndex = function() {
  127. return client.indices.delete({
  128. index: index_name
  129. });
  130. };
  131. lib.buildIndex = function() {
  132. return client.indices.create({
  133. index: index_name,
  134. body: require(default_mapping_file)
  135. });
  136. };
  137. lib.rebuildIndex = function() {
  138. var self = this;
  139. return self.deleteIndex()
  140. .then(function(data) {
  141. return self.buildIndex();
  142. });
  143. };
  144. lib.addAllPages = function() {
  145. var offset = 0;
  146. var stream = Page.getStreamOfFindAll();
  147. var self = this;
  148. stream.on('data', function (doc) {
  149. if (!doc.creator || !doc.revision) {
  150. debug('Skipped', doc.path);
  151. return ;
  152. }
  153. var likeCount = doc.liker.length;
  154. var bookmarkCount = 0; // TODO
  155. var updated = doc.updatedAt; // TODO
  156. self.addPage(doc._id.toString(), doc.path, doc.revision.body, doc.creator.username, likeCount, bookmarkCount, updated, true)
  157. .then(function(data) {
  158. debug('Page Added', data);
  159. }).catch(function (err) {
  160. debug('Error addPage:', err);
  161. });
  162. //debug('Data received: ', doc.path, doc.liker.length, doc.revision.body);
  163. }).on('error', function (err) {
  164. debug('Error stream:', err);
  165. // handle err
  166. }).on('close', function () {
  167. debug('Close');
  168. // all done
  169. });
  170. };
  171. lib.addPage = function(id, path, body, creator, likeCount, bookmarkCount, updated, is_public) {
  172. var self = this;
  173. return client.create({
  174. index: index_name,
  175. type: 'page',
  176. id: id,
  177. body: {
  178. path: path,
  179. body: body,
  180. creator: creator,
  181. likeCount: likeCount,
  182. bookmarkCount: bookmarkCount,
  183. is_public: is_public,
  184. updated: updated,
  185. }
  186. });
  187. };
  188. lib.updatePage = function(id, path, body, creator, likeCount, bookmarkCount, updated, is_public) {
  189. };
  190. lib.searchPageByKeyword = function(keyword) {
  191. var queryBody = {
  192. query: {
  193. bool: {
  194. should: [
  195. {term: { path: { term: keyword, boost: 2.0 } }},
  196. {term: { body: { term: keyword } }}
  197. ]
  198. }
  199. },
  200. highlight : { fields : { body : {} } },
  201. //sort: [{ updated: { order: "desc" } } ]
  202. };
  203. return client.search({
  204. index: index_name,
  205. body: queryBody
  206. });
  207. };
  208. lib.searchPageByLikeCount = function() {
  209. };
  210. return lib;
  211. };
  212. */