コンテンツにスキップ

設計の概要

扱うこと: 設計書全体の目的・方式(用語)・全体構成・動作環境と、読む人ごとの入口。扱わないこと: 各処理の仕様そのもの(各区分のページで扱う)。先に読むページ: なし(ここが設計書の入口)。

設計書は scripts/*.ps1 および起動用 tebunko.bat の実装から仕様を書き起こしたものである。記載内容は現行実装の挙動を正とする。

本ツールは画面(tebunko.bat)から使う。インデックス作成・検索はすべて画面から行い、コンソールでの操作(.bat の実行・設定ファイルの手編集・キー入力)は前提としない。

設計書の構成

初めて読む・変更に取りかかるときの入口は はじめに(読む順番・1 周の流れ)と 変更の種類から見る設計書を引く にある。

flowchart TB
    top["design/index.md<br>(このページ)"]
    top --> start["start/ はじめに"]
    top --> structure["structure/ 全体の構成"]
    top --> indexing["indexing/ インデックス作成"]
    top --> data["index-data/ インデックスのデータ"]
    top --> search["search/ 検索"]
    top --> gui["gui/ 画面"]
    top --> testing["testing/ テストと CI"]
    top --> ref["reference/ 関数一覧"]
    start -. 読む順番 .-> structure
    structure -. 流れ .-> indexing
    indexing -. 作ったものの形 .-> data
    data -. 読む .-> search
    search -. 見せる .-> gui

目的

フォルダ配下に大量に存在する Office ファイル・テキストファイル・PDF ファイルに対し、ファイルを開かずに全文検索できるようにする。

種類 拡張子
Excel .xlsx / .xlsm / .xls / .xlsb
Word .docx / .docm / .doc
PowerPoint .pptx / .pptm / .ppt
テキスト 対象の拡張子
PDF .pdf(PDF ファイルの読み取り)

方式

2 段階方式を採る。Office ファイル・テキストファイル・PDF ファイルから抽出した文字列を索引データ(インデックス)として事前に保存し、検索時はインデックスのみを照合する。これにより、検索のたびにファイルを開く処理を省く。インデックスの中身の具体例は インデックスとは(はじめて読む方へ) にある。

  1. インデックス作成(インデックス作成) 各ファイルを取り込み、「場所」(Excel のシート、Word のページ、PowerPoint のスライド、PDF のページ、テキストは「本文」の 1 つ)ごとの TSV(UTF-8)に書き出し、フォルダの取り込みが終わるとフォルダ・拡張子ごとの本文インデックスにまとめて work/store/content/ に蓄積する。Excel のセルは COM で操作してテキストを抽出し、Excel の図形・コメントと Word・PowerPoint はファイル(ZIP 内の XML)を直接読む(Word・PowerPoint の旧形式は Word・PowerPoint で新形式に変換してから読む)。テキストファイルは文字コードを判定してから行に分けて読む(テキストファイルの読み取り)。PDF は PowerShell だけでページごとの文字を読む(PDF ファイルの読み取り)。2 回目以降は、取り込み済みで更新の無いファイルをスキップする(差分取り込み)。
  2. 検索(検索) 本文インデックスを検索し(大文字と小文字の区別・正規表現・ファイルの種類の条件はサクラエディタの Grep にならう)、ヒットした「ファイル名(相対フォルダ付き)・場所・該当行」を、元のファイルごとの見出しにまとめて画面の表に表示する。必要なときは work/search_results.txt に出力する。

どちらも画面(画面)から行う。インデックス作成は画面のプロセスの中のスレッドで動き、進み具合を画面に表示する(プロセスとスレッド)。画面には、インデックス作成を異常終了させた際に残る Excel・Word・PowerPoint のプロセスを強制終了する機能もある。

用語は検索エンジンにならい、画面・設計書・コードで次のようにそろえる。

用語 意味・置き場所 画面に出すか コードでの名前
インデックス作成 クロールから取り込みまでの一連の処理(開始・中止・中断・再開の単位) 出す indexing(画面側)、indexer.ps1・indexer/
インデクサ インデックス作成を行うプログラム(indexer.ps1) 出す indexer
クロール クロール対象フォルダをたどって Office・テキストのファイルを列挙し、取り込むファイルを決める 出す createTargetList・findTargetFiles
取り込み 1 ファイルをインデックスに入れる(Office もテキストも、コピー → 抽出 → コピーを消す → TSV に書き出す → インデックスに置く) 出す ingest
抽出 元のファイルからテキストを読み出す 出さない extract
インデックス 登録したフォルダ 1 件ぶんの索引。本文インデックスと 2-gram の索引を合わせたもの 出す index
本文インデックス 検索が照合する本体。フォルダ 1 つ・元のファイルの拡張子 1 つにつき、大きさで分けて 1 つ以上。work/store/content/<インデックス名>/<相対フォルダ>/content_index.<拡張子>.<番号>.tsv。1 つずつを指すときは「本文インデックスのファイル」 出さない contentIndex
2-gram の索引(gram 索引) 検索で照合する本文インデックスのファイルを絞るための索引。インデックス 1 つにつき、目録 1 つと区画のファイル。work/store/gram/<インデックス名>/toc.tsv・g<10 桁>.seg。作り直せる派生データ 出さない gram
本文インデックスに入れる前の TSV 取り込んでから本文インデックスに入れるまでの一時的な TSV。work/store/content/<インデックス名>/<相対フォルダ>/<元のファイル名>/<場所>.tsv。インデックス作成が途中で止まったときだけ残る 出さない 変えない(無し)
元のフォルダの記録 work/store/content/<インデックス名>/source_folder.txt(インデックス名と登録したフォルダの対応。インデックスを写しても元の場所が分かるようにする) 出さない sourceFolderFileName
本文インデックスのフォルダ ワークスペースの store/content/ 手引き・README ではフォルダの名前として出す Workspace.IndexDir
インデックスの追加 フォルダをインデックスとして一覧に登録する(中身は取り込まない) 出す newIndex

store/content/ の中身は本文インデックス・入れる前の TSV・元のフォルダの記録の 3 種類で、本文インデックスは store/content/ の中身すべてではない。コードの名前 contentIndex(関数・変数・ファイル名)は、設計書でもそのまま書く。計測の結果の項目(Index.Pack など)と段階の名前(pack の作成)は、実行をまたいで数字を比べるため、前の名前のまま残している。

「変換」は、旧形式を新形式に保存し直す処理(.doc → .docx など)のように、形式を変えることだけに使う。検索ワード・件・該当行・元のファイルは検索エンジンの用語に合わせず、そのまま使う。

全体構成

flowchart LR
    user(["利用者"])

    bat["tebunko.bat"]

    subgraph scripts["scripts/"]
        subgraph tool["tebunko/(このツール固有)"]
            gui["gui.ps1<br>画面の起動口<br>(ui/ 配下を読み込む)"]
            conv["indexer.ps1<br>インデクサの起動口<br>(indexer/ 配下を読み込む)"]
            common["lib.ps1<br>画面以外の部品の読み込み口<br>(core/・index/・indexer/・search/)"]
        end
        subgraph sh["shared/(どのツールからも使う)"]
            shared["shared.ps1<br>共通基盤の読み込み口<br>(core/・office/)"]
            reader["office/office_reader.ps1<br>Word・PowerPoint と<br>Excel の図形・コメントの読み取り"]
            app["office/office_app.ps1<br>Officeアプリの起動・終了"]
        end
    end

    c1["setting.config<br>画面が保存する設定<br>(クロール対象フォルダ・検索対象インデックスなど)"]

    subgraph work["work/(自動生成)"]
        idx[("store/content/<br>本文インデックス")]
        status["store/ingest_status.tsv<br>(更新日時・状態)"]
        ctl["indexing_log.txt<br>store/journal/ingest.tsv"]
        out["search_results.txt<br>([結果をファイルに出力])"]
    end

    tmp[("work/tmp/#lt;PC の鍵#gt;/#lt;PID#gt;<br>取り込みの作業領域<br>(置けないときはスキップ)")]
    src[("クロール対象フォルダ<br>Excel・Word・PowerPoint・テキスト・PDF のファイル群")]
    excel["Microsoft Excel<br>(COM)"]
    office["Microsoft Word / PowerPoint<br>(COM。旧形式の変換のみ)"]

    user --> bat --> gui
    gui -- "スレッドで実行(-Channel)" --> conv
    gui -. "dot-source" .-> common
    conv -. "dot-source" .-> common
    common -. "dot-source" .-> shared
    conv -. "dot-source" .-> reader
    conv -. "dot-source" .-> app

    gui <--> c1
    c1 --> conv
    src --> excel & office & reader
    app <--> excel
    app <--> office
    conv --> reader
    conv <--> status
    gui <--> status
    gui --> ctl
    conv <--> ctl
    conv --> tmp --> idx

    idx --> gui
    gui --> out
    gui -- "強制終了" --> excel & office

ソースの分け方(文脈と層)は ソースの分け方、インデックスを作って検索するまでの 1 周の流れは はじめに を参照。

動作環境・前提条件

項目 内容
OS Windows
実行環境 Windows PowerShell 5.1(powershell.exe)
必須ソフトウェア Microsoft Excel(Excel.Application COM オブジェクトを使用。Excel ファイルの取り込みに必要)
任意のソフトウェア Microsoft Word・PowerPoint(旧形式 .doc .ppt、パスワード付き、拡張子と中身が異なる Word・PowerPoint ファイルの取り込みにのみ使用。新形式の .docx .pptx 等は無くても取り込める)
起動方法 tebunko.bat をダブルクリック。conhost.exe を通して -ExecutionPolicy RemoteSigned -WindowStyle Hidden で画面を開く(Bypass は使わない。PowerShell の窓は残らない)。zip 展開で付く Mark-of-the-Web は、同じ PowerShell が画面のスクリプトを実行する前に消す(Unblock-File)ため、RemoteSigned のままスクリプトを実行できる。PowerShell の起動は 1 回だけ。インデクサは画面のプロセスの中のスレッドで動く(別の powershell.exe は起動しない)。詳細は 画面の共通仕様
スクリプトの文字コード scripts/*.ps1・tests/*.ps1 は UTF-8(BOM 付き)、改行 CRLF。PowerShell 5.1 は BOM なしファイルをシステム既定コードページ(CP932)で読むため、BOM を外すと日本語リテラルが化ける
テスト Pester 5.9.0(版を固定する。入れ方は CONTRIBUTING)。.\tests\run.ps1(詳細は テストの実行と CI)