index.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // Copyright 2012-present Oliver Eilhard. All rights reserved.
  2. // Use of this source code is governed by a MIT-license.
  3. // See http://olivere.mit-license.org/license.txt for details.
  4. package elastic
  5. import (
  6. "context"
  7. "fmt"
  8. "net/url"
  9. "gopkg.in/olivere/elastic.v5/uritemplates"
  10. )
  11. // IndexService adds or updates a typed JSON document in a specified index,
  12. // making it searchable.
  13. //
  14. // See https://www.elastic.co/guide/en/elasticsearch/reference/5.2/docs-index_.html
  15. // for details.
  16. type IndexService struct {
  17. client *Client
  18. pretty bool
  19. id string
  20. index string
  21. typ string
  22. parent string
  23. routing string
  24. timeout string
  25. timestamp string
  26. ttl string
  27. version interface{}
  28. opType string
  29. versionType string
  30. refresh string
  31. waitForActiveShards string
  32. pipeline string
  33. bodyJson interface{}
  34. bodyString string
  35. }
  36. // NewIndexService creates a new IndexService.
  37. func NewIndexService(client *Client) *IndexService {
  38. return &IndexService{
  39. client: client,
  40. }
  41. }
  42. // Id is the document ID.
  43. func (s *IndexService) Id(id string) *IndexService {
  44. s.id = id
  45. return s
  46. }
  47. // Index is the name of the index.
  48. func (s *IndexService) Index(index string) *IndexService {
  49. s.index = index
  50. return s
  51. }
  52. // Type is the type of the document.
  53. func (s *IndexService) Type(typ string) *IndexService {
  54. s.typ = typ
  55. return s
  56. }
  57. // WaitForActiveShards sets the number of shard copies that must be active
  58. // before proceeding with the index operation. Defaults to 1, meaning the
  59. // primary shard only. Set to `all` for all shard copies, otherwise set to
  60. // any non-negative value less than or equal to the total number of copies
  61. // for the shard (number of replicas + 1).
  62. func (s *IndexService) WaitForActiveShards(waitForActiveShards string) *IndexService {
  63. s.waitForActiveShards = waitForActiveShards
  64. return s
  65. }
  66. // Pipeline specifies the pipeline id to preprocess incoming documents with.
  67. func (s *IndexService) Pipeline(pipeline string) *IndexService {
  68. s.pipeline = pipeline
  69. return s
  70. }
  71. // Refresh the index after performing the operation.
  72. func (s *IndexService) Refresh(refresh string) *IndexService {
  73. s.refresh = refresh
  74. return s
  75. }
  76. // Ttl is an expiration time for the document.
  77. func (s *IndexService) Ttl(ttl string) *IndexService {
  78. s.ttl = ttl
  79. return s
  80. }
  81. // TTL is an expiration time for the document (alias for Ttl).
  82. func (s *IndexService) TTL(ttl string) *IndexService {
  83. s.ttl = ttl
  84. return s
  85. }
  86. // Version is an explicit version number for concurrency control.
  87. func (s *IndexService) Version(version interface{}) *IndexService {
  88. s.version = version
  89. return s
  90. }
  91. // OpType is an explicit operation type, i.e. "create" or "index" (default).
  92. func (s *IndexService) OpType(opType string) *IndexService {
  93. s.opType = opType
  94. return s
  95. }
  96. // Parent is the ID of the parent document.
  97. func (s *IndexService) Parent(parent string) *IndexService {
  98. s.parent = parent
  99. return s
  100. }
  101. // Routing is a specific routing value.
  102. func (s *IndexService) Routing(routing string) *IndexService {
  103. s.routing = routing
  104. return s
  105. }
  106. // Timeout is an explicit operation timeout.
  107. func (s *IndexService) Timeout(timeout string) *IndexService {
  108. s.timeout = timeout
  109. return s
  110. }
  111. // Timestamp is an explicit timestamp for the document.
  112. func (s *IndexService) Timestamp(timestamp string) *IndexService {
  113. s.timestamp = timestamp
  114. return s
  115. }
  116. // VersionType is a specific version type.
  117. func (s *IndexService) VersionType(versionType string) *IndexService {
  118. s.versionType = versionType
  119. return s
  120. }
  121. // Pretty indicates that the JSON response be indented and human readable.
  122. func (s *IndexService) Pretty(pretty bool) *IndexService {
  123. s.pretty = pretty
  124. return s
  125. }
  126. // BodyJson is the document as a serializable JSON interface.
  127. func (s *IndexService) BodyJson(body interface{}) *IndexService {
  128. s.bodyJson = body
  129. return s
  130. }
  131. // BodyString is the document encoded as a string.
  132. func (s *IndexService) BodyString(body string) *IndexService {
  133. s.bodyString = body
  134. return s
  135. }
  136. // buildURL builds the URL for the operation.
  137. func (s *IndexService) buildURL() (string, string, url.Values, error) {
  138. var err error
  139. var method, path string
  140. if s.id != "" {
  141. // Create document with manual id
  142. method = "PUT"
  143. path, err = uritemplates.Expand("/{index}/{type}/{id}", map[string]string{
  144. "id": s.id,
  145. "index": s.index,
  146. "type": s.typ,
  147. })
  148. } else {
  149. // Automatic ID generation
  150. // See https://www.elastic.co/guide/en/elasticsearch/reference/5.2/docs-index_.html#index-creation
  151. method = "POST"
  152. path, err = uritemplates.Expand("/{index}/{type}/", map[string]string{
  153. "index": s.index,
  154. "type": s.typ,
  155. })
  156. }
  157. if err != nil {
  158. return "", "", url.Values{}, err
  159. }
  160. // Add query string parameters
  161. params := url.Values{}
  162. if s.pretty {
  163. params.Set("pretty", "1")
  164. }
  165. if s.waitForActiveShards != "" {
  166. params.Set("wait_for_active_shards", s.waitForActiveShards)
  167. }
  168. if s.refresh != "" {
  169. params.Set("refresh", s.refresh)
  170. }
  171. if s.opType != "" {
  172. params.Set("op_type", s.opType)
  173. }
  174. if s.parent != "" {
  175. params.Set("parent", s.parent)
  176. }
  177. if s.pipeline != "" {
  178. params.Set("pipeline", s.pipeline)
  179. }
  180. if s.routing != "" {
  181. params.Set("routing", s.routing)
  182. }
  183. if s.timeout != "" {
  184. params.Set("timeout", s.timeout)
  185. }
  186. if s.timestamp != "" {
  187. params.Set("timestamp", s.timestamp)
  188. }
  189. if s.ttl != "" {
  190. params.Set("ttl", s.ttl)
  191. }
  192. if s.version != nil {
  193. params.Set("version", fmt.Sprintf("%v", s.version))
  194. }
  195. if s.versionType != "" {
  196. params.Set("version_type", s.versionType)
  197. }
  198. return method, path, params, nil
  199. }
  200. // Validate checks if the operation is valid.
  201. func (s *IndexService) Validate() error {
  202. var invalid []string
  203. if s.index == "" {
  204. invalid = append(invalid, "Index")
  205. }
  206. if s.typ == "" {
  207. invalid = append(invalid, "Type")
  208. }
  209. if s.bodyString == "" && s.bodyJson == nil {
  210. invalid = append(invalid, "BodyJson")
  211. }
  212. if len(invalid) > 0 {
  213. return fmt.Errorf("missing required fields: %v", invalid)
  214. }
  215. return nil
  216. }
  217. // Do executes the operation.
  218. func (s *IndexService) Do(ctx context.Context) (*IndexResponse, error) {
  219. // Check pre-conditions
  220. if err := s.Validate(); err != nil {
  221. return nil, err
  222. }
  223. // Get URL for request
  224. method, path, params, err := s.buildURL()
  225. if err != nil {
  226. return nil, err
  227. }
  228. // Setup HTTP request body
  229. var body interface{}
  230. if s.bodyJson != nil {
  231. body = s.bodyJson
  232. } else {
  233. body = s.bodyString
  234. }
  235. // Get HTTP response
  236. res, err := s.client.PerformRequest(ctx, method, path, params, body)
  237. if err != nil {
  238. return nil, err
  239. }
  240. // Return operation response
  241. ret := new(IndexResponse)
  242. if err := s.client.decoder.Decode(res.Body, ret); err != nil {
  243. return nil, err
  244. }
  245. return ret, nil
  246. }
  247. // IndexResponse is the result of indexing a document in Elasticsearch.
  248. type IndexResponse struct {
  249. Index string `json:"_index,omitempty"`
  250. Type string `json:"_type,omitempty"`
  251. Id string `json:"_id,omitempty"`
  252. Version int64 `json:"_version,omitempty"`
  253. Result string `json:"result,omitempty"`
  254. Shards *ShardsInfo `json:"_shards,omitempty"`
  255. SeqNo int64 `json:"_seq_no,omitempty"`
  256. PrimaryTerm int64 `json:"_primary_term,omitempty"`
  257. Status int `json:"status,omitempty"`
  258. ForcedRefresh bool `json:"forced_refresh,omitempty"`
  259. }