search_index_backend.rb 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. # Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/
  2. class SearchIndexBackend
  3. =begin
  4. create/update/delete index
  5. SearchIndexBackend.index(
  6. :action => 'create', # create/update/delete
  7. :data => {
  8. :mappings => {
  9. :Ticket => {
  10. :properties => {
  11. :articles_all => {
  12. :type => 'nested',
  13. :properties => {
  14. 'attachments' => { :type => 'attachment' }
  15. }
  16. }
  17. }
  18. }
  19. }
  20. }
  21. )
  22. SearchIndexBackend.index(
  23. :action => 'delete', # create/update/delete
  24. :name => 'Ticket', # optional
  25. )
  26. SearchIndexBackend.index(
  27. :action => 'delete', # create/update/delete
  28. )
  29. =end
  30. def self.index(data)
  31. url = build_url( data[:name] )
  32. return if !url
  33. if data[:action] && data[:action] == 'delete'
  34. return SearchIndexBackend.remove( data[:name] )
  35. end
  36. puts "# curl -X PUT \"#{url}\" -d '#{data[:data].to_json}'"
  37. conn = connection( url )
  38. response = conn.put do |req|
  39. req.url url
  40. req.headers['Content-Type'] = 'application/json'
  41. req.body = data[:data].to_json
  42. end
  43. puts "# #{response.status.to_s}"
  44. return true if response.success?
  45. data = JSON.parse( response.body )
  46. raise data.inspect
  47. end
  48. =begin
  49. add new object to search index
  50. SearchIndexBackend.add( 'Ticket', some_data_object )
  51. =end
  52. def self.add(type, data)
  53. url = build_url( type, data['id'] )
  54. return if !url
  55. puts "# curl -X POST \"#{url}\" -d '#{data.to_json}'"
  56. conn = connection( url )
  57. response = conn.post do |req|
  58. req.url url
  59. req.headers['Content-Type'] = 'application/json'
  60. req.body = data.to_json
  61. end
  62. puts "# #{response.status.to_s}"
  63. return true if response.success?
  64. data = JSON.parse( response.body )
  65. raise data.inspect
  66. end
  67. =begin
  68. remove whole data from index
  69. SearchIndexBackend.remove( 'Ticket', 123 )
  70. SearchIndexBackend.remove( 'Ticket' )
  71. =end
  72. def self.remove( type, o_id = nil )
  73. url = build_url( type, o_id )
  74. return if !url
  75. puts "# curl -X DELETE \"#{url}\""
  76. conn = connection( url )
  77. response = conn.delete( url )
  78. puts "# #{response.status.to_s}"
  79. return false if !response.success?
  80. data = JSON.parse( response.body )
  81. # raise data.inspect
  82. return { :data => data, :response => response }
  83. end
  84. =begin
  85. return search result
  86. result = SearchIndexBackend.search( 'search query', limit, ['User', 'Organization'] )
  87. result = SearchIndexBackend.search( 'search query', limit, 'User' )
  88. result = [
  89. {
  90. :id => 123,
  91. :type => 'User',
  92. },
  93. {
  94. :id => 125,
  95. :type => 'User',
  96. },
  97. {
  98. :id => 15,
  99. :type => 'Organization',
  100. }
  101. ]
  102. =end
  103. def self.search( query, limit = 10, index = nil, query_extention = {} )
  104. return [] if !query
  105. url = build_url()
  106. return if !url
  107. if index
  108. if index.class == Array
  109. url += "/#{index.join(',')}/_search"
  110. else
  111. url += "/#{index}/_search"
  112. end
  113. else
  114. url += '/_search'
  115. end
  116. data = {}
  117. data['from'] = 0
  118. data['size'] = 10
  119. data['sort'] =
  120. [
  121. {
  122. :updated_at => {
  123. :order => 'desc'
  124. }
  125. },
  126. "_score"
  127. ]
  128. data['query'] = query_extention || {}
  129. if !data['query']['bool']
  130. data['query']['bool'] = {}
  131. end
  132. if !data['query']['bool']['must']
  133. data['query']['bool']['must'] = []
  134. end
  135. # real search condition
  136. condition = {
  137. 'query_string' => {
  138. 'query' => query
  139. }
  140. }
  141. data['query']['bool']['must'].push condition
  142. puts "# curl -X POST \"#{url}\" -d '#{data.to_json}'"
  143. conn = connection( url )
  144. response = conn.get do |req|
  145. req.headers['Content-Type'] = 'application/json'
  146. req.body = data.to_json
  147. end
  148. puts "# #{response.status.to_s}"
  149. data = JSON.parse( response.body )
  150. if !response.success?
  151. return []
  152. # raise data.inspect
  153. end
  154. ids = []
  155. return ids if !data
  156. return ids if !data['hits']
  157. return ids if !data['hits']['hits']
  158. data['hits']['hits'].each { |item|
  159. puts "... #{item['_type'].to_s} #{item['_id'].to_s}"
  160. data = {
  161. :id => item['_id'],
  162. :type => item['_type'],
  163. }
  164. ids.push data
  165. }
  166. ids
  167. end
  168. =begin
  169. return true if backend is configured
  170. result = SearchIndexBackend.enabled?
  171. =end
  172. def self.enabled?
  173. return if !Setting.get('es_url')
  174. return if Setting.get('es_url').empty?
  175. true
  176. end
  177. private
  178. def self.build_url( type = nil, o_id = nil )
  179. return if !SearchIndexBackend.enabled?
  180. index = Setting.get('es_index').to_s + "_#{Rails.env}"
  181. url = Setting.get('es_url')
  182. if type
  183. if o_id
  184. url = "#{url}/#{index}/#{type}/#{o_id}"
  185. else
  186. url = "#{url}/#{index}/#{type}"
  187. end
  188. else
  189. url = "#{url}/#{index}"
  190. end
  191. url
  192. end
  193. def self.connection( url )
  194. conn = Faraday.new( :url => url )
  195. user = Setting.get('es_user')
  196. pw = Setting.get('es_password')
  197. if user && !user.empty? && pw && !pw.empty?
  198. conn.basic_auth( user, pw )
  199. end
  200. conn
  201. end
  202. end