Solr って何者?③:コアを作ってみる

こんにちは。サイオステクノロジー OSS サポート担当 山本 です。

今回も solr のお話です。
今回は前回まで使っていた demo をベースにして、フィールドの内容を変更した新しいコアを作ってみることで、コアを作る手順を確認しようかと思います。

■おさらい:コア?フィールド?

コアを作っていく前に、solr の基本的な部分の用語を再確認しておきましょう。
今回見る必要な範囲でいうと、大まかに以下のような感じです。

コア箱 (空間) のようなもの。一連の設定の適用範囲であり、また検索の際にはコアを指定して検索します。
ドキュメント:ユーザが登録したデータ。そのコアスキーマで定義されたフィールドに合わせた、一連のデータの組を1つの単位として登録されます。
フィールドドキュメントの構造を決定する要素。型 (数値か文字列か) や、必須であるかどうか、解析を行うかどうか (また、その解析方法) などをフィールド毎に決定します。スキーマで設定します。
スキーマフィールドの名前や型や解析方法、フィールドで使用される型などの定義を行うための設定ファイル。

…これだけ言われてもピンと来ないかもしれませんので、この先やってみながら確認していきましょう。

■コアを作る

ということで新しいコアを作ってみます。
一つの solr で複数のコアを作ることができるので、今回は前回までにも使用していたデモ用の環境にコアを追加してみます。

…と軽く言ってはみますが、solr のコアを作るには準備が必要です。コマンド一つでお手軽簡単!!とはいきません。
用意するファイルの数もそこそこあるので、今回はフィールドの内容を決定するスキーマファイルのみ作成し、他の必要なファイルはデモ用環境のコア “demo” のものを流用してコアを作っていきます。

■デモ環境 (コンテナ) の起動

まずはベースとなる solr 環境として、公式コンテナイメージからデモ用の環境を作ります。
これは前回まででやったのと同じです。podman を導入して以下のコマンドを実行すれば OK ですね。

## 前回の環境を消してしまっている場合
$ podman run -dt --name test-solr -p 8984:8983 solr solr-demo
## 前回の環境から続けて試す場合
$ podman start test-solr

ブラウザを開いて以下の URL にアクセスし、管理画面が開けることを確認できたら一旦 OK です。

http://(IPアドレス or ホスト名):8984/solr

■スキーマファイルの作成

続いて、今回のお話のキーであるスキーマを作成します。
スキーマは、“managed-schema.xml” (または “schema.xml”) という名前の xml ファイルで定義していきます。

今回は日本語を扱う 2つのフィールド “test_1” “test_2” と、managed-schema.xml で最低限必要になるフィールドだけを持ったスキーマファイルを作ってみます。

適当なテキストエディタ (vi など) を使って、以下のような内容を持つ “managed-schema.xml” を作成してください。

