Solr の Kuromoji を extended で使うとインデックスサイズが予想以上に小さくなる問題について

前回得られた、Kuromoji の mode を extended にした場合にインデックスサイズが最も小さくなるという不思議な結果を調査しました。

mode=search と mode=extended の違いは未知語の扱いです。 なので、未知語を含むクエリがどのように扱われるのかを確認しました。

【mode=search の場合】

"rawquerystring":"title:西沙諸島 AND text:パラセル諸島"
"parsedquery":"+title:西沙諸島 +(text:パラセル text:諸島)"

【mode=extended の場合】

"rawquerystring":"title:西沙諸島 AND text:パラセル諸島"
"parsedquery":"+title:西沙諸島 +text:諸島"

未知語が1-gramに分割されてインデックスサイズが多少大きくなることを予想していたのに、実際は逆に未知語が落とされてしまっています。

そこで、mode=search と mode=extended とで「パラセル諸島」を形態素解析した結果を比べてみました。

mode=search で「パラセル諸島」を形態素解析した結果
mode=extendedで「パラセル諸島」を形態素解析した結果

mode=search では「パラセル」が名詞-一般となっており、mode=extended では「パラセル」が1文字ずつに分解されてそれぞれが記号-一般となっています。分解のされ方はどちらも期待通りです。形態素解析に問題が無さそうなので、怪しいのは形態素解析後のフィルタということになります。おそらくストップワードに引っ掛かっているのでしょう。

設定ファイルの lang/stoptags_ja.txt を確認すると、記号-一般がストップワードとして定義されていました。

#  symbol-misc: A general symbol not in one of the categories below.
# e.g. [○◎@$〒→+]
記号-一般

そこで、この行をコメントアウトした configset (それ以外は全く同じ)を作り、wikipedia-ja のインデックスを作成しました。

4.2G    example/cloud/node1/solr/wikipedia-ja-extended2_shard1_replica_n1
2.1G example/cloud/node1/solr/wikipedia-ja-extended_shard1_replica_n1
3.1G example/cloud/node1/solr/wikipedia-ja-normal_shard1_replica_n1
3.1G example/cloud/node1/solr/wikipedia-ja-search_shard1_replica_n1

予想通り、4.2GBとmode=searchよりもインデックスサイズが大きくなりました。形態素解析の結果は以下の通りです。

"rawquerystring":"title:西沙諸島 AND text:パラセル諸島"
"parsedquery":"+title:西沙諸島 +(text:パ text:ラ text:セ text:ル text:諸島)"

インデックスサイズが大きくなったのは、単に未知語が1-gramに分割されただけではなく、他の記号類もストップワードから外れてインデックスに入ってしまったからだと思います。 1-gram に分割したときの品詞を変更できるようになっていればいいのですが、ざっと調べた感じではそうはなっていないようです。 その弊害を考えると、mode=extended はちょっと使い勝手が悪いと言えるかもしれません。

カスタム投稿タイプをWordPressに追加する方法(プラグイン不要!)

WordPressでお知らせや商品一覧などデフォルトで用意されている投稿とは別に、独立したコンテンツを投稿したい場合ってありますよね。
そんなときは、カスタム投稿タイプを使って投稿ページを増やしましょう!

①管理画面にカスタム投稿の追加

「functions.php」に下記のコードを追加します。

add_action( 'init', 'add_post_type' );
function add_post_type() {

  // 「ニュース」のカスタム投稿タイプ
  register_post_type(
    'news', /* 投稿タイプ名 */
    array(
      'labels' => array( // 投稿タイプの名前を定義
        'name'          => 'ニュース', // 管理画面などの表示名
        'singular_name' => 'ニュース', // 管理画面などの表示名(単数形)
        'add_new_item'  => '新規追加', // 新規追加画面の表示名
        'edit_item'     => '編集', // 編集画面の表示名
      ),
      'public'          => true, // trueで管理画面等に表示
      'hierarchical'    => true, // trueで階層型
      'has_archive'     => true, // trueでアーカイブページ(一覧表示)を持つ
      'supports' => array( // カスタム投稿ページに表示される項目
        'title', // タイトル
        'editor', // 本文のエディタ
        'author', // 作成者
        'thumbnail', // アイキャッチ画像
        'excerpt', // 抜粋
        'trackbacks', // トラックバック送信
        'custom-fields', // カスタムフィールド
        'revisions', // リビジョン
        'comments', // ディスカッション
        'page-attributes', // 属性(親・順序)
      ),
      'menu_position'   => 5, // 左メニュー「投稿」の下に表示
      'rewrite' => array('with_front' => false), // パーマリンクの編集(newsの前の階層URLを消して表示)
    )
  );
}

