ElasticSearch + Go:索引失败(名称没有功能)

时间:2014-12-15 19:36:05

标签: go elasticsearch

我正在尝试让ElasticSearch使用v1.4x中的Completion Suggesters为我的自动完成服务索引内容。我正在关注ElasticSearch - You Complete Me的建议并使用Go Client olivere/elastic

我的索引方法看起来有点像这样:

func IndexVehicle(client *elastic.Client, vehicle Vehicle) (bool, error) {
    // See if it exists already
    fetch, err := client.Get().
        Index(vehicleIndex).
        Type("vehicle").
        Id(vehicle.Id).
        Do()
    if err != nil || fetch.Found {
        return false, err
    }

    vehicleName := fmt.Sprintf("%s %s (%s) %s", vehicle.Make, vehicle.Model, vehicle.Model_year, vehicle.Primary_fuel)

    suggest := elastic.NewSuggestField()
    suggest.Input(vehicle.Make, vehicle.Model, vehicle.Primary_fuel, vehicle.Model_year).
        Output(vehicleName).
        Payload(vehicle)

    // Go forth and save
    put, err := client.Index().
        Index(vehicleIndex).
        Type("vehicle").
        Id(vehicle.Id).
        Debug(true).Pretty(true).
        BodyJson(indexBody{Name: vehicleName, Suggest: suggest}).
        Do()
    if err != nil {
        return false, err
    }
    return put.Created, nil
}

现在奇怪的是,在我的一些测试中,这种方法工作正常,项目将被编入索引。在擦除和重建索引之后的其他测试中,测试将失败:

早期的测试在调试中看起来像这样:

2014/12/15 14:11:37 PUT /vehicle/vehicle/369f96459b340507c4688740da3bfe1a?pretty=true HTTP/1.1
Host: localhost:9200
User-Agent: elastic/1.3.1 (darwin-amd64)
Transfer-Encoding: chunked
Accept: application/json
Content-Type: application/json
Accept-Encoding: gzip

{"name":"American Motors Corporation Eagle 4WD (1986) regular","suggest":{"input":["American Motors Corporation","Eagle 4WD","regular","1986"],"output":"American Motors Corporation Eagle 4WD (1986) regular","payload":{"make":"American Motors Corporation","model_year":"1986","model":"Eagle 4WD","primary_fuel":"regular","vehicle_class":"Special Purpose Vehicle 4WD","transmission":"Automatic 3-spd","displacement":"4.2","drive":"4-Wheel or All-Wheel Drive","city_mpg":"15.0","highway_mpg":"19.0","comb_mpg":"17.0"}}}

2014/12/15 14:11:37 HTTP/1.1 201 Created
Content-Length: 134
Content-Type: application/json; charset=UTF-8

{
  "_index" : "vehicle",
  "_type" : "vehicle",
  "_id" : "369f96459b340507c4688740da3bfe1a",
  "_version" : 1,
  "created" : true
}

但是在以后的测试中,做同样的事情会导致错误。在以后的测试中从err返回的IndexVehicle()是:

E
Errors:

  * /Users/phil/go/src/github.com/ride/autocomplete/vehicle_test.go 
  Line 79: - elastic: Error 400: ElasticsearchIllegalArgumentException[No feature for name [vehicle]] 
  goroutine 245 [running]:
  github.com/ride/autocomplete.func·033()
    /Users/phil/go/src/github.com/ride/autocomplete/vehicle_test.go:79 +0x249
  github.com/ride/autocomplete.useIndex(0x499e98)
    /Users/phil/go/src/github.com/ride/autocomplete/test_helper.go:18 +0x55
  github.com/ride/autocomplete.func·034()
    /Users/phil/go/src/github.com/ride/autocomplete/vehicle_test.go:96 +0x2a
  github.com/jtolds/gls._m(0x0, 0xc2080ae9e0)
    /Users/phil/go/src/github.com/jtolds/gls/stack_tags.go:70 +0x32
  github.com/jtolds/gls.markS(0x0, 0xc2080ae9e0)
    /Users/phil/go/src/github.com/jtolds/gls/stack_tags.go:21 +0x32
  github.com/jtolds/gls.addStackTag(0x0, 0xc2080ae9e0)
    /Users/phil/go/src/github.com/jtolds/gls/stack_tags.go:18 +0x3e
  github.com/jtolds/gls.(*ContextManager).SetValues(0xc20801e080, 0xc2080b31d0, 0xc2080ae9e0)
    /Users/phil/go/src/github.com/jtolds/gls/context.go:98 +0x503
  github.com/ride/autocomplete.TestSearchForVehicles(0xc20806a480)
    /Users/phil/go/src/github.com/ride/autocomplete/vehicle_test.go:97 +0x243
  testing.tRunner(0xc20806a480, 0x5be890)
    /opt/boxen/homebrew/Cellar/go/1.4/libexec/src/testing/testing.go:447 +0xbf
  created by testing.RunTests
    /opt/boxen/homebrew/Cellar/go/1.4/libexec/src/testing/testing.go:555 +0xa8b

  goroutine 1 [chan receive]:
  testing.RunTests(0x49a078, 0x5be800, 0x7, 0x7, 0x67c001)
    /opt/boxen/homebrew/Cellar/go/1.4/libexec/src/testing/testing.go:556 +0xad6
  testing.(*M).Run(0xc2080463c0, 0x5c9b20)
    /opt/boxen/homebrew/Cellar/go/1.4/libexec/src/testing/testing.go:485 +0x6c
  main.main()
    github.com/ride/autocomplete/_test/_testmain.go:64 +0x1d5

  goroutine 208 [chan receive]:
  github.com/olivere/elastic.(*Client).pinger(0xc208106d40)
    /Users/phil/go/src/github.com/olivere/elastic/client.go:79 +0x6b
  created by github.com/olivere/elastic.NewClient
    /Users/phil/go/src/github.com/olivere/elastic/client.go:60 +0x26e

  goroutine 248 [runnable]:
  net/http.(*persistConn).readLoop(0xc20802e4d0)
    /opt/boxen/homebrew/Cellar/go/1.4/libexec/src/net/http/transport.go:928 +0x9ce
  created by net/http.(*Transport).dialConn
    /opt/boxen/homebrew/Cellar/go/1.4/libexec/src/net/http/transport.go:660 +0xc9f

  goroutine 98 [chan receive]:
  github.com/olivere/elastic.(*Client).pinger(0xc208033e00)
    /Users/phil/go/src/github.com/olivere/elastic/client.go:79 +0x6b
  created by github.com/olivere/elastic.NewClient
    /Users/phil/go/src/github.com/olivere/elastic/client.go:60 +0x26e

  goroutine 17 [syscall, locked to thread]:
  runtime.goexit()
    /opt/boxen/homebrew/Cellar/go/1.4/libexec/src/runtime/asm_amd64.s:2232 +0x1

  goroutine 44 [chan receive]:
  github.com/olivere/elastic.(*Client).pinger(0xc2080332c0)
    /Users/phil/go/src/github.com/olivere/elastic/client.go:79 +0x6b
  created by github.com/olivere/elastic.NewClient
    /Users/phil/go/src/github.com/olivere/elastic/client.go:60 +0x26e

  goroutine 249 [select]:
  net/http.(*persistConn).writeLoop(0xc20802e4d0)
    /opt/boxen/homebrew/Cellar/go/1.4/libexec/src/net/http/transport.go:945 +0x41d
  created by net/http.(*Transport).dialConn
    /opt/boxen/homebrew/Cellar/go/1.4/libexec/src/net/http/transport.go:661 +0xcbc

  goroutine 54 [chan receive]:
  github.com/olivere/elastic.(*Client).pinger(0xc208032f80)
    /Users/phil/go/src/github.com/olivere/elastic/client.go:79 +0x6b
  created by github.com/olivere/elastic.NewClient
    /Users/phil/go/src/github.com/olivere/elastic/client.go:60 +0x26e

  goroutine 76 [chan receive]:
  github.com/olivere/elastic.(*Client).pinger(0xc208032e00)
    /Users/phil/go/src/github.com/olivere/elastic/client.go:79 +0x6b
  created by github.com/olivere/elastic.NewClient
    /Users/phil/go/src/github.com/olivere/elastic/client.go:60 +0x26e

  goroutine 250 [chan receive]:
  github.com/olivere/elastic.(*Client).pinger(0xc208106c40)
    /Users/phil/go/src/github.com/olivere/elastic/client.go:79 +0x6b
  created by github.com/olivere/elastic.NewClient
    /Users/phil/go/src/github.com/olivere/elastic/client.go:60 +0x26e

  goroutine 120 [chan receive]:
  github.com/olivere/elastic.(*Client).pinger(0xc208106b00)
    /Users/phil/go/src/github.com/olivere/elastic/client.go:79 +0x6b
  created by github.com/olivere/elastic.NewClient
    /Users/phil/go/src/github.com/olivere/elastic/client.go:60 +0x26e

  goroutine 142 [chan receive]:
  github.com/olivere/elastic.(*Client).pinger(0xc208106e00)
    /Users/phil/go/src/github.com/olivere/elastic/client.go:79 +0x6b
  created by github.com/olivere/elastic.NewClient
    /Users/phil/go/src/github.com/olivere/elastic/client.go:60 +0x26e

  goroutine 164 [chan receive]:
  github.com/olivere/elastic.(*Client).pinger(0xc208106b80)
    /Users/phil/go/src/github.com/olivere/elastic/client.go:79 +0x6b
  created by github.com/olivere/elastic.NewClient
    /Users/phil/go/src/github.com/olivere/elastic/client.go:60 +0x26e

  goroutine 186 [chan receive]:
  github.com/olivere/elastic.(*Client).pinger(0xc208106d00)
    /Users/phil/go/src/github.com/olivere/elastic/client.go:79 +0x6b
  created by github.com/olivere/elastic.NewClient
    /Users/phil/go/src/github.com/olivere/elastic/client.go:60 +0x26e

  goroutine 230 [chan receive]:
  github.com/olivere/elastic.(*Client).pinger(0xc208106dc0)
    /Users/phil/go/src/github.com/olivere/elastic/client.go:79 +0x6b
  created by github.com/olivere/elastic.NewClient
    /Users/phil/go/src/github.com/olivere/elastic/client.go:60 +0x26e