<?xml version="1.0" encoding="UTF-8"?>
<schema name="default-config" version="1.6">
  <types>
    <fieldType name="booleans" class="solr.BoolField" sortMissingLast="true" multiValued="true"/>
    <fieldType name="pdates" class="solr.DatePointField" docValues="true" multiValued="true"/>
    <fieldType name="plongs" class="solr.LongPointField" docValues="true" multiValued="true"/>
    <fieldType name="pdoubles" class="solr.DoublePointField" docValues="true" multiValued="true"/>
    <fieldType name="pint" class="solr.IntPointField" docValues="true"/>
    <fieldType name="plong" class="solr.LongPointField" docValues="true"/>
    <fieldType name="string" class="solr.StrField" sortMissingLast="true" docValues="true"/>
    <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100" multiValued="true">
      <analyzer type="index">
        <tokenizer name="standard"/>
        <filter ignoreCase="true" words="stopwords.txt" name="stop"/>
        <filter name="lowercase"/>
      </analyzer>
      <analyzer type="query">
        <tokenizer name="standard"/>
        <filter ignoreCase="true" words="stopwords.txt" name="stop"/>
        <filter ignoreCase="true" synonyms="synonyms.txt" name="synonymGraph" expand="true"/>
        <filter name="lowercase"/>
      </analyzer>
    </fieldType>

   <!-- ここまで必須分 -->
   <!-- ここから独自フィールド用の設定 -->

    <fieldType name="text_ja" class="solr.TextField" autoGeneratePhraseQueries="false" positionIncrementGap="100">
      <analyzer>
        <tokenizer mode="search" name="japanese"/>
        <filter name="japaneseBaseForm"/>
        <filter tags="lang/stoptags_ja.txt" name="japanesePartOfSpeechStop"/>
        <filter name="cjkWidth"/>
        <filter ignoreCase="true" words="lang/stopwords_ja.txt" name="stop"/>
        <filter name="japaneseKatakanaStem" minimumLength="4"/>
        <filter name="lowercase"/>
      </analyzer>
    </fieldType>
  </types>

  <fields>
    <field name="_version_" type="plong" indexed="false" stored="false"/>
    <field name="id" type="string" multiValued="false" required="true" stored="true"/>

   <!-- ここまで必須分 -->
   <!-- ここから独自フィールド用の設定 -->

    <field name="test_1" type="text_ja"/>
    <field name="test_2" type="text_ja"/>
  </fields>

  <uniqueKey>id</uniqueKey>
</schema>

これでスキーマファイルの準備は OK です。

■スキーマファイルの中身の基本的な見方

折角なので、今回のスキーマファイルの設定内容についても一部確認してみましょう。

まずざっくり見ると、“<field>”“<fieldType>” という要素を大量に定義してるなー、というのがわかるかと思います。 “<field>” 要素の方から確認してみましょう。

  <fields>
    <field name="_version_" type="plong" indexed="false" stored="false"/>
    <field name="id" type="string" multiValued="false" required="true" stored="true"/>

   <!-- ここまで必須分 -->
   <!-- ここから独自フィールド用の設定 -->

    <field name="test_1" type="text_ja"/>
    <field name="test_2" type="text_ja"/>
  </fields>

よくよく見てみると、name 属性に今回作ると宣言していたフィールド名 “test_1” “test_2” を含むものがありますね。
お察しのとおり、“<field>” 要素こそがこのスキーマの、つまりはこのスキーマを使うコアで扱えるフィールドを定義するための要素になります。

例えば、この行は “_version_” という名前のフィールドを定義しています。

    <field name="_version_" type="plong" indexed="false" stored="false"/>

ところで、<field> 要素の設定には name 属性の他に type 属性が必ず含まれているのに気づくかと思います。
この “_version_” フィールドでは type は “plong” ですね。
ここで “<fieldType>” 要素に目を向けてみましょう。

    <fieldType name="plong" class="solr.LongPointField" docValues="true"/>

探してみると、<fieldType> の中にはこのように name 属性が先の “plong” と同じ名前になっているものが存在しているはずです。
これは勿論偶然などではなく、”_version_” フィールドで使用される “plong” type がどんなものなのかを定義するものになります。
実際にどんなものなのかはこの <fieldType> 要素の各属性を確認する必要がありますが、特に重要なのは class 属性です。
基本的に使用される class 属性の値については、こちらのドキュメントを確認してください。例えば、ここで使用されている “solr.LongPointField” なら Long 値 (64bit 符号なし整数) ということになります。

もう一つ見てみましょう。”test_1″ “test_2” フィールドの設定部分です。

    <field name="test_1" type="text_ja"/>
    <field name="test_2" type="text_ja"/>

これらのフィールドで使用している type “text_ja” の定義を確認してみます。

    <fieldType name="text_ja" class="solr.TextField" autoGeneratePhraseQueries="false" positionIncrementGap="100">
      <analyzer>
        <tokenizer mode="search" name="japanese"/>
        <filter name="japaneseBaseForm"/>
        <filter tags="lang/stoptags_ja.txt" name="japanesePartOfSpeechStop"/>
        <filter name="cjkWidth"/>
        <filter ignoreCase="true" words="lang/stopwords_ja.txt" name="stop"/>
        <filter name="japaneseKatakanaStem" minimumLength="4"/>
        <filter name="lowercase"/>
      </analyzer>
    </fieldType>

