【ElasticSearch】WordデータをElasticSearchに投入

# はじめに
ElasticSearchにWordのデータ投入をどうにかできないかということで、ElasticSearchのingest-attachmentプラグインを用いてファイルの取り込みを検証

↓参考の記事
https://qiita.com/tsgkdt/items/6dec64a8e98dfbf8ab24

# 投入するデータ
下記のような職務経歴書のテンプレートを投入してみようと思います
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306026/1d96cc4a-c87a-17a9-d2e4-666af2d30775.png)


# ingest-attachmentプラグインのインストール
下記コマンドをコマンドプロンプトで実行

```
elasticsearch-plugin.bat install ingest-attachment
```

# C#のソース

```C#:ElasticSearch.cs
// ElasticSearchのURLを定義
public static string ApiUrl = "http://localhost:9200";

// ElasticSearchのingest-attachmentプラグインを用いてファイルの取り込み
public static void RegistWordData()
{
    var indexDefinition = new IndexDefinition(new Uri(ApiUrl));
    var file = new FileInfo(@"任意のwordファイル.doc");

    // wordのデータをElasticSearchに登録
    indexDefinition.CreateMapping()
        .PutPipeline()
        .AddAttachment("1", file)
    ;
}
```

```C#:IndexDefinition.cs（ほとんどコピペ）
using ConsoleElasticSearchSample.Model;
using Nest;
using System;
using System.IO;
using System.Net.Http;

namespace ConsoleElasticSearchSample
{
    class IndexDefinition
    {
        private readonly string DocumentsIndex = "worddata";

        private readonly ElasticClient _client = null;

        /// <summary>
        /// ElasticClientを生成するコンストラクタ
        /// 接続したいElasticSearchのエンドポイントを指定します。(例：new Uri("http://192.168.1.1:9200/"))
        /// </summary>
        /// <param path="uri">ElasticSearch接続先</param>
        public IndexDefinition(Uri uri = null)
        {
            var connectionSettings = new ConnectionSettings(uri)
                .DefaultMappingFor<IndexModel>(m => m
                        .IndexName(DocumentsIndex)
                //CallDetails.DebugInformationを出す用に
                ).DisableDirectStreaming()
                ;
            _client = new ElasticClient(connectionSettings);
        }

        /// <summary>
        /// Indexとマッピングを生成します。
        /// </summary>
        /// <returns></returns>
        public IndexDefinition CreateMapping()
        {
            /*
            var indexResponse = _client.CreateIndex(DocumentsIndex, c => c
                .Settings(s => s
                        .Analysis(a => a
                                .Analyzers(ad => ad
                                        .Custom("windows_path_hierarchy_analyzer", ca => ca
                                                .Tokenizer("windows_path_hierarchy_tokenizer")
                                        )
                                )
                                .Tokenizers(t => t
                                        .PathHierarchy("windows_path_hierarchy_tokenizer", ph => ph
                                                .Delimiter('\\')
                                        )
                                )
                        )
                )
                .Mappings(m => m
                    .Map<Document>(mp => mp
                        .AutoMap()
                        .AllField(all => all
                                .Enabled(false)
                        )
                        .Properties(ps => ps
                            .Text(s => s
                                    .Name(n => n.Path)
                                    .Analyzer("windows_path_hierarchy_analyzer")
                            )
                            .Object<Attachment>(a => a
                                .Name(n => n.Attachment)
                                .Properties(p => p
                                    .Text(t => t
                                        .Name(n => n.Content)
                                        .Fields(f => f
                                            .Keyword(k => k.IgnoreAbove(256)))
                                        )
                                    )
                            .AutoMap()
                            )
                        )
                    )
                )
            );
*/
            var indexResponse = _client.Indices.Create(DocumentsIndex, c => c
                .Settings(s => s
                    .Analysis(a => a
                        .Analyzers(ad => ad
                            .Custom("windows_path_hierarchy_analyzer", ca => ca
                                .Tokenizer("windows_path_hierarchy_tokenizer")
                            )
                        )
                        .Tokenizers(t => t
                            .PathHierarchy("windows_path_hierarchy_tokenizer", ph => ph
                                .Delimiter('\\')
                            )
                        )
                    )
                )
                .Mappings(m => m
                    .Map<IndexModel>(mp => mp
                        .AllField(all => all
                            .Enabled(false)
                        )
                        .Properties(ps => ps
                            .Number(n => n
                                .Name(nn => nn.id)
                            )
                            .Text(s => s
                                .Name(n => n.path)
                                .Analyzer("windows_path_hierarchy_analyzer")
                            )
                            .Object<Attachment>(a => a
                                .Name(n => n.Attachment)
                                .Properties(p => p
                                    .Text(t => t
                                        .Name(n => n.Name)
                                    )
                                    .Text(t => t
                                        .Name(n => n.Content)
                                    )
                                    .Text(t => t
                                        .Name(n => n.ContentType)
                                    )
                                    .Number(n => n
                                        .Name(nn => nn.ContentLength)
                                    )
                                    .Date(d => d
                                        .Name(n => n.Date)
                                    )
                                    .Text(t => t
                                        .Name(n => n.Author)
                                    )
                                    .Text(t => t
                                        .Name(n => n.Title)
                                    )
                                    .Text(t => t
                                        .Name(n => n.Keywords)
                                    )
                                )
                            )
                        )
                    )
                )
            );
            return this;
        }

        /// <summary>
        /// マッピングを取得します。
        /// </summary>
        /// <returns></returns>
        //public IGetMappingResponse GetMapping()
        //{
        //    var mappingResponse = _client.GetMapping<Document>();
        //    return mappingResponse;
        //}

        /// <summary>
        /// Attachments用のパイプラインを設定します。
        /// </summary>
        /// <returns></returns>
        public IndexDefinition PutPipeline()
        {
            _client.Ingest.PutPipeline("attachments", p => p
                .Description("Document attachment pipeline")
                .Processors(pr => pr
                    .Attachment<IndexModel>(a => a
                        .Field(f => f.Content)
                        .TargetField(f => f.Attachment)
                        .IndexedCharacters(-1)
                    )
                    .Remove<IndexModel>(r => r
                        .Field(ff => ff
                        .Field(f => f.Content))
                    )
                )
            );
            return this;
        }

        /// <summary>
        /// ファイルを登録します。
        /// </summary>
        /// <param path="id">ID</param>
        /// <param path="file">インデックスしたいファイル</param>
        /// <returns></returns>
        public IndexDefinition AddAttachment(string id, FileInfo file)
        {
            var bytes = File.ReadAllBytes(Path.Combine(file.FullName));
            Index(bytes, id, file.FullName);
            return this;
        }

        /// <summary>
        /// ネット上に転がっているファイルを登録します。
        /// </summary>
        /// <param path="id">ID</param>
        /// <param path="uri">URL</param>
        /// <returns></returns>
        public IndexDefinition AddAttachment(string id, Uri uri)
        {
            var bytes = new HttpClient().GetByteArrayAsync(uri).Result;
            Index(bytes, id, uri.AbsolutePath);
            return this;
        }

        /// <summary>
        /// ElasticSearchに登録します
        /// </summary>
        /// <param path="content">ファイルの中身</param>
        /// <param path="id">登録するID</param>
        /// <param path="path">パスに指定する</param>
        private void Index(byte[] content, string id, string path)
        {
            var base64File = Convert.ToBase64String(content);
            var res = _client.Index(new IndexModel
            {
                id = id,
                path = path,
                Content = base64File
            }, i => i.Pipeline("attachments"));

            Console.WriteLine(res.DebugInformation);
        }
    }
}

```

# kibanaでデータ確認
下記コマンドを実行

```
get /worddata/_search
```
データが確認されていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306026/a2a9afeb-8be0-0c3c-83bd-74b316170abe.png)