コンテンツへスキップ

定性コーディングのための全文検索

ある単語に言及するすべてのインタビューの抜粋や自由記述式の回答を見つけ、コーダーが一致するアイテムを自分のキューに取り込めるようにします。

Potato は、サーバーの起動時にすべてのアイテムのテキストに対する全文インデックスを構築し、管理者は、QDA モードの有無にかかわらず、どのプロジェクトでもそのインデックスを検索できます。copay の検索は、「copay」で始まる単語を含む各インタビューの抜粋や自由記述式のアンケート回答を返します。結果は関連度順に並び、一致した単語は短いスニペット内でハイライトされます。任意の設定 search.annotator_claim は、コーディングページに Find パネルを追加します。Find パネルでは、コーダーが同じインデックスを検索し、一致するアイテムを自分のキューに取り込めます。検索と QDA モードは、どちらも Potato 2.6.0 で登場しました。

FTS5 は、SQLite の全文検索拡張です。SQLite は、Potato のプロジェクトストアの背後にある組み込みデータベースです。Potato はインデックスを <task_dir>/project.sqlite のテーブルとして保持し、同じファイルにメモとコードブックも入っています。インデックスには、アイテムの単語が含まれます。コード、メモ、アノテーションはインデックスの外にあり、検索が、見つけた一節にコードを適用することはありません。

検索は、定性研究のプロジェクトで二つの役割を果たします。

  • コーディングする一節を探す。 コーパスをトピックごとに進めるコーダーは、「bus」や「copay」を検索し、その単語に言及するアイテムを取り込み、スパンスキームで関連する一節をコーディングします。
  • コーパス全体で用語を確認する。 コードの包含基準を書くアナリストや裁定者は、用語を検索して、どのアイテムがその用語を使っているかを確認します。どのコーダーのキューも変わりません。

設定

検索に設定は必要ありません。search ブロックのないプロジェクトは、起動時にすべてのアイテムにインデックスを付け、管理者の検索を提供します。以下の設定は、コーダー向けの検索と取り込みもオンにする、完全な QDA モードのプロジェクトです。

yaml
annotation_task_name: Clinic access interviews
task_dir: .
output_annotation_dir: annotation_output/
data_files:
- data/interviews.json
item_properties:
  id_key: id
  text_key: text
admin_api_key: change-this-key
 
qda_mode:
  enabled: true
 
search:
  annotator_claim: true
 
annotation_schemes:
- annotation_type: span
  name: codes
  description: Highlight a passage and apply a code
  codebook: true
  labels: [access barriers, cost concerns, provider trust]

QDA モードは、コーパス全体を一人のコーダーが扱うことを前提としています。qda_mode.enabled: true の下では、Potato は、どの割り当て設計でも annotator_claim を受け付けます。admin_api_key により、スクリプトやコマンドラインから管理者の検索を呼び出せます。

search ブロックは、四つのキーを取ります。

オプションデフォルト説明
search.enabledtrue起動時にインデックスを構築し、検索のエンドポイントを提供します。false にすると、Potato はインデックスを構築せず、管理者の検索は 503 を返します。
search.backendfts5インデックスのエンジン。Potato 2.13.1 のバックエンドは fts5 のみです。それ以外の値は、検索をオフにして警告をログに記録します。
search.max_instances100000インデックスされるアイテムの最大数。Potato は、読み込み順に上限までアイテムにインデックスを付けます。上限を超えたアイテムはインデックスの外に残り、サーバーログが上限を報告します。
search.annotator_claimfalseコーダーに Find パネルを表示し、コーダーの検索と取り込みのエンドポイントを提供します。この設定が割り当て設計と衝突する場合、Potato は起動を拒否します(割り当てのガードを参照)。

誰が検索できるか

管理者の検索とコーダーの検索は、異なるエンドポイントを通じて同じインデックスを読みます。

誰がエンドポイント利用できる条件リクエストあたりの結果
管理者と裁定者GET /admin/api/search?q=<query>&limit=<n>search.enabled が trueデフォルトは 50、最大 500
サインイン済みの任意のコーダーGET /api/search?q=<query>&limit=<n> と Find パネルsearch.annotator_claim: trueデフォルトは 50、最大 200。Find パネルは 50 を要求
サインイン済みの任意のコーダー{"instance_id": "<id>"} を持つ POST /api/search/claimsearch.annotator_claim: trueリクエストあたり一つのアイテム

管理者のアクセスとは、X-API-Key ヘッダーの管理 API キー、または、そのロールが管理ダッシュボードを許可するサインイン済みのユーザーを意味します。adjudication ブロックが有効なプロジェクトの裁定者も、管理者の検索を使えます。管理者の検索は読み取り専用で、どのキューも変えません。Potato 2.13.1 の管理ダッシュボードには検索ボックスがなく、管理者はエンドポイントを通じて検索します。

bash
curl -H "X-API-Key: change-this-key" \
  "http://localhost:8000/admin/api/search?q=copay&limit=20"