ちょっと長いですが、これ全部で fieldType “text_ja” の定義になります。
これは前回に長々とお話しした、solr の文字列解析を行うための設定をしたものになります。
class 属性に “solr.TextField”、子要素に <analyzer> を設定することで、この fieldType が解析処理を行う対象であることを定義できます。
解析時の処理内容としては、<analyzer> の子要素として処理の内容を上から順番に書いていきます。
上記の例の場合だと、tokenizer の後に “japaneseBaseForm”、”japanesePartOfSpeechStop”、……という順番でフィルタ処理を行う形になります。

<analyzer> の中身についての詳細は、こちらのドキュメントを確認してください。

なお、今回作ったスキーマファイルは非常にコンパクトな内容です。
色々と設定されている例が見たい場合は、デモ環境のデフォルトコア demo のスキーマファイルを覗いてみるといいかもしれません。

■必要になるディレクトリ作成とファイル配置

ではコア作成の準備の仕上げとして、ディレクトリを作成してファイルを配置していきます。

とりあえず今回はデモ環境のコンテナ内に入って操作していきます。

$ podman exec -it test-solr /bin/bash

まず、環境変数 “SOLR_HOME” で設定されている solr のホームディレクトリ (デモ環境では “/var/solr/data/” になっているはずです) に、新しいコア用のディレクトリを作成します。
ここで作成するディレクトリ名がそのまま新しいコアのコア名になります。今回は “test-new-core” というコア名にしてみます。

 (※コンテナ内での操作)

$ mkdir /var/solr/data/test-new-core

続いて、必要になるファイルをこのディレクトリに配置していきます。
先述のとおり、今回は managed-schema.xml 以外はデモ環境 “demo” から流用するので、流用するファイルをコピーしていきます。
(実際に運用する環境を構築する際には、これらのファイルもコピーではなくちゃんと確認して設定しましょう。特に solrconfig.xmlsolr.xml など)

 (※コンテナ内での操作)

$ mkdir /var/solr/data/test-new-core/data
$ mkdir /var/solr/data/test-new-core/conf
$ mkdir /var/solr/data/test-new-core/conf/lang
$ cp /var/solr/data/demo/core.properties /var/solr/data/test-new-core/
$ cp /var/solr/data/demo/conf/solrconfig.xml /var/solr/data/test-new-core/conf/
$ cp /var/solr/data/demo/conf/stopwords.txt /var/solr/data/test-new-core/conf/
$ cp /var/solr/data/demo/conf/synonyms.txt /var/solr/data/test-new-core/conf/
$ cp /var/solr/data/demo/conf/lang/stoptags_ja.txt /var/solr/data/test-new-core/conf/lang/
$ cp /var/solr/data/demo/conf/lang/stopwords_ja.txt /var/solr/data/test-new-core/conf/lang/

 (※ コンテナ内の操作終わり)
$ exit

最後に、作成した managed-schema.xml を配置すればファイルの配置は完了です。

$ podman cp ./managed-schema.xml test-solr:/var/solr/data/test-new-core/conf/managed-schema.xml

■コア作成の実行

必要な各種ファイルの配置ができたら、コア作成を実行します。
コマンドからでも Web の管理画面からでもコアは作成できますが、今回は Web の管理画面で追加する方法を見ていきます。

まずは適当なブラウザから管理画面にアクセスします。今回のコンテナの実行方法なら以下のアドレスですね。

http://(IPアドレス or ホスト名):8984/solr

管理画面にアクセスできたら、画面左メニューから “Core-Admin” を開きます。

“Add Core” から、”name” と “instanceDir” に先の手順で作成したコア用のディレクトリと同じ名前に変更して “Add Core” ボタンで…

