複数のExcelファイルを、fzfやpeco等のfuzzy finderツールを用いて曖昧検索ができるgem「exfuz」をリリースしました!
目次
gemの概要
exfuzは、複数のExcelファイル内のテキスト(現バージョンではセルのテキストのみ)を対象に曖昧検索が出来るTUIツールです。曖昧検索にはfuzzy finderツール*1を利用します。
さらにwsl環境でgemを利用する場合、曖昧検索で選択した箇所へのジャンプが可能です。つまり、選択したセルをアクティブ状態にすることが可能です。
開発した経緯
開発した経緯は、前職で経験したExcelの辛い問題を解決したいためです。
私の前職は、SES企業(SIer業界)のプログラマです。
いくつかのプロジェクトを携わりましたが、要件定義や設計等を管理するドキュメントツールはExcelでした。Excelは便利機能が豊富ですが、ドキュメントを管理する手段としては辛い点が多々ありました。
特に辛いと感じた箇所は以下です。
- 検索機能が使いづらい
- 正規表現検索が出来ない
- 検索文字列の入力から検索までの手順が手間
- 複数のファイル(Book)を横断して検索ができない
- ターミナル上で検索できない
ドキュメント数が少ない場合は、上記の不便さに目を瞑ることも出来ました。
しかし、プロジェクト規模が大きい場合、そうは行かなかったです。ドキュメント数が膨大になり、ナレッジの検索に多大な時間を要するため、非効率な時間が増えました。
この問題は私だけでなく、当時のチームメンバーも同様の悩みを抱えてました。(ターミナル上で検索したいというメンバーがいるかは定かではないですが。。。)
このような背景から、Excelを使ったドキュメント管理の苦労を削減できればと思い、TUIツールを作ることにしました。
使い方
ここでは、exfuzの最低限の使い方について解説したいと思います。詳細はREADMEをご覧ください。
まず、起動コマンドは以下となります。
exfuz start
起動後の画面は、初期画面と曖昧検索画面の2つで構成されます。
初期画面では、情報の表示とキー入力によるイベントの受付けを担います。
曖昧検索画面では、Excelファイル内のテキストを曖昧検索します。曖昧検索の対象ファイルは、カレントディレクトの階層内のxlsxファイルとなります。
初期画面
起動をすると、以下の初期画面が表示されます。
上図の①は、クエリの入力エリアになります。入力した文字列は、曖昧検索の対象(セルのテキスト)をフィルタリングすることが可能です。
②は、xlsxファイルの解析ステータスになります。内訳としては以下となります。
- 左:現時点で曖昧検索可能なファイル数
- 右:曖昧検索の対象となる全ファイル数
①について詳細に説明します。例として、2つのxlsxファイルを曖昧検索の対象にexfuzを起動してます。
クエリがブランクの場合は、2つのxlsxファイルの全セルが曖昧検索の対象となります。下図は、クエリがブランクのときの曖昧検索画面になります。
次に、クエリに文字列がある場合です。
例えば、クエリエリアに正規表現の test.*data
を入力します。この場合の曖昧検索画面では、下図のようにクエリにマッチしたセルのみ曖昧検索の対象となります。
fuzzy finderツールで選択した後は、初期画面に戻ります。下図の③のように選択行の一覧が表示されます。
曖昧検索画面
曖昧検索画面は初期画面から遷移でき、下図のような画面が表示されます。
曖昧検索画面の構成はfuzzy finderツールに依存します。上図の曖昧検索画面は、fuzzy finderツールであるfzfを使用した場合です。
標準入力の各1行ごとの内容は、以下のようなフォーマットで構成された文字列となります。フォーマットは、各項目ごとに区切り文字を連結した文字列です。
行番号:ファイル名:シート名:セル番地:セルのテキスト
行番号は、標準入力に渡したデータの順序となります。また、各項目ごと区切り文字は:
です。
使用技術とシステム構成
使用した技術は以下となります。
- Ruby 3.0.2
- Powershell
- gem
次に、exfuzのコア機能のシステム構成について概要を説明します。
下図はシステム構成図となります。
全体的な処理の流れは、左から右への一方通行となります。
はじめに上図①のパース処理です。
Excelで利用されるxlsxファイルはxmlファイルの圧縮ファイルで構成されています。そのため、普段私達が見慣れた形式(ブック、シート、セル)に変換するためにパース処理を行います。
次に、パースされたデータをキューに格納していきます。データは、「ブック名、シート名、セル番地、セル内の値」から構成されてます。
そして、曖昧検索を起動すると上図②、③の処理を実行します。
キュー内のデータからレコード格納オブジェクトにデータを移します。
レコード格納オブジェクトでは、フィルタリングやグルーピングが出来る振る舞いを用意しました。フィルタリング機能は、クエリによる曖昧検索対象の絞り込みに用います。
最後に、fuzzy finderツールをサブプロセスで起動し、標準入力にデータを流し込みます。
処理の流れは逐次ですが、実際には並行処理が行われています。 上図の2色の矢印(緑色とオレンジ色)でスレッドを分け、スレッド構成は以下となります。
- 緑色矢印の処理:メインスレッド(プログラム実行時に作成されたスレッド)
- オレンジ色矢印の処理:ワーカースレッド(メインスレッドとは別のスレッド)
このように処理を別のスレッドに分けることで、パース処理が未完了の状態でも曖昧検索を可能にしました。
技術選定
使用技術とシステム構成
で述べましたが、exfuzはいくつかのgemを利用しています。ここでは、重要な処理を担うgemのXsv
を選定した理由について述べます。
exfuzはExcelのファイル、つまりxlsxファイルをパースし、ブック、シート、セル等のExcelの構成要素に変換します。 Xsv
はこのパース処理を担います。
Excelをパースするgemは他にもいくつかありますが、その中から Xsv
を選定した理由は、パース処理が高速だからです。
xlsxファイルは、xmlファイル群をzip形式で圧縮したものです。テキストファイル同様に曖昧検索を可能にするためには、パース処理が必要になります。Excelの曖昧検索の速度は当然、テキストファイルの曖昧検索と比較すると遅いです。そのため、いかにExcelとテキストファイル間で曖昧検索の処理速度の差を縮められるかが、ユーザー体験を向上させる上で重要だと考えました。
パース処理の速度の調査と検証は、以下のブログを見た上で、軽めのパフォーマンス検証を行いました。その結果、最も高速だったXsv
を採用するに至りました。
パフォーマンス以外でも実装コストの懸念は若干ありました。Xsv
以外のgemは、概ねExcelの高機能な操作が可能なため、実装コストの削減でメリットがありました。しかし、リリース予定のexfuzは、機能をシンプルにしたかったので、パース後のExcel操作は最低限の自前実装でも何とかなると判断しました。
苦労した点
苦労したことは、設計と実装です。
exfuzの機能はシンプルですが、設計と実装の難易度が、経験上最も高かったです。スクラッチ開発が必要な機能が多く、そのような機能の設計・実装に着手した当初は、方針の目処が全く立たない状況でした。
そんな状況下でも少しずつですが、開発に粘り強く取り組みました。小さく問題を切り分けたり、知識を増やしていくことで自力でリリースすることが出来ました。設計や実装方法の知見は、類似した機能を持つOSSのAPIやコード、技術書を参考にして増やしました。
具体的には、以下のOSS、技術書が大変参考になりました。
- TUIの作成
- マルチスレッド、サブプロセスの扱い方
- データのフィルタリング・集計処理のインターフェース設計
- pandasのGroupbyオブジェクト
- RailsのActiveRecord::Relation
- gemに関連する実装方法
直近で対応したいこと
リリース速度を優先させたため、改善すべき点や追加したい機能が沢山あります。課題がある中で、直近で対応したいことは以下があります。
- コードのリファクタリング
- テストコードも含めて汚いです。モジュール化はある程度しましたが、特に命名が分かりづらいので早期に修正したいです。
- Windows環境対応
- exfuzのシングルバイナリ化
- ユーザーの中にはRubyが入ってない環境もあると思われるので、手軽に導入出来るようにしたいです。
最後に
今回の開発では、OSSのコードリーディングをしたことが非常に良い経験となりました。OSSの設計・実装がハイレベルなので、コードを読み解く経験が私の血肉となりました。将来的には、今回参考にしたOSSのような技術力を身につけたいので、自己研鑽に努めてきたいと思います。
そして、OSSに対しての感謝の気持ちが一段と増しました。スクラッチ開発で苦労したこともあり、普段何気なく使っていたOSSへの有難みが身に沁みました。
TwitterでExcelに関するツイートを眺めると、「Excelの検索が辛い」と感じるユーザーは多そうでした。開発したgemによって、ユーザーの苦労を少しでも減らせたら嬉しいです。
しかし、リリースを優先したこともあって、exfuzは、機能数も少なく使い勝手が悪い部分も多いです。
より良くするために今後も開発を継続していきたいと思います。