search_index_es.rake 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. $LOAD_PATH << './lib'
  2. require 'rubygems'
  3. namespace :searchindex do
  4. task :drop, [:opts] => :environment do |_t, _args|
  5. # drop indexes
  6. print 'drop indexes...'
  7. SearchIndexBackend.index(
  8. action: 'delete',
  9. )
  10. puts 'done'
  11. Rake::Task['searchindex:drop_pipeline'].execute
  12. end
  13. task :create, [:opts] => :environment do |_t, _args|
  14. print 'create indexes...'
  15. # es with mapper-attachments plugin
  16. info = SearchIndexBackend.info
  17. number = nil
  18. if info.present?
  19. number = info['version']['number'].to_s
  20. end
  21. settings = {
  22. 'index.mapping.total_fields.limit': 2000,
  23. }
  24. mapping = {}
  25. Models.indexable.each do |local_object|
  26. mapping.merge!(get_mapping_properties_object(local_object))
  27. end
  28. # create indexes
  29. SearchIndexBackend.index(
  30. action: 'create',
  31. data: {
  32. mappings: mapping,
  33. settings: settings,
  34. }
  35. )
  36. if number.blank? || number =~ /^[2-4]\./ || number =~ /^5\.[0-5]\./
  37. Setting.set('es_pipeline', '')
  38. end
  39. puts 'done'
  40. Rake::Task['searchindex:create_pipeline'].execute
  41. end
  42. task :create_pipeline, [:opts] => :environment do |_t, _args|
  43. # es with mapper-attachments plugin
  44. info = SearchIndexBackend.info
  45. number = nil
  46. if info.present?
  47. number = info['version']['number'].to_s
  48. end
  49. next if number.blank? || number =~ /^[2-4]\./ || number =~ /^5\.[0-5]\./
  50. # update processors
  51. pipeline = Setting.get('es_pipeline')
  52. if pipeline.blank?
  53. pipeline = "zammad#{rand(999_999_999_999)}"
  54. Setting.set('es_pipeline', pipeline)
  55. end
  56. print 'create pipeline (pipeline)... '
  57. SearchIndexBackend.processors(
  58. "_ingest/pipeline/#{pipeline}": [
  59. {
  60. action: 'delete',
  61. },
  62. {
  63. action: 'create',
  64. description: 'Extract zammad-attachment information from arrays',
  65. processors: [
  66. {
  67. foreach: {
  68. field: 'article',
  69. ignore_failure: true,
  70. processor: {
  71. foreach: {
  72. field: '_ingest._value.attachment',
  73. ignore_failure: true,
  74. processor: {
  75. attachment: {
  76. target_field: '_ingest._value',
  77. field: '_ingest._value._content',
  78. ignore_failure: true,
  79. }
  80. }
  81. }
  82. }
  83. }
  84. }
  85. ]
  86. }
  87. ]
  88. )
  89. puts 'done'
  90. end
  91. task :drop_pipeline, [:opts] => :environment do |_t, _args|
  92. # es with mapper-attachments plugin
  93. info = SearchIndexBackend.info
  94. number = nil
  95. if info.present?
  96. number = info['version']['number'].to_s
  97. end
  98. next if number.blank? || number =~ /^[2-4]\./ || number =~ /^5\.[0-5]\./
  99. # update processors
  100. pipeline = Setting.get('es_pipeline')
  101. next if pipeline.blank?
  102. print 'delete pipeline (pipeline)... '
  103. SearchIndexBackend.processors(
  104. "_ingest/pipeline/#{pipeline}": [
  105. {
  106. action: 'delete',
  107. },
  108. ]
  109. )
  110. puts 'done'
  111. end
  112. task :reload, [:opts] => :environment do |_t, _args|
  113. puts 'reload data...'
  114. Models.indexable.each do |model_class|
  115. puts " reload #{model_class}"
  116. started_at = Time.zone.now
  117. puts " - started at #{started_at}"
  118. model_class.search_index_reload
  119. took = Time.zone.now - started_at
  120. puts " - took #{took.to_i} seconds"
  121. end
  122. end
  123. task :rebuild, [:opts] => :environment do |_t, _args|
  124. Rake::Task['searchindex:drop'].execute
  125. Rake::Task['searchindex:create'].execute
  126. Rake::Task['searchindex:reload'].execute
  127. end
  128. end
  129. =begin
  130. This function will return a index mapping based on the
  131. attributes of the database table of the existing object.
  132. mapping = get_mapping_properties_object(Ticket)
  133. Returns:
  134. mapping = {
  135. User: {
  136. properties: {
  137. firstname: {
  138. type: 'keyword',
  139. },
  140. }
  141. }
  142. }
  143. =end
  144. def get_mapping_properties_object(object)
  145. result = {
  146. object.name => {
  147. properties: {}
  148. }
  149. }
  150. store_columns = %w[preferences data]
  151. object.columns_hash.each do |key, value|
  152. if value.type == :string && value.limit && value.limit <= 5000 && store_columns.exclude?(key)
  153. result[object.name][:properties][key] = {
  154. type: 'string',
  155. fields: {
  156. raw: { 'type': 'string', 'index': 'not_analyzed' }
  157. }
  158. }
  159. elsif value.type == :integer
  160. result[object.name][:properties][key] = {
  161. type: 'integer',
  162. }
  163. elsif value.type == :datetime
  164. result[object.name][:properties][key] = {
  165. type: 'date',
  166. }
  167. elsif value.type == :boolean
  168. result[object.name][:properties][key] = {
  169. type: 'boolean',
  170. fields: {
  171. raw: { 'type': 'boolean', 'index': 'not_analyzed' }
  172. }
  173. }
  174. elsif value.type == :binary
  175. result[object.name][:properties][key] = {
  176. type: 'binary',
  177. }
  178. elsif value.type == :bigint
  179. result[object.name][:properties][key] = {
  180. type: 'long',
  181. }
  182. elsif value.type == :decimal
  183. result[object.name][:properties][key] = {
  184. type: 'float',
  185. }
  186. elsif value.type == :date
  187. result[object.name][:properties][key] = {
  188. type: 'date',
  189. }
  190. end
  191. end
  192. # es with mapper-attachments plugin
  193. info = SearchIndexBackend.info
  194. number = nil
  195. if info.present?
  196. number = info['version']['number'].to_s
  197. end
  198. if object.name == 'Ticket'
  199. result[object.name][:_source] = {
  200. excludes: ['article.attachment']
  201. }
  202. if number.blank? || number =~ /^[2-4]\./ || number =~ /^5\.[0-5]\./
  203. result[object.name][:_source] = {
  204. excludes: ['article.attachment']
  205. }
  206. result[object.name][:properties][:article] = {
  207. type: 'nested',
  208. include_in_parent: true,
  209. properties: {
  210. attachment: {
  211. type: 'attachment',
  212. }
  213. }
  214. }
  215. end
  216. end
  217. result
  218. end