You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

835 lines
19 KiB

  1. // Copyright 2013 Belogik. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package goes
  5. import (
  6. . "launchpad.net/gocheck"
  7. "net/http"
  8. "net/url"
  9. "os"
  10. "testing"
  11. "time"
  12. )
  13. var (
  14. ES_HOST = "localhost"
  15. ES_PORT = "9200"
  16. )
  17. // Hook up gocheck into the gotest runner.
  18. func Test(t *testing.T) { TestingT(t) }
  19. type GoesTestSuite struct{}
  20. var _ = Suite(&GoesTestSuite{})
  21. func (s *GoesTestSuite) SetUpTest(c *C) {
  22. h := os.Getenv("TEST_ELASTICSEARCH_HOST")
  23. if h != "" {
  24. ES_HOST = h
  25. }
  26. p := os.Getenv("TEST_ELASTICSEARCH_PORT")
  27. if p != "" {
  28. ES_PORT = p
  29. }
  30. }
  31. func (s *GoesTestSuite) TestNewConnection(c *C) {
  32. conn := NewConnection(ES_HOST, ES_PORT)
  33. c.Assert(conn, DeepEquals, &Connection{ES_HOST, ES_PORT, http.DefaultClient})
  34. }
  35. func (s *GoesTestSuite) TestWithClient(c *C) {
  36. tr := &http.Transport{
  37. DisableCompression: true,
  38. ResponseHeaderTimeout: 1 * time.Second,
  39. }
  40. cl := &http.Client{
  41. Transport: tr,
  42. }
  43. conn := NewConnection(ES_HOST, ES_PORT).WithClient(cl)
  44. c.Assert(conn, DeepEquals, &Connection{ES_HOST, ES_PORT, cl})
  45. c.Assert(conn.Client.Transport.(*http.Transport).DisableCompression, Equals, true)
  46. c.Assert(conn.Client.Transport.(*http.Transport).ResponseHeaderTimeout, Equals, 1*time.Second)
  47. }
  48. func (s *GoesTestSuite) TestUrl(c *C) {
  49. conn := NewConnection(ES_HOST, ES_PORT)
  50. r := Request{
  51. Conn: conn,
  52. Query: "q",
  53. IndexList: []string{"i"},
  54. TypeList: []string{},
  55. method: "GET",
  56. api: "_search",
  57. }
  58. c.Assert(r.Url(), Equals, "http://"+ES_HOST+":"+ES_PORT+"/i/_search")
  59. r.IndexList = []string{"a", "b"}
  60. c.Assert(r.Url(), Equals, "http://"+ES_HOST+":"+ES_PORT+"/a,b/_search")
  61. r.TypeList = []string{"c", "d"}
  62. c.Assert(r.Url(), Equals, "http://"+ES_HOST+":"+ES_PORT+"/a,b/c,d/_search")
  63. r.ExtraArgs = make(url.Values, 1)
  64. r.ExtraArgs.Set("version", "1")
  65. c.Assert(r.Url(), Equals, "http://"+ES_HOST+":"+ES_PORT+"/a,b/c,d/_search?version=1")
  66. r.id = "1234"
  67. r.api = ""
  68. c.Assert(r.Url(), Equals, "http://"+ES_HOST+":"+ES_PORT+"/a,b/c,d/1234/?version=1")
  69. }
  70. func (s *GoesTestSuite) TestEsDown(c *C) {
  71. conn := NewConnection("a.b.c.d", "1234")
  72. var query = map[string]interface{}{"query": "foo"}
  73. r := Request{
  74. Conn: conn,
  75. Query: query,
  76. IndexList: []string{"i"},
  77. method: "GET",
  78. api: "_search",
  79. }
  80. _, err := r.Run()
  81. c.Assert(err, ErrorMatches, "Get http://a.b.c.d:1234/i/_search:(.*)lookup a.b.c.d: no such host")
  82. }
  83. func (s *GoesTestSuite) TestRunMissingIndex(c *C) {
  84. conn := NewConnection(ES_HOST, ES_PORT)
  85. var query = map[string]interface{}{"query": "foo"}
  86. r := Request{
  87. Conn: conn,
  88. Query: query,
  89. IndexList: []string{"i"},
  90. method: "GET",
  91. api: "_search",
  92. }
  93. _, err := r.Run()
  94. c.Assert(err.Error(), Equals, "[404] IndexMissingException[[i] missing]")
  95. }
  96. func (s *GoesTestSuite) TestCreateIndex(c *C) {
  97. indexName := "testcreateindexgoes"
  98. conn := NewConnection(ES_HOST, ES_PORT)
  99. defer conn.DeleteIndex(indexName)
  100. mapping := map[string]interface{}{
  101. "settings": map[string]interface{}{
  102. "index.number_of_shards": 1,
  103. "index.number_of_replicas": 0,
  104. },
  105. "mappings": map[string]interface{}{
  106. "_default_": map[string]interface{}{
  107. "_source": map[string]interface{}{
  108. "enabled": false,
  109. },
  110. "_all": map[string]interface{}{
  111. "enabled": false,
  112. },
  113. },
  114. },
  115. }
  116. resp, err := conn.CreateIndex(indexName, mapping)
  117. c.Assert(err, IsNil)
  118. c.Assert(resp.Acknowledged, Equals, true)
  119. }
  120. func (s *GoesTestSuite) TestDeleteIndexInexistantIndex(c *C) {
  121. conn := NewConnection(ES_HOST, ES_PORT)
  122. resp, err := conn.DeleteIndex("foobar")
  123. c.Assert(err.Error(), Equals, "[404] IndexMissingException[[foobar] missing]")
  124. c.Assert(resp, DeepEquals, Response{})
  125. }
  126. func (s *GoesTestSuite) TestDeleteIndexExistingIndex(c *C) {
  127. conn := NewConnection(ES_HOST, ES_PORT)
  128. indexName := "testdeleteindexexistingindex"
  129. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  130. c.Assert(err, IsNil)
  131. resp, err := conn.DeleteIndex(indexName)
  132. c.Assert(err, IsNil)
  133. expectedResponse := Response{}
  134. expectedResponse.Acknowledged = true
  135. c.Assert(resp, DeepEquals, expectedResponse)
  136. }
  137. func (s *GoesTestSuite) TestRefreshIndex(c *C) {
  138. conn := NewConnection(ES_HOST, ES_PORT)
  139. indexName := "testrefreshindex"
  140. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  141. c.Assert(err, IsNil)
  142. _, err = conn.RefreshIndex(indexName)
  143. c.Assert(err, IsNil)
  144. _, err = conn.DeleteIndex(indexName)
  145. c.Assert(err, IsNil)
  146. }
  147. func (s *GoesTestSuite) TestBulkSend(c *C) {
  148. indexName := "testbulkadd"
  149. docType := "tweet"
  150. tweets := []Document{
  151. Document{
  152. Id: "123",
  153. Index: nil,
  154. Type: docType,
  155. BulkCommand: BULK_COMMAND_INDEX,
  156. Fields: map[string]interface{}{
  157. "user": "foo",
  158. "message": "some foo message",
  159. },
  160. },
  161. Document{
  162. Id: nil,
  163. Index: indexName,
  164. Type: docType,
  165. BulkCommand: BULK_COMMAND_INDEX,
  166. Fields: map[string]interface{}{
  167. "user": "bar",
  168. "message": "some bar message",
  169. },
  170. },
  171. }
  172. conn := NewConnection(ES_HOST, ES_PORT)
  173. _, err := conn.CreateIndex(indexName, nil)
  174. c.Assert(err, IsNil)
  175. response, err := conn.BulkSend(indexName, tweets)
  176. i := Item{
  177. Id: "123",
  178. Type: docType,
  179. Version: 1,
  180. Index: indexName,
  181. }
  182. c.Assert(response.Items[0][BULK_COMMAND_INDEX], Equals, i)
  183. c.Assert(err, IsNil)
  184. _, err = conn.RefreshIndex(indexName)
  185. c.Assert(err, IsNil)
  186. var query = map[string]interface{}{
  187. "query": map[string]interface{}{
  188. "match_all": map[string]interface{}{},
  189. },
  190. }
  191. searchResults, err := conn.Search(query, []string{indexName}, []string{}, url.Values{})
  192. c.Assert(err, IsNil)
  193. var expectedTotal uint64 = 2
  194. c.Assert(searchResults.Hits.Total, Equals, expectedTotal)
  195. extraDocId := ""
  196. checked := 0
  197. for _, hit := range searchResults.Hits.Hits {
  198. if hit.Source["user"] == "foo" {
  199. c.Assert(hit.Id, Equals, "123")
  200. checked++
  201. }
  202. if hit.Source["user"] == "bar" {
  203. c.Assert(len(hit.Id) > 0, Equals, true)
  204. extraDocId = hit.Id
  205. checked++
  206. }
  207. }
  208. c.Assert(checked, Equals, 2)
  209. docToDelete := []Document{
  210. Document{
  211. Id: "123",
  212. Index: indexName,
  213. Type: docType,
  214. BulkCommand: BULK_COMMAND_DELETE,
  215. },
  216. Document{
  217. Id: extraDocId,
  218. Index: indexName,
  219. Type: docType,
  220. BulkCommand: BULK_COMMAND_DELETE,
  221. },
  222. }
  223. response, err = conn.BulkSend(indexName, docToDelete)
  224. i = Item{
  225. Id: "123",
  226. Type: docType,
  227. Version: 2,
  228. Index: indexName,
  229. }
  230. c.Assert(response.Items[0][BULK_COMMAND_DELETE], Equals, i)
  231. c.Assert(err, IsNil)
  232. _, err = conn.RefreshIndex(indexName)
  233. c.Assert(err, IsNil)
  234. searchResults, err = conn.Search(query, []string{indexName}, []string{}, url.Values{})
  235. c.Assert(err, IsNil)
  236. expectedTotal = 0
  237. c.Assert(searchResults.Hits.Total, Equals, expectedTotal)
  238. _, err = conn.DeleteIndex(indexName)
  239. c.Assert(err, IsNil)
  240. }
  241. func (s *GoesTestSuite) TestStats(c *C) {
  242. conn := NewConnection(ES_HOST, ES_PORT)
  243. indexName := "teststats"
  244. conn.DeleteIndex(indexName)
  245. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  246. c.Assert(err, IsNil)
  247. // we must wait for a bit otherwise ES crashes
  248. time.Sleep(1 * time.Second)
  249. response, err := conn.Stats([]string{indexName}, url.Values{})
  250. c.Assert(err, IsNil)
  251. c.Assert(response.All.Indices[indexName].Primaries["docs"].Count, Equals, 0)
  252. _, err = conn.DeleteIndex(indexName)
  253. c.Assert(err, IsNil)
  254. }
  255. func (s *GoesTestSuite) TestIndexIdDefined(c *C) {
  256. indexName := "testindexiddefined"
  257. docType := "tweet"
  258. docId := "1234"
  259. conn := NewConnection(ES_HOST, ES_PORT)
  260. // just in case
  261. conn.DeleteIndex(indexName)
  262. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  263. c.Assert(err, IsNil)
  264. defer conn.DeleteIndex(indexName)
  265. d := Document{
  266. Index: indexName,
  267. Type: docType,
  268. Id: docId,
  269. Fields: map[string]interface{}{
  270. "user": "foo",
  271. "message": "bar",
  272. },
  273. }
  274. extraArgs := make(url.Values, 1)
  275. extraArgs.Set("ttl", "86400000")
  276. response, err := conn.Index(d, extraArgs)
  277. c.Assert(err, IsNil)
  278. expectedResponse := Response{
  279. Index: indexName,
  280. Id: docId,
  281. Type: docType,
  282. Version: 1,
  283. }
  284. c.Assert(response, DeepEquals, expectedResponse)
  285. }
  286. func (s *GoesTestSuite) TestIndexIdNotDefined(c *C) {
  287. indexName := "testindexidnotdefined"
  288. docType := "tweet"
  289. conn := NewConnection(ES_HOST, ES_PORT)
  290. // just in case
  291. conn.DeleteIndex(indexName)
  292. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  293. c.Assert(err, IsNil)
  294. defer conn.DeleteIndex(indexName)
  295. d := Document{
  296. Index: indexName,
  297. Type: docType,
  298. Fields: map[string]interface{}{
  299. "user": "foo",
  300. "message": "bar",
  301. },
  302. }
  303. response, err := conn.Index(d, url.Values{})
  304. c.Assert(err, IsNil)
  305. c.Assert(response.Index, Equals, indexName)
  306. c.Assert(response.Type, Equals, docType)
  307. c.Assert(response.Version, Equals, 1)
  308. c.Assert(response.Id != "", Equals, true)
  309. }
  310. func (s *GoesTestSuite) TestDelete(c *C) {
  311. indexName := "testdelete"
  312. docType := "tweet"
  313. docId := "1234"
  314. conn := NewConnection(ES_HOST, ES_PORT)
  315. // just in case
  316. conn.DeleteIndex(indexName)
  317. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  318. c.Assert(err, IsNil)
  319. defer conn.DeleteIndex(indexName)
  320. d := Document{
  321. Index: indexName,
  322. Type: docType,
  323. Id: docId,
  324. Fields: map[string]interface{}{
  325. "user": "foo",
  326. },
  327. }
  328. _, err = conn.Index(d, url.Values{})
  329. c.Assert(err, IsNil)
  330. response, err := conn.Delete(d, url.Values{})
  331. c.Assert(err, IsNil)
  332. expectedResponse := Response{
  333. Found: true,
  334. Index: indexName,
  335. Type: docType,
  336. Id: docId,
  337. // XXX : even after a DELETE the version number seems to be incremented
  338. Version: 2,
  339. }
  340. c.Assert(response, DeepEquals, expectedResponse)
  341. response, err = conn.Delete(d, url.Values{})
  342. c.Assert(err, IsNil)
  343. expectedResponse = Response{
  344. Found: false,
  345. Index: indexName,
  346. Type: docType,
  347. Id: docId,
  348. // XXX : even after a DELETE the version number seems to be incremented
  349. Version: 3,
  350. }
  351. c.Assert(response, DeepEquals, expectedResponse)
  352. }
  353. func (s *GoesTestSuite) TestGet(c *C) {
  354. indexName := "testget"
  355. docType := "tweet"
  356. docId := "111"
  357. source := map[string]interface{}{
  358. "f1": "foo",
  359. "f2": "foo",
  360. }
  361. conn := NewConnection(ES_HOST, ES_PORT)
  362. conn.DeleteIndex(indexName)
  363. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  364. c.Assert(err, IsNil)
  365. defer conn.DeleteIndex(indexName)
  366. d := Document{
  367. Index: indexName,
  368. Type: docType,
  369. Id: docId,
  370. Fields: source,
  371. }
  372. _, err = conn.Index(d, url.Values{})
  373. c.Assert(err, IsNil)
  374. response, err := conn.Get(indexName, docType, docId, url.Values{})
  375. c.Assert(err, IsNil)
  376. expectedResponse := Response{
  377. Index: indexName,
  378. Type: docType,
  379. Id: docId,
  380. Version: 1,
  381. Found: true,
  382. Source: source,
  383. }
  384. c.Assert(response, DeepEquals, expectedResponse)
  385. fields := make(url.Values, 1)
  386. fields.Set("fields", "f1")
  387. response, err = conn.Get(indexName, docType, docId, fields)
  388. c.Assert(err, IsNil)
  389. expectedResponse = Response{
  390. Index: indexName,
  391. Type: docType,
  392. Id: docId,
  393. Version: 1,
  394. Found: true,
  395. Fields: map[string]interface{}{
  396. "f1": []interface{}{"foo"},
  397. },
  398. }
  399. c.Assert(response, DeepEquals, expectedResponse)
  400. }
  401. func (s *GoesTestSuite) TestSearch(c *C) {
  402. indexName := "testsearch"
  403. docType := "tweet"
  404. docId := "1234"
  405. source := map[string]interface{}{
  406. "user": "foo",
  407. "message": "bar",
  408. }
  409. conn := NewConnection(ES_HOST, ES_PORT)
  410. conn.DeleteIndex(indexName)
  411. _, err := conn.CreateIndex(indexName, map[string]interface{}{})
  412. c.Assert(err, IsNil)
  413. defer conn.DeleteIndex(indexName)
  414. d := Document{
  415. Index: indexName,
  416. Type: docType,
  417. Id: docId,
  418. Fields: source,
  419. }
  420. _, err = conn.Index(d, url.Values{})
  421. c.Assert(err, IsNil)
  422. _, err = conn.RefreshIndex(indexName)
  423. c.Assert(err, IsNil)
  424. // I can feel my eyes bleeding
  425. query := map[string]interface{}{
  426. "query": map[string]interface{}{
  427. "bool": map[string]interface{}{
  428. "must": []map[string]interface{}{
  429. map[string]interface{}{
  430. "match_all": map[string]interface{}{},
  431. },
  432. },
  433. },
  434. },
  435. }
  436. response, err := conn.Search(query, []string{indexName}, []string{docType}, url.Values{})
  437. expectedHits := Hits{
  438. Total: 1,
  439. MaxScore: 1.0,
  440. Hits: []Hit{
  441. Hit{
  442. Index: indexName,
  443. Type: docType,
  444. Id: docId,
  445. Score: 1.0,
  446. Source: source,
  447. },
  448. },
  449. }
  450. c.Assert(response.Hits, DeepEquals, expectedHits)
  451. }
  452. func (s *GoesTestSuite) TestIndexStatus(c *C) {
  453. indexName := "testindexstatus"
  454. conn := NewConnection(ES_HOST, ES_PORT)
  455. conn.DeleteIndex(indexName)
  456. mapping := map[string]interface{}{
  457. "settings": map[string]interface{}{
  458. "index.number_of_shards": 1,
  459. "index.number_of_replicas": 1,
  460. },
  461. }
  462. _, err := conn.CreateIndex(indexName, mapping)
  463. c.Assert(err, IsNil)
  464. defer conn.DeleteIndex(indexName)
  465. // gives ES some time to do its job
  466. time.Sleep(1 * time.Second)
  467. response, err := conn.IndexStatus([]string{"_all"})
  468. c.Assert(err, IsNil)
  469. expectedShards := Shard{Total: 2, Successful: 1, Failed: 0}
  470. c.Assert(response.Shards, Equals, expectedShards)
  471. expectedIndices := map[string]IndexStatus{
  472. indexName: IndexStatus{
  473. Index: map[string]interface{}{
  474. "primary_size_in_bytes": float64(99),
  475. "size_in_bytes": float64(99),
  476. },
  477. Translog: map[string]uint64{
  478. "operations": 0,
  479. },
  480. Docs: map[string]uint64{
  481. "num_docs": 0,
  482. "max_doc": 0,
  483. "deleted_docs": 0,
  484. },
  485. Merges: map[string]interface{}{
  486. "current": float64(0),
  487. "current_docs": float64(0),
  488. "current_size_in_bytes": float64(0),
  489. "total": float64(0),
  490. "total_time_in_millis": float64(0),
  491. "total_docs": float64(0),
  492. "total_size_in_bytes": float64(0),
  493. },
  494. Refresh: map[string]interface{}{
  495. "total": float64(1),
  496. "total_time_in_millis": float64(0),
  497. },
  498. Flush: map[string]interface{}{
  499. "total": float64(0),
  500. "total_time_in_millis": float64(0),
  501. },
  502. },
  503. }
  504. c.Assert(response.Indices, DeepEquals, expectedIndices)
  505. }
  506. func (s *GoesTestSuite) TestScroll(c *C) {
  507. indexName := "testscroll"
  508. docType := "tweet"
  509. tweets := []Document{
  510. Document{
  511. Id: nil,
  512. Index: indexName,
  513. Type: docType,
  514. BulkCommand: BULK_COMMAND_INDEX,
  515. Fields: map[string]interface{}{
  516. "user": "foo",
  517. "message": "some foo message",
  518. },
  519. },
  520. Document{
  521. Id: nil,
  522. Index: indexName,
  523. Type: docType,
  524. BulkCommand: BULK_COMMAND_INDEX,
  525. Fields: map[string]interface{}{
  526. "user": "bar",
  527. "message": "some bar message",
  528. },
  529. },
  530. Document{
  531. Id: nil,
  532. Index: indexName,
  533. Type: docType,
  534. BulkCommand: BULK_COMMAND_INDEX,
  535. Fields: map[string]interface{}{
  536. "user": "foo",
  537. "message": "another foo message",
  538. },
  539. },
  540. }
  541. conn := NewConnection(ES_HOST, ES_PORT)
  542. mapping := map[string]interface{}{
  543. "settings": map[string]interface{}{
  544. "index.number_of_shards": 1,
  545. "index.number_of_replicas": 0,
  546. },
  547. }
  548. defer conn.DeleteIndex(indexName)
  549. _, err := conn.CreateIndex(indexName, mapping)
  550. c.Assert(err, IsNil)
  551. _, err = conn.BulkSend(indexName, tweets)
  552. c.Assert(err, IsNil)
  553. _, err = conn.RefreshIndex(indexName)
  554. c.Assert(err, IsNil)
  555. query := map[string]interface{}{
  556. "query": map[string]interface{}{
  557. "filtered": map[string]interface{}{
  558. "filter": map[string]interface{}{
  559. "term": map[string]interface{}{
  560. "user": "foo",
  561. },
  562. },
  563. },
  564. },
  565. }
  566. scan, err := conn.Scan(query, []string{indexName}, []string{docType}, "1m", 1)
  567. c.Assert(err, IsNil)
  568. c.Assert(len(scan.ScrollId) > 0, Equals, true)
  569. searchResults, err := conn.Scroll(scan.ScrollId, "1m")
  570. c.Assert(err, IsNil)
  571. // some data in first chunk
  572. c.Assert(searchResults.Hits.Total, Equals, uint64(2))
  573. c.Assert(len(searchResults.ScrollId) > 0, Equals, true)
  574. c.Assert(len(searchResults.Hits.Hits), Equals, 1)
  575. searchResults, err = conn.Scroll(searchResults.ScrollId, "1m")
  576. c.Assert(err, IsNil)
  577. // more data in second chunk
  578. c.Assert(searchResults.Hits.Total, Equals, uint64(2))
  579. c.Assert(len(searchResults.ScrollId) > 0, Equals, true)
  580. c.Assert(len(searchResults.Hits.Hits), Equals, 1)
  581. searchResults, err = conn.Scroll(searchResults.ScrollId, "1m")
  582. c.Assert(err, IsNil)
  583. // nothing in third chunk
  584. c.Assert(searchResults.Hits.Total, Equals, uint64(2))
  585. c.Assert(len(searchResults.ScrollId) > 0, Equals, true)
  586. c.Assert(len(searchResults.Hits.Hits), Equals, 0)
  587. }
  588. func (s *GoesTestSuite) TestAggregations(c *C) {
  589. indexName := "testaggs"
  590. docType := "tweet"
  591. tweets := []Document{
  592. Document{
  593. Id: nil,
  594. Index: indexName,
  595. Type: docType,
  596. BulkCommand: BULK_COMMAND_INDEX,
  597. Fields: map[string]interface{}{
  598. "user" : "foo",
  599. "message" : "some foo message",
  600. "age" : 25,
  601. },
  602. },
  603. Document{
  604. Id: nil,
  605. Index: indexName,
  606. Type: docType,
  607. BulkCommand: BULK_COMMAND_INDEX,
  608. Fields: map[string]interface{}{
  609. "user" : "bar",
  610. "message" : "some bar message",
  611. "age" : 30,
  612. },
  613. },
  614. Document{
  615. Id: nil,
  616. Index: indexName,
  617. Type: docType,
  618. BulkCommand: BULK_COMMAND_INDEX,
  619. Fields: map[string]interface{}{
  620. "user" : "foo",
  621. "message" : "another foo message",
  622. },
  623. },
  624. }
  625. conn := NewConnection(ES_HOST, ES_PORT)
  626. mapping := map[string]interface{}{
  627. "settings": map[string]interface{}{
  628. "index.number_of_shards": 1,
  629. "index.number_of_replicas": 0,
  630. },
  631. }
  632. defer conn.DeleteIndex(indexName)
  633. _, err := conn.CreateIndex(indexName, mapping)
  634. c.Assert(err, IsNil)
  635. _, err = conn.BulkSend(indexName, tweets)
  636. c.Assert(err, IsNil)
  637. _, err = conn.RefreshIndex(indexName)
  638. c.Assert(err, IsNil)
  639. query := map[string]interface{}{
  640. "aggs": map[string]interface{}{
  641. "user": map[string]interface{}{
  642. "terms": map[string]interface{}{
  643. "field": "user",
  644. "order": map[string]interface{}{
  645. "_term": "asc",
  646. },
  647. },
  648. "aggs": map[string]interface{}{
  649. "age": map[string]interface{}{
  650. "stats": map[string]interface{}{
  651. "field": "age",
  652. },
  653. },
  654. },
  655. },
  656. "age": map[string]interface{}{
  657. "stats": map[string]interface{}{
  658. "field": "age",
  659. },
  660. },
  661. },
  662. }
  663. resp, err := conn.Search(query, []string{indexName}, []string{docType}, url.Values{})
  664. user, ok := resp.Aggregations["user"]
  665. c.Assert(ok, Equals, true)
  666. c.Assert(len(user.Buckets()), Equals, 2)
  667. c.Assert(user.Buckets()[0].Key(), Equals, "bar")
  668. c.Assert(user.Buckets()[1].Key(), Equals, "foo")
  669. barAge := user.Buckets()[0].Aggregation("age")
  670. c.Assert(barAge["count"], Equals, 1.0)
  671. c.Assert(barAge["sum"], Equals, 30.0)
  672. fooAge := user.Buckets()[1].Aggregation("age")
  673. c.Assert(fooAge["count"], Equals, 1.0)
  674. c.Assert(fooAge["sum"], Equals, 25.0)
  675. age, ok := resp.Aggregations["age"]
  676. c.Assert(ok, Equals, true)
  677. c.Assert(age["count"], Equals, 2.0)
  678. c.Assert(age["sum"], Equals, 25.0 + 30.0)
  679. }