【问题标题】:How to perform a GET request for Elasticsearch in R如何在 R 中对 Elasticsearch 执行 GET 请求
【发布时间】:2021-03-27 18:59:53
【问题描述】:

我是 Elasticsearch 的新手,我正在尝试在 R 中运行一个基本查询。因为我需要一个 API 密钥,所以我无法在 R 中使用任何可用的 Elasticsearch 库。

我可以检索弹性搜索索引中的所有文档,但我似乎无法运行自定义查询。我想这一定是因为我的GET 请求格式不正确。这是我目前所拥有的:

json_query <- jsonlite::toJSON('{
    "query": {
        "match" : {
            "LastName": "Baggins"
        }
    }
}
')

我尝试将 my_query 添加为 body= 参数,但它只是不运行查询(而是检索 10000 个文档)。我最终尝试将其粘贴到 url 参数:

get_scroll_id <-  httr::GET(url =paste("'https://Myserver:9200/indexOfInterest/_search?scroll=1m&size=10000'",my_query),
                            encoding='json',
                            add_headers(.headers = c("Authorization" = "ApiKey ****", "Content-Type" = "application/json")),
                            config=httr::config(ssl_verifypeer = FALSE,ssl_verifyhost = FALSE))

scroll_data <- fromJSON(content(get_scroll_id, as="text"))

这给了我错误:

Error in curl::curl_fetch_memory(url, handle = handle) : 
  Protocol "" not supported or disabled in libcurl

我也尝试将查询添加为查询参数,如下所示:

get_scroll_id <-  httr::GET(url ='https://Myserver:9200/indexOfInterest/_search?scroll=1m&size=10000',
                            query= json_query,
                            encoding='json',
                            add_headers(.headers = c("Authorization" = "ApiKey *****==", "Content-Type" = "application/json")),
                            verbose(),
                            config=httr::config(ssl_verifypeer = FALSE,ssl_verifyhost = FALSE))

这给了我输出:

GET https://Myserver:9200/indexOfInterest/_search?{
    "query": {
        "match" : {
            "LastName" : "Baggins"
        }
    }
}

Options:
* ssl_verifypeer: FALSE
* ssl_verifyhost: FALSE
* debugfunction: function (type, msg) 
{
    switch(type + 1, text = if (info) prefix_message("*  ", msg), headerIn = prefix_message("<- ", msg), headerOut = prefix_message("-> ", msg), dataIn = if (data_in) prefix_message("<<  ", msg, TRUE), dataOut = if (data_out) prefix_message(">> ", msg, TRUE), sslDataIn = if (ssl && data_in) prefix_message("*< ", msg, TRUE), sslDataOut = if (ssl && data_out) prefix_message("*> ", msg, TRUE))
}
* verbose: TRUE
Headers:
* Authorization: ApiKey *****==
* Content-Type: application/json

查看Elasticsearch文档,curl如下:

 curl 'localhost:9200/get-together/event/_search?pretty&scroll=1m' -d ' {
 "query": {
"match" : {
 "LastName" : "Baggins"
 }
 }
}'

如何为 Elasticsearch 创建正确的命令?

【问题讨论】:

  • 使用 paste() 构建 URL 似乎不正确。只需将基本 URL 放在那里并使用 query=my_query 作为单独的参数(不是 body= 参数)
  • 我现在已经完成了@MrFLick,但我得到如下: curl::curl_fetch_memory(url, handle = handle) 中的错误:URL 使用错误/非法格式或缺少 URL。我已经更新了答案
  • myquery 到底是在哪里定义的?和json_query一样吗?因此 curl 命令确实会显示 json_query 的内容进入正文,因此您不想将其粘贴到 URL。
  • json_query 和 myquery 是一样的。对不起错字。我已经纠正了。根据上面问题的第二部分,我已经删除了粘贴,它只在查询参数中说明,但错误仍然存​​在。
  • 那么httr::GET(url ="https://Myserver:9200/indexOfInterest/_search?scroll=1m&amp;size=10000", encoding='json', add_headers(.headers = c("Authorization" = "ApiKey ****", "Content-Type" = "application/json")), body=my_query) 到底有什么错误?

