首页 > 解决方案 > 将文档上传到 FSCrawler 以在 Elasticsearch 中建立索引的正确方法

问题描述

我正在对 Rails 应用程序进行原型设计,以将文档上传到 FSCrawler(运行 REST 接口),以合并到 Elasticsearch 索引中。使用他们的例子,这有效:

response = `curl -F "file=@#{params[:document][:upload].tempfile.path}" "http://127.0.0.1:8080/fscrawler/_upload?debug=true"`

文件被上传,内容被索引。这是我得到的一个例子:

"{\n \"ok\" : true,\n \"filename\" : \"RackMultipart20200130-91061-16swulg.pdf\",\n \"url\" : \"http://127.0.0.1:9200/local/_doc/d661edecf3e28572676e97a6f0d1d\",\n \"doc\" : {\n \"content\" : \"\\n \\n \\n\\nBasically, what you need to know is that Dante is all IP-based, and makes use of common IT standards. Each Dante device behaves \\n\\nmuch like any other network device you would already find on your network. \\n\\nIn order to make integration into an existing network easy, here are some of the things that Dante does: \\n\\n▪ Dante...

当我curl在命令行运行时,我得到了一切,比如正确设置了“文件名”。如果我如上所述使用它,在 Rails 控制器中,如您所见,文件名设置为 Tempfile 的文件名。这不是一个可行的解决方案。尝试使用params[:document][:upload].tempfile(without .path) 或params[:document][:upload]两者都完全失败。

我正在尝试以“正确的方式”执行此操作,但是使用正确的 HTTP 客户端执行此操作的每一个化身都失败了。我不知道如何调用 HTTP POST,它将文件提交给 FSCrawler 的方式curl(在命令行上)。

在此示例中,我只是尝试使用Tempfile文件对象发送文件。出于某种原因,FSCrawler 给了我评论中的错误,并获得了一些元数据,但没有内容被索引:

## Failed to extract [100000] characters of text for ...
## org.apache.tika.exception.ZeroByteFileException: InputStream must have > 0 bytes
uri = URI("http://127.0.0.1:8080/fscrawler/_upload?debug=true")
request = Net::HTTP::Post.new(uri)
form_data = [['file', params[:document][:upload].tempfile,
  { filename: params[:document][:upload].original_filename,
  content_type: params[:document][:upload].content_type }]]
request.set_form form_data, 'multipart/form-data'
response = Net::HTTP.start(uri.hostname, uri.port) do |http|
  http.request(request)
end

如果我将上面的内容更改为 use params[:document][:upload].tempfile.path,那么我不会收到有关 InputStream 的错误,但我也(仍然)没有得到任何索引的内容。这是我得到的一个例子:

 {"_index":"local","_type":"_doc","_id":"72c9ecf2a83440994eb87d28786e6","_version":3,"_seq_no":26,"_primary_term":1,"found":true,"_source":{"content":"/var/folders/bn/pcc1h8p16tl534pw__fdz2sw0000gn/T/RackMultipart20200130-91061-134tcxn.pdf\n","meta":{},"file":{"extension":"pdf","content_type":"text/plain; charset=ISO-8859-1","indexing_date":"2020-01-30T15:33:45.481+0000","filename":"Similarity in Postgres and Rails using Trigrams · pganalyze.pdf"},"path":{"virtual":"Similarity in Postgres and Rails using Trigrams · pganalyze.pdf","real":"Similarity in Postgres and Rails using Trigrams · pganalyze.pdf"}}}

如果我尝试使用 RestClient,并尝试通过引用 Tempfile 的实际路径来发送文件,则会收到此错误消息,但什么也得不到:

## Unsupported media type
response = RestClient.post 'http://127.0.0.1:8080/fscrawler/_upload?debug=true',
  file: params[:document][:upload].tempfile.path,
  content_type: params[:document][:upload].content_type

如果我尝试访问.read()该文件并提交该文件,那么我会破坏 FSCrawler 表单:

## Internal server error
request = RestClient::Request.new(
  :method => :post,
  :url => 'http://127.0.0.1:8080/fscrawler/_upload?debug=true',
  :payload => {
    :multipart => true,
    :file => File.read(params[:document][:upload].tempfile),
    :content_type => params[:document][:upload].content_type
})
response = request.execute

显然,我一直在尽我所能尝试,但我无法复制curl任何已知的基于 Ruby 的 HTTP 客户端所做的任何事情。我完全不知道如何让 Ruby 以一种可以正确索引文档内容的方式向 FSCrawler 提交数据。我在这方面的时间比我愿意承认的要长得多。我在这里想念什么?

标签: rubycurlrest-clientnet-httpfscrawler

解决方案


我终于尝试了Faraday,并且基于这个答案,想出了以下内容:

connection = Faraday.new('http://127.0.0.1:8080') do |f|
  f.request :multipart
  f.request :url_encoded
  f.adapter :net_http
end
file = Faraday::UploadIO.new(
  params[:document][:upload].tempfile.path,
  params[:document][:upload].content_type,
  params[:document][:upload].original_filename
)
payload = { :file => file }
response = connection.post('/fscrawler/_upload', payload)

随着我越来越接近请求,使用Fiddler帮助我看到了尝试的结果。curl此代码段几乎与 curl 一样发布请求。要通过代理路由此呼叫,我只需要添加, proxy: 'http://localhost:8866'到连接设置的末尾即可。


推荐阅读