F# を使って雑にExcelから取り出したデータをElasticsearchに放り込む

この記事はF# Advent Calendar 2017の25日目の記事です。 大遅刻しましたごめんなさい…。

とあるExcelファイルがでかすぎて閲覧するのに苦痛だったので書きなぐった時のメモ。 .NET Coreです。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Program.fs" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="EPPlus" Version="4.5.0.1-beta" />
    <PackageReference Include="Nest" Version="5.6.0" />
  </ItemGroup>
</Project>

まだbeta段階ですがEPPlusもnetstandard版があります。

open System
open System.IO
open OfficeOpenXml
open Nest

let getSheet (sheet: string) (excel: ExcelPackage) =
  excel.Workbook.Worksheets.[sheet]

type Questionnaire = {
  Value: string
}

let getQuestionnaire (excel: ExcelPackage) =
  let sheet = getSheet "アンケート" excel
  seq {
    for i in [ 2 .. Seq.length sheet.Cells - 1] ->
      {
        Value = sheet.Cells.[i, 1].Text
      }
  }

let questionnairesIndex = IndexName.op_Implicit "questionnaires"

let createIndex (name: IndexName) (client: ElasticClient) =
  client.CreateIndex(name)
  |> ignore

let insertQuestionnaire (client: ElasticClient) (messages: Questionnaire seq) =
  client.IndexMany(messages, questionnairesIndex, TypeName.op_Implicit "questionnaire")
  |> ignore

[<EntryPoint>]
let main argv =

  let file = argv.[0]
  let url = argv.[1]
  let user = argv.[2]
  let pass = argv.[3]

  use excel = new ExcelPackage(File.OpenRead(file))

  printfn "try to connect %s" url

  use settings =
    (new ConnectionSettings(Uri(url)))
      .BasicAuthentication(user, pass)
      .DisableDirectStreaming()
  let client = ElasticClient(settings)

  createIndex questionnairesIndex client

  getQuestionnaire excel
  |> insertQuestionnaire client

  0

仕様だったりCellにheaderが付いていた関係だったりでindexが少々ずれていますが気にしないでください。 雑に取得してdockerで立ち上げたElasticsearchに放り込むくらいだったらこれで十分ですはい。

とはいえElasticsearch 6.0系からmulti typeが廃止されたという事実に気づかずどハマりしましたが…。