标签: r elasticsearch


【解决方案1】:

我认为这里的问题是,httr 包根本不支持 body 参数,因为在 GET 请求中使用正文并不常见(查看关于 HTTP GET with request body 的 SO 答案) .

但您也可以在此处使用 POST 请求,这对我有用。请尝试以下方法,看看是否有帮助:

library(httr)
library(rjson)

my_query <- rjson::toJSON(
'{
   "query": {
     "match": {
       "LastName": "Baggins"
     }
   }
 }
'
)

response <- httr::POST(
  url = "https://Myserver:9200/indexOfInterest/_search",
  httr::add_headers(
    .headers = c(
      "Authorization" = "ApiKey ****", 
      "Content-Type" = "application/json"
    )
  ), 
  body = fromJSON(my_query)
)


data <- fromJSON(content(response, as="text"))

编辑:

如果你真的坚持做一个 GET 请求,请尝试使用 curl。我无法测试授权部分,但其余部分正常工作:

library(curl)
library(jsonlite)

my_query <- toJSON(
'{
   "query": {
     "match": {
       "LastName": "Baggins"
     }
   }
 }
'
)

h <- new_handle(verbose = TRUE)
handle_setheaders(h,
   "Authorization" = "ApiKey ****", 
   "Content-Type" = "application/json"
)
handle_setopt(handle = h, postfields=fromJSON(my_query), customrequest="GET")

c <- curl_fetch_memory(url = "https://Myserver:9200/indexOfInterest/_search", handle=h)

prettify(rawToChar(c$content))

这里的技巧是使用postfields 参数来传递正文。但这会触发 curl 库执行 POST 请求。 所以通过设置customrequest="GET",我们明确告诉他使用GET请求。

【讨论】:

  • @Sebastian Zeki,你能检查一下这是否解决了你的问题吗?
【解决方案2】:

jsonlite::toJSON() 的输出可能会被忽略,因为它会将您的 json 包含在 []s 中。如果你改用rjson::toJSON() 会发生什么?

my_query <- rjson::toJSON(
'{
    "query": {
        "match" : {
            "LastName": "Baggins"
        }
    }
}'
)

httr::GET(
  url = "https://Myserver:9200/indexOfInterest/_search",
  query = list(scroll = "1m", size = "10000"), 
  encoding = 'json', 
  httr::add_headers(
    .headers = c(
      "Authorization" = "ApiKey ****", 
      "Content-Type" = "application/json"
      )
  ), 
  body = my_query
)

【讨论】:

  • 我遇到了同样的问题 - 只返回 10000 条记录的默认值,但似乎忽略了查询本身
【解决方案3】:

您也可以试试elastic 库。

conn <- elastic::connect(host = "Myserver", 
                        path = "", 
                        user = "<username>",
                        pwd = "<password>",
                        port = 9200, 
                        transport_schema  = "https")
# conn$ping()

body <-'{
    "query": {
        "match" : {
            "LastName": "Baggins"
        }
    }
}
'
out <- elastic::Search(conn, index="indexOfInterest", body = body, size = 10000)

然后,如果您想滚动以获取超过 10000 个条目(这是弹性对单个查询所允许的最大值)。

# Scrolling
res <- elastic::Search(conn_cloud, index = 'indexOfInterest', time_scroll="5m",body = body, size = 10000)
out <- res$hits$hits
hits = 1
while(hits != 0){
  res <- elastic::scroll(conn, res$`_scroll_id`, time_scroll="5m")
  hits <- length(res$hits$hits)
  if(hits > 0)
    out <- c(out, res$hits$hits)
}
elastic::scroll_clear(conn_cloud, res$`_scroll_id`)

请注意,Elastic does not recommend using scrolling 和我使用它得到的结果略有不同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    相关资源
    最近更新 更多