このエンドポイントは、次の形の JSON を返します。

json
{
  "count": 1,
  "query": "copay",
  "results": [
    {
      "id": "P01-03",
      "instance_id": "P01-03",
      "score": -0.525,
      "snippet": "My \u0002copay\u0003 went up again this year, so I skipped the follow…"
    }
  ]
}

スニペットは、アイテムの最もよく一致する部分の周囲の最大 12 語に及び、一致した各単語に制御文字 U+0002 と U+0003 で印を付けます。Find パネルは、その印をハイライトに変えます。score は、FTS5 の BM25 ランクです。スコアが低いほどよい一致で、結果は最良の一致から順に返されます。count は返された結果の数です。limit は件数に上限を設け、レスポンスは、上限を超えて一致するアイテムの数を報告しません。

クエリの構文

Potato は、クエリを、文字、数字、アンダースコア以外のすべての文字で分割し、結果として得られたすべての単語を接頭辞として含むアイテムを返します。Potato は、クエリを FTS5 にクエリ構文として渡すことはありません。以下の規則は、その一つの段階から導かれます。

  • すべての単語が現れなければならない。 bus line は、「bus」と「line」の両方を、どちらの順序でも、どれだけ離れていても含むアイテムに一致します。
  • 各単語は接頭辞として一致する。 copay は「copay」、「copays」、「copayment」に一致します。care は「care」のほか、「career」や「careful」にも一致します。
  • 大文字小文字とアクセントは無視される。 Copay と copay は同じアイテムを返し、cafe は「café」に一致します。
  • 句読点は単語を分割する。 self-care は「self」と「care」を検索します。cost-of-care は、テキストのどこかに「cost」、「of」、「care」を含むアイテムを返します。
  • アポストロフィは単語を分割する。 couldn't は「couldn」と「t」を検索します。「couldn't」を含むアイテムは見つかり、スニペットは「t」で始まる他の単語もハイライトします。
  • 演算子は普通の単語である。 引用符と * は除かれ、OR、NOT、NEAR は、アイテムが含まなければならない単語になります。cost OR care のようなクエリは、通常、何も返しません。
  • 語形は統合されない。 run は接頭辞の規則により「running」に一致しますが、ran は「run」には一致しません。参加者が使いそうな各語形を、別々に検索してください。

インデックスされるテキストとインデックスの再構築

Potato は、アイテムごとに一つの文字列にインデックスを付け、次の順序で選びます。

  1. item_properties.text_key(デフォルトは text)が指定するフィールド。
  2. text_key の下にあるリストまたはオブジェクト、たとえば、ターンのリストとして保存された記録。Potato は、コーディングページが表示する JSON テキストを、フィールド名も含めてインデックスします。
  3. text_key の下に使える値がないアイテムには、caption、description、transcript、prompt、question、title、content、message のうち、最初の空でないフィールド。

これらのフィールドがどれもないアイテムはインデックスの外に残り、サーバーログがスキップされたアイテムの数を報告します。キャプションのない画像が典型的な場合です。アイテム ID、participant_id のようなケースのフィールド、その他のアイテムのフィールドはインデックスされず、参加者 ID の検索では何も見つかりません。ケースは、抜粋を参加者ごとにグループ化します。

Potato は、サーバーの起動のたびに、インデックス全体を再構築します。data_directory から読み込まれた調査では、ディレクトリの読み込み後に Potato がインデックスを再構築し、新しいファイルが届くとディレクトリウォッチャーが再インデックスします。Python のビルドの SQLite に FTS5 がない場合、Potato は検索をオフのままにし、検索のエンドポイントは 503 を返し、Potato の残りは通常どおり動作します。

検索と取り込み

Find パネル

search.annotator_claim: true を指定すると、コーディングページに Find ボタンが表示されます。Find パネルはクエリを受け取り、最大 50 件の一致を、それぞれスニペット、アイテム ID、Claim ボタンとともに一覧します。Claim は、アイテムをコーダーのキューの末尾に追加し、ボタンを「In your queue」に置き換えます。すでにコーダーのキューにあるアイテムの取り込みは何も変えず、取り込みのエンドポイントは "already_assigned": true を報告します。パネルはアイテムを開かず、コーダーは、キューを先に進めることで、取り込んだアイテムに到達します。

取り込みのエンドポイントは、プロジェクト内の任意のアイテム ID を受け付けます。ほかのコーダーがすでに持っているアイテムも取り込めます。未知の ID は 404 を、セッションのないリクエストは 401 を、annotator_claim のないプロジェクトは 403 を返します。

割り当てのガード

アイテムを取り込むコーダーはサンプルを選んでいることになり、多くの調査設計は、その選択を Potato が行うことに依存しています。search.annotator_claim: true の場合、設定が次のいずれかも設定していると、Potato は起動を拒否します。