新しいコアが登録できました。
画面左メニューの “Core Selector” プルダウンにも、新しいコアが出てくるようになっているはずです。

■ドキュメントの登録と検索

新しくコアを作れたので、このコアを使って基本的なドキュメントの登録や検索の方法も確認しましょう。

■ドキュメントの登録

ドキュメントの登録は、Web 管理画面または curl などを用いた直接のリクエストにより、xmlJSON などの形式のファイルまたは文字列の直接入力によって行うことができます。

今回は管理画面から xml ファイルを使って登録する方法を確認していきます。

まずは以下のような xml ファイルを作りましょう。(“<field>” の中身はお好みの内容で OK です。)

<add>
  <doc>
    <field name="test_1">サイオステクノロジー株式会社</field>
    <field name="test_2">SIOS Tech.Lab</field>
  </doc>
  <doc>
    <field name="test_1">OSSのsolrを試しています</field>
    <field name="test_2">ドキュメントの登録</field>
  </doc>
  <doc>
    <field name="test_1">これらの "doc" 内の "field" 要素は</field>
    <field name="test_2">スキーマで定義したフィールドに合わせて作りましょう</field>
  </doc>
  <doc>
    <field name="test_1">サンプルドキュメント</field>
    <field name="test_2">サンプルのドキュメント</field>
  </doc>
  <doc>
    <field name="test_1">OSSよろず相談室</field>
    <field name="test_2">some document</field>
  </doc>
</add>

続いて、管理画面を開いて画面左メニューの “Core Selector” プルダウンから先ほど作ったコア名を選択し、”Documents” を開きます。

Document Type” で “File Upload” を選択したら、”Document(s)” で先に作った xml ファイルを選択して “Submit Document” を押下すれば OK です。

■ドキュメントの検索

続いて登録したドキュメントを検索してみましょう。
前々回もやった内容なので、ざっくりいきます。

まずは管理画面から登録に成功しているか確認してみます。

画面左メニュー “Core Selector” で先ほどのコア名を選択した状態で “Query” 画面を開き、画面下の “Execute Query” ボタンを押下します。 すると、登録したドキュメントが表示されるはずです。

この画面の “q” に、例えば “test_2:ドキュメント” や “test_2:ドキュメント AND test_1:OSS” などのように “(フィールド名):(検索文字列)” という形式で条件を指定することで、検索条件を指定してドキュメントを表示させることもできます。

また、以下のような形式でアドレスに直接リクエストを行うことで、ドキュメントを取得することもできます。

http://(IPアドレス or ホスト名):(ポート)/solr/(コア名)/select?q=(条件)

例えば、curl を使って今回作った環境のドキュメントを取得すると以下のようになります。
記号や全角文字は URL エンコードする必要があります

$ curl 'http://(IP アドレス or ホスト名):8984/solr/test-new-core/select?q=test_1%3AOSS%20AND%20test_2%3Asome'
{
  "responseHeader":{
    "status":0,
    "QTime":2,
    "params":{
      "q":"test_1:OSS AND test_2:some"
    }
  },
  "response":{
    "numFound":1,
    "start":0,
    "numFoundExact":true,
    "docs":[{
      "id":"0fa6bbf2-b548-4933-b2de-107eebaea887",
      "test_1":"OSSよろず相談室",
      "test_2":"some document",
      "_version_":1814150309105106944
    }]
  }
}

■最後に

今回は solr に新しいコアを追加する手順を確認してみました。

今回はスキーマファイルのみ自作し、他の必要ファイルはデモ環境から流用するという実験用の手順大幅削減アプローチでやってみましたが、それでも確認すべきことは結構ありましたね。
勿論、今回流用した部分や見なかった部分にも確認すべき内容は多数あり、気軽に使うにはやや敷居が高いと感じるところはあります。

ただ、solr には活用することでより検索の利便性を向上させる機能がまだまだありますので、次回はそのうちの一つを紹介してみたいと思います。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です