将文档上传到 FSCrawler 以在 Elasticsearch 中建立索引的正确方法

Proper way to upload a doc to FSCrawler for indexing in 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 时,我得到了一切,比如 "filename" 被正确设置。如果我像上面那样使用它,在 Rails 控制器中,如您所见,文件名设置为临时文件的文件名。这不是一个可行的解决方案。尝试使用 params[:document][:upload].tempfile(不使用 .path)或仅使用 params[:document][:upload] 都完全失败。

我正在尝试执行此操作 "the right way," 但是每次使用适当的 HTTP 客户端执行此操作都失败了。我不知道如何调用 HTTP POST 以 curl(在命令行上)的方式将文件提交给 FSCrawler。

在此示例中,我只是尝试使用 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

如果我将 以上 更改为使用 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,并尝试通过引用临时文件的实际路径来发送文件,那么我会收到此错误消息,但我什么也得不到:

## 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。我在这方面的时间比我愿意承认的要长得多。我在这里错过了什么?

我终于尝试了 Faraday, and, based on this answer,得到了以下结果:

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' 添加到连接设置的末尾。