設定Potato が拒否する理由
random、diversity_clustering、max_diversity、active_learning、llm_confidence、least_annotated、category_based、batch、psychometric、model_review、engine に設定された assignment_strategy戦略のサンプルや順序は、Potato が各アイテムを選ぶことに依存しています。
1 を超える num_annotators_per_item、1 を超える overlap_sample.count、または 1 を超える古いキー max_annotations_per_item と min_annotators_per_instancePotato は、オーバーラップのアイテムが複数のコーダーに届くことを保証できません。
attention_checks.enabled または gold_standards.enabledコーダーがチェックのアイテムを見つけてスキップできてしまいます。
icl_labeling.enabledモデル用のブラインド検証アイテムが、見つけられるようになってしまいます。
adjudication.enabledPotato が裁定のキューを管理しています。
expert 以外の値に設定された crowdsourcing.provider、または従来の prolific または mturk ブロックやログインタイプ有償のタスクが割り当ての単位であり、取り込みは支払いとカバレッジを壊します。

このガードは、割り当て戦略 fixed_order と priority を許可し、fixed_order は Potato のデフォルトです。assignment_strategy: random と num_annotators_per_item: 2 を持つ設定は、次のメッセージで検証に失敗します。

text
ERRORS:
  - search.annotator_claim: true is incompatible with this configuration:
  - assignment_strategy: random (self-selection breaks sampling/ordering)
  - num_annotators_per_item: 2 (inter-annotator overlap cannot be guaranteed under self-selection)

qda_mode.enabled: true または solo_mode.enabled: true の下では、Potato は上の表のすべてのチェックをスキップします。したがって、コーダー間信頼性のためにオーバーラップのサンプルを割り当てる、QDA モードのチームプロジェクトは、取り込みがオンの状態で起動し、コーダーは、Potato が各コーダーに割り当てたサンプルの外にあるアイテムを取り込めます。チームが信頼性のサンプルをコーディングしている間は annotator_claim をオフにし、コーダーが自分でアイテムを選ぶことが設計に合う場合は、その後でオンにしてください。管理者の検索はキューを変えないため、ガードの対象外です。

QDA モードでコーディングしながら検索する

コーパスである用語を検索し、その用語が現れる各一節をコーディングする研究者は、Potato で次の手順を踏みます。

  1. Find を開き、たとえば transport のように用語を検索します。接頭辞の規則により、「transportation」と「transported」も返されます。
  2. スニペットを読み、スニペットが関連しそうに見える各アイテムを取り込みます。
  3. 取り込んだ各アイテムが自分のキューに現れたときにコーディングします。一節をハイライトしてコードブックのコードを適用するか、i を押して選択範囲からインビボ・コードを作ります。
  4. アイテムまたは選択範囲にメモを付けて、その一節がなぜそのコードに当てはまるのか、または惜しい例がなぜそのコードの外にあるのかを記録します。

検索はアイテムを返し、アイテムごとに一つのスニペットを返します。ある用語に五回言及するアイテムは一度だけ現れ、完全なアイテムはキューからのみ開きます。Potato 2.13.1 には、すべての出現箇所のキーワード・イン・コンテキストのリストも、すべての検索の一致にコードを適用する手順もありません。各コーディングの判断は、その一節を読むコーダーに委ねられます。

制限

  • アイテムのテキストのみ。 コード、メモ、アノテーション、アイテム ID、インデックスされるテキスト以外のフィールドは検索できません。
  • フレーズ、ブール、近接、語幹の検索なし。 すべてのクエリは、すべてが現れなければならない接頭辞の集合です。
  • アイテムごとに一つのスニペット。 スニペットは最大 12 語で、用語が何回現れても、アイテムは一度だけ現れます。
  • 結果リストの上限。 管理者の検索はリクエストあたり最大 500 件、コーダーの検索は最大 200 件、Find パネルは 50 件を返します。
  • スペースなしで書かれる言語。 中国語や日本語のテキストは、句読点の間の文字の連なりとしてインデックスされ、クエリは連なりの先頭でのみ一致します。
  • テキストのないメディア。 画像、音声、動画のアイテムは、text_key が指定する、またはフォールバックのフィールドの中で見つかる、キャプションまたは記録のフィールドを通じてのみインデックスされます。

上流のサンプルプロジェクト

Potato のチェックアウトから、上流の検索の例を起動し、例のキーを使って管理者のエンドポイントにクエリを実行します。

bash
python potato/flask_server.py start examples/advanced/search-example/config.yaml -p 8000
curl -H "X-API-Key: search-example-key" \
  "http://localhost:8000/admin/api/search?q=rare"

この例は、六つの短い状況報告を読み込み、そのうち三つが「rare」に言及しています。この例は、fixed_order の割り当てと max_annotations_per_user: 2 の下で、検索と取り込みをオンにします。インタビューの抜粋のプロジェクトで Find パネルを見るには、代わりに examples/advanced/qda-mode-example/config.yaml の QDA モードの例を起動してください。

関連資料

実装の詳細については、ソースドキュメントを参照してください。