「functions.php」にコードを追加すると左メニューに「ニュース」が追加されます。

※ 不要なフォームがある場合は、「supports」の中の不要な値を削除してください。
※ 表示位置をもっと下にしたい場合は、menu_positionの値を増やしてください。
(例えばメディアの下に持っていきたい場合はmenu_positionの値を10にします。)

②カスタム投稿タイプの表示方法テンプレートの用意

次に記事表示用のテンプレート「single-news.php」を作成します。
ファイル名single-news.phpの「news」の部分は、function.phpに追記した「投稿タイプ名」と同じにします。
(single-news.phpがない場合はsingle.phpを使って表示されます。)

③パーマリンクの保存

「設定>パーマリンク設定」で内容を変更せずに、「保存」ボタンをクリックします。
(パーマリンク設定で保存をしないとエラーページが表示されます。)

「ニュース」で投稿した記事のURLにアクセスすると投稿した内容が表示されていると思います。

やってみると意外と簡単にカスタム投稿タイプが追加出来たのではないでしょうか?
こういう所から少しずつWordPressと親しくなれたらと思います。

 

アプリを探すならApplivがめっちゃ便利

こんにちわ。
リエです。

先日Applivというサイトで弊社サービスの【HASH】を掲載いただきました。+゚(*´∀`*)。+゚
https://app-liv.jp/1368925370
※ Applivさんありがとうございます!

Applivは欲しい・役立つiOSアプリ(iPhone・iPad)をレビューやおすすめランキングから見つけることができるサービスです。


「ゲームアプリを探しているけど、どんなアプリをダウンロードしていいかわからないなぁ・・・」と思ったらカテゴリのゲームをチェックすれば、すぐにアプリを探すことができます。
カテゴリはランキング形式になっていて、表示も[すべて][無料][新作]と変更でき、さらには[すべて]を選択すると、おすすめ順と利用者が多い順に並び替えできるのです!便利〜(・∀・)

掲載されているアプリはアプリ詳細ページからレビューすることもできるので、他の人のレビューを参考にすることもできます。
実際アプリを使っている人のレビューって、参考になりますよね。
わたしはレビューはめっちゃ読んで参考にするタイプです。(だって気になりません??)
なので他の人の参考になればいいなとレビュー投稿は結構するのですが、アカウント登録があるとめんどうでやっぱやめようと思うことも度々・・・。
でもApplivはアカウント登録しなくてもレビュー投稿ができちゃいます。
個人的にはそれって気軽にレビューできるのでハードルが低くていいなぁと思いました。

これからもアプリを探したい時はApplivを活用しようと思います。

この春新社会人になるあなたへ

こんにちわ。
リエです。

もうすぐ新生活が始まる時期ですね。
この春ご卒業された方おめでとうございます。

新社会人になるあなたへこのブログを捧げます。

よく就職活動中の学生さんに「就職までに何をやればいいですか?」と聞かれます。
ということで、参考になるかわからないわたしの新卒時代の話しを織り交ぜながら話していこうかと思います。

わたしは専門学校卒なので大学生とは就職活動はかなり異なると思います。
学校を卒業する年の2月に国試があったのですが、昨年の夏から秋にかけて行われる模試で合格点が取れないと就職活動ができないという境遇でした。できの悪いわたしは1回も合格点が取れず(ちーん)就職活動はできないまま冬を迎えました。

優秀な子でも就職活動をできるのは10月から翌年1月まで。
大学生とはここがかなり異なりますね。
専門職なので、短い期間での就職活動が可能だったのだと思います。
業種も決まっていましたしね。

そして2月に試験、3月に卒業し晴れて4月に新社会人になりました。
社会人になるまでの約2週間は何をやったかというと、お友達と遊んだり、実技から少し離れて不安だったので家で練習などをしていました。
でも、時間に余裕があるうちにやっておけばよかったなと思うことはたくさんあります。

なので、冒頭の学生さんからの質問にはこう答えています。
「今の時間を満喫して!!」

資格の勉強とかその職種の研究とか、自分が進んでやりたいと思ったらやればいいと思います。それももちろん大事。自ら進んで学んだ知識は財産ですから。
あと下記のことは激しくおすすめします。
・入社1週間前からは生活リズムを整えておく
→これは結構大事。生活リズムって2〜3日では中々整いません。
・体力をつけておく
→業種によりますが、まじでシステム系は運動不足になります。
運動をする週間をつけておいた方が、健康的にすごくいいです。

今の時間は本当にかけがえのないものだと思うので、悔いなく過ごしてくださいね。社会人生活の方が圧倒的に長いのですから/(^o^)\ガクブル

でも社会人楽しいので、怖がらず飛び込んできてね!




Solrで日本語版Wikipediaのインデックスを作った場合のサイズをTokenizerの設定毎に調べる

はじめに

Solrで日本語の文書を扱う場合に考えなくてはならないことの一つに、Tokenizerをどれにするか、があります。ざっくり言うと、n-gram(だいたいは2-gram)にするか、形態素解析にするか、です。
それぞれの長所、短所はこんな感じです。

n-gram

長所

  • 検索漏れが少ない
  • 未知語に強い

短所

  • nより短いキーワードを扱えない
  • インデックスサイズが大きくなる
  • 検索結果のノイズが多い

形態素解析

長所

  • 検索結果のノイズが少ない
  • インデックスサイズを小さくする余地が大きい

短所

  • 未知語に弱い
  • 入力キーワードに対する完全一致検索が難しい

双方の長所・短所に出てきたインデックスサイズがどれくらいの差になるのかを日本語版Wikipediaを対象に調べてみました。

SolrにWikipediaを投入する

Wikipediaのダンプデータをダウンロード

https://dumps.wikimedia.org/jawiki/
の latest から jawiki-latest-pages-articles.xml.bz2 をダウンロードして展開しておきます。

configset準備

_default をベースに設定ファイルを用意します。

cp -r server/solr/configsets/_default server/solr/configsets/wikipedia 

wikipedia/conf/solrconfig.xml に以下を追加

<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-dataimporthandler-.*\.jar" />

<requestHandler name="/dataimport" class="solr.DataImportHandler">
  <lst name="defaults">
    <str name="config">solr-data-config.xml</str>
  </lst>
</requestHandler>

Wikppediaインポート用の DataImportHander の設定 solr-data-config.xml を
https://wiki.apache.org/solr/DataImportHandler#Example:_Indexing_wikipedia
を参考にして作成

<dataConfig>
  <dataSource type="FileDataSource" encoding="UTF-8" />
  <document>
    <entity name="page"
                processor="XPathEntityProcessor"
                stream="true"
                forEach="/mediawiki/page/"
                url="data/jawiki-latest-pages-articles.xml"
                transformer="RegexTransformer,DateFormatTransformer">
      <field column="id"        xpath="/mediawiki/page/id" />
      <field column="title"     xpath="/mediawiki/page/title" />
      <field column="revision"  xpath="/mediawiki/page/revision/id" />
      <field column="user"      xpath="/mediawiki/page/revision/contributor/username" />
      <field column="userId"    xpath="/mediawiki/page/revision/contributor/id" />
      <field column="text"      xpath="/mediawiki/page/revision/text" />
      <field column="timestamp" xpath="/mediawiki/page/revision/timestamp" dateTimeFormat="yyyy-MM-dd'T'hh:mm:ss'Z'" />
      <field column="$skipDoc"  regex="^#REDIRECT .*" replaceWith="true" sourceColName="text"/>
    </entity>
  </document>
</dataConfig>

configsetをアップロード

(cd server/solr/configsets/wikipedia/conf && zip -r - *) |curl -X POST --header "Content-Type:application/octet-stream" --data-binary @- "http://localhost:8983/solr/admin/configs?action=UPLOAD&name=wikipedia"

コレクション”wikipedia”を作成

curl 'http://localhost:8983/solr/admin/collections?action=CREATE&name=wikipedia&numShards=1&replicationFactor=1&collection.configName=wikipedia&wt=xml'

インポート開始

管理画面からインポート開始

各Tokenizerの設定

以下の4種類の設定で試してみます。
今回は手っ取り早く上記の手順の「configsetの準備」のところで managed-schema ファイルを編集しています。

CJK bigram

managed-schema の変更箇所

(略)
<pre>
    <fieldType name="text_cjk" class="solr.TextField" positionIncrementGap="100">
      <analyzer>
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <!-- normalize width before bigram, as e.g. half-width dakuten combine  -->
        <filter class="solr.CJKWidthFilterFactory"/>
        <!-- for any non-CJK -->
        <filter class="solr.LowerCaseFilterFactory"/>
        <filter class="solr.CJKBigramFilterFactory"/>
      </analyzer>
    </fieldType>
</pre>
(略)
<field name="title"     type="string"  indexed="true" stored="false"/>
<field name="revision"  type="pint"    indexed="true" stored="true"/>
<field name="user"      type="string"  indexed="true" stored="true"/>
<field name="userId"    type="pint"     indexed="true" stored="true"/>
<field name="text"      type="text_cjk"    indexed="true" stored="false"/>
<field name="timestamp" type="pdate"    indexed="true" stored="true"/>
(略)

Kuromoji (mode=normal)

辞書通りの分割
(例) 株式会社→「株式会社」

managed-schema の変更箇所

(略)
<pre>
    <fieldType name="text_ja" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="false">
      <analyzer>
        <tokenizer class="solr.JapaneseTokenizerFactory" mode="normal"/>
        <filter class="solr.JapaneseBaseFormFilterFactory"/>
        <filter class="solr.JapanesePartOfSpeechStopFilterFactory" tags="lang/stoptags_ja.txt" />
        <filter class="solr.CJKWidthFilterFactory"/>
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_ja.txt" />
        <filter class="solr.JapaneseKatakanaStemFilterFactory" minimumLength="4"/>
        <filter class="solr.LowerCaseFilterFactory"/>
      </analyzer>
    </fieldType>
</pre>
(略)
<field name="title"     type="string"  indexed="true" stored="false"/>
<field name="revision"  type="pint"    indexed="true" stored="true"/>
<field name="user"      type="string"  indexed="true" stored="true"/>
<field name="userId"    type="pint"     indexed="true" stored="true"/>
<field name="text"      type="text_ja"    indexed="true" stored="false"/>
<field name="timestamp" type="pdate"    indexed="true" stored="true"/>
(略)

Kuromoji (mode=search)

複合語を細かく分割
株式会社→「株式」「会社」

managed-schema の変更箇所

        <tokenizer class="solr.JapaneseTokenizerFactory" mode="search"/>

それ以外は mode=normal と同じ。

Kuromoji (mode=extended)

mode=search + 未知語を 1-gram に分割

managed-schema の変更箇所

        <tokenizer class="solr.JapaneseTokenizerFactory" mode="extended"/>

それ以外は mode=normal と同じ。

結果

インデックスサイズ生成時間
CJK5.9GB35分
Kuromoji(normal)3.1GB76分
Kuromoji(search)3.1GB83分
Kuromoji(extended)2.1GB79分

ちなみに、日本語版Wikipedia全記事のテキスト部分のサイズをカウントしてみたところ、約1.4GBでした。

まとめ

Solrで日本語版Wikipedia全記事のインデックスを作成しました。2-gramのインデックスサイズは形態素解析インデックスの約2倍になりました。

Kuromoji(extended)は未知語を1-gramに分割する分他のモードよりもインデックスサイズが大きくなると予想していたのですが、逆に30%強も小さくなりました。ここはもうちょっと調べてみる必要がありそうです。