可能这个回溯中更重要的部分是:

  

错误400:ElasticsearchIllegalArgumentException [没有名称[vehicle]的功能]

所以,不知道这里到底出了什么问题。我在索引上有1秒的超时,因为这个客户端不支持“等待绿色”逻辑[还]。

func ResetVehicleIndex(client *elastic.Client) (err error) {

    if _, err = client.DeleteIndex(vehicleIndex).Do(); err != nil {
        return
    }
    if _, err = EnsureVehicleIndex(client); err != nil {
        return
    }

    // TODO: This is awful. Switch to "wait for green" when elastic client supports it
    time.Sleep(time.Second * 1)

    return nil
}

这适用于大多数其他测试,因为elasticsearch似乎在一秒左右就准备好了,但是无论代码中的等待时间如何,这些测试都会一直出错。

有什么想法吗?我可能需要编辑问题以添加更多代码或更好的解释,但我会快速回答任何问题,特别是如果你在Twitter @philsturgeon上ping我。我真的很困惑。

2 个答案:

答案 0 :(得分:10)

该异常是only triggered in one place,这是在Get Index API调用期间。这意味着您的车辆ID必须为空:

fetch, err := client.Get().
        Index(vehicleIndex).
        Type("vehicle").
        Id(vehicle.Id).       //<-- this
        Do()

您正在尝试使用格式为GET /{index}/{type}/{id}的Get Document API。但是,您的客户并没有区分Get Document和Get Index API调用......并且它不会验证您的参数是否为空。

因此,如果将null vehicle.Id传递给Get方法,那么您的最终网址实际上将为GET /{index}/{type}/

从Elasticsearch的角度来看,这不再是Get Document API调用......它实际上是一个Get Index调用,它具有以下格式:GET /{index}/{feature}。功能可以是以下之一:_settings_mappings_aliases_warmers

由于vehicle不是这些功能之一,因此ES会抛出异常并喷出。您可以从控制台验证这一点:

curl -XGET localhost:9200/my_index/vehicle/

答案 1 :(得分:0)

为了完整性:当我用“post”而不是“POST”初始化我的请求方法时,我遇到了同样的错误

像这样:

req, _ := http.NewRequest("post", url, query)
// returns: Error 400: ElasticsearchIllegalArgumentException[No feature for name [_bulk]]
req, _ := http.NewRequest("POST", url, query)
// works just fine