カテゴリー
Uncategorized

MySQL全文検索について調べたこと

業務案件で全文検索を使うことになった。とはいえ全文検索について全く知識がなかったのでここでインプットしておこうということで、いろいろ調べてみた。

全文検索とは

コンピュータにおいて、複数の文書から特定の文字列を検索すること。複数文書にまたがって文書に含まれる全文を対象とした検索。

  • grep型(逐次走査検索)

    事前に索引を作成せず、複数のファイルを順次走査していく。検索対象の増加によって検索速度が低下する。
  • 索引型(インデックス)

    事前に検索対象となる文書を走査し、索引データを準備しておく。これをインデクシングとよび、これにより生成されるファイルをインデックス(インデクス)と呼ぶ。

索引文字列の抽出手法

インデックスを作成するために検索対象の文書を解析・分割を行う。その手法として主に下記2手法がある。

  • 形態素解析

    英文は単語の間にスペースが入るため、これで区切れば索引データの作成は容易である。しかし日本語の場合それができないため形態素解析技術を用いて、文書の解析、単語分解を行い、それをもとにインデックスを作成する。形態素解析を行うためには解析用の辞書が必要であり、辞書に品質を受けやすく、検索漏れが生じる場合がある。
  • N-Gram

    「N-文字インデックス」「N-グラム法」なとどもいう。単語単位ではなく文字単位で分解し、後続のN-1文字を含めた状態で出現頻度を求める方法。N=1は「ユニグラム(uni-gram)」N=2は「バイグラム(bi-gram)」N=3は「トライグラム(tri-gram)」と呼ばれる。検索漏れが生じず、辞書の必要がない。しかし形態素解析と比べるとノイズの発生とインデックスサイズの肥大化という2つの欠点がある。
全文検索技術
↓
全文/文検/検索/索技/技術/術

MySQLにおける全文検索

MySQLでは、バージョン5.6.4 より全文検索をサポートしている。しかし、これは空白で単語が区切られるラテン語ベースの言語に対してのみ有効である。

これに対し、バージョン5.7.6 よりCJK(日韓中文字)で使用できるn-gramパーサ がサポートされました。(組み込みのサーバープラグイン。サーバーの起動時に自動的にロードされる。)

同タイミングで MeCab全文パーサプラグイン も提供されていて、形態素解析によるインデクシングも可能。(RDSだと使えないらしい?要調査)

MySQLサーバー設定

プロパティ説明備考
innodb_ft_min_token_size単語の最小長0~16 デフォルト3
innodb_ft_max_token_size単語の最大長10~84 デフォルト10
ft_min_word_lenmyIsamの場合はこれ(後で調べよう)
ft_max_word_lenmyIsamの場合はこれ(後で調べよう)
ngram_token_sizen-gramパーサを使用する際の分割文字数デフォルト2
innodb_ft_sort_pll_degreeインデックスを作成するスレッド数1~32 デフォルト2大きなテーブルにFULLTEXTインデックスを作成するときは、スレッドの数を増やすことを検討
innodb_ft_cache_size補助インデックステーブルごとのキャッシュ容量デフォルト 8000000bytes

InnnoDB全文検索の要素

InnoDB Full-Text Index Tables

InnoDB FULLTEXTインデックスを作成すると、FTS_から始まるインデックステーブルのセットが作成される。これらを転置インデックスという。

InnoDB Full-Text Index Cache

ドキュメントがインサートされると、FULLTEXT INDEXにもインサートが実行される。小さなドキュメントの場合でもインサートアクセスが実行されることになり、補助インデックステーブルへのアクセスが競合する場合があります。これを回避するために、最近インサートされた行の挿入はキャッシュされる。キャッシュ領域がいっぱいになると、ディスクに書き込まれまれる。これにより競合を防いでいる。Innodb_ft_cache_sizeはこのキャッシュ容量を設定できる。

InnoDB Full-Text Index Deletion Handling

FULLTEXT INDEX列をもつレコードを削除すると、補助インデックステーブルへの同時アクセスで競合が発生する場合があります。これを防ぐために削除されたドキュメントIDをFTS_*_DELETEDテーブルに記録する。クエリ結果を返す前に、FTS_*_DELETEDテーブルの情報を使用して削除されたドキュメントIDを除外する。補助インデックステーブルの値は保持されるため容量は減らない。補助インデックステーブルの値を削除するには、OPTIMIZE TABLE句を用いて実行できる。

一部引用元:
https://ja.wikipedia.org/wiki/%E5%85%A8%E6%96%87%E6%A4%9C%E7%B4%A2
https://dev.mysql.com/doc/refman/5.7/en/fulltext-search.html

カテゴリー
Uncategorized

IFTTTでWebサービスのイベントをLINEグループに通知できるようにした

友人と作っているWebプロダクトがあります。このサービスは特定のジャンルの人同士の友達探しをサポートするサービスであり、クローズドなやりとりが多く、サービスが盛り上がっているのかどうか?どれくらいの頻度でユーザ登録があるか?といったデータが把握しにくいという状況でした。1ヶ月前に公開したばかりのサービスでもあり管理画面を実装するほどでもないと思ったので、より簡単な方法を模索しました。友人との連絡はLINEグループを使用しています。そのため今回はLINEグループに通知をする方針としました。

個人開発は、いかに工数をかけずに実装するか?という観点を重要視しています。そこで記憶の片隅にあったIFTTT(イフト)を活用することにしました。

幸いなことに、IFTTTはLINE Notifyというサービスと簡単に連携することができます。LINE Notifyは様々なサービスからの通知を受信して、端末にメッセージ等を送信してくれるサービスです。このサービスの公式アカウントをLINEグループに招待することで、LINEグループへメッセージ通知を流し込むことが可能です。

さて、Webアプリケーションでユーザ通知が行われた場合、どのようにIFTTTに通知するでしょうか。最も簡単な方法は、Webhookでしょう。よって構成は下記の通りになります。

早速始めましょう。IFTTT

IFTTTでレシピを作成します。

IFTTTは「もし何かがあったら」「その時何をする」をセットで設定します。今回は「Webhookを受信したら」「LINE Notifyで通知する」という設定を行います。

If Thisを選択して、Webhookを設定します。

次に、Then Thatをクリックし、LINEを選択します。

初回はLINEアカウント連携に飛ばされると思うので、連携してください。Send messageのRecipientで、送信先のグループ名を選択します。ここで、「1:1でLINE Notifyから通知を受け取る」を選択すれば、自分だけに届くはずです。

Value1,2,3はプレースホルダです。これらの値はWebhookリクエスト毎に自由に設定でき、LINEにはその値で置き換えられたメッセージが送信されます。

これで設定完了です。

次に、WebアプリケーションからIFTTTにWebhookリクエストを投げる必要があります。事前に、エンドポイントのURLを取得しましょう。右上アイコン>My services>Webhooks>右上 Documents を選択しましょう。

WebアプリケーションからWebhookリクエストを送信する部分を実装します。

# LINE通知
# value1 ユーザ名
# value2 登録日時
# value3 URL
begin
  uri = URI.parse(IFTTTから取得したエンドポイント)
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  params = { value1: 値1, value2: 値2, value3: 値3}
  headers = { "Content-Type" => "application/json" }
  response = http.post(uri.path, params.to_json, headers)
  ap response
rescue => e
  Raven.capture_exception(e)
end

最後に、お手持ちのスマホのLINEでLINE Notifyを友達追加したあと、グループに招待しましょう。

喜んでもらえて、エンジニア冥利に尽きますね!

まとめ

IFTTTを使うことで、Webhookを契機にLINE通知を行う仕組みを簡単に実現することができました。

IFTTTはLINEの他、Slackなど様々なサービスと連携することができます。活用方法によっては実装なしに便利な自動化ができるようになることでしょう。

個人的には、IFTTTを使った自動化を体験できたのは知見が広がったという意味でよかったかなと思います。それでは。

カテゴリー
Uncategorized

FlutterのCupertinoTimerPickerを日本語化する

何も考えずにCupertinoTimePickerを追加すると、端末の言語設定に関わらず、英語表記になってしまいます。

Widgetのプロパティでどうにかできると思いきやそのような機能は提供されていませんでした。いろいろ調べた結果、Flutterアプリケーションの多言語化対応が必要でした。

まず、Flutter公式のflutter_localizationsプラグインをインストールします。公式プラグインは、pub.devで提供されるのではなく、Flutter内部に内包されているようです。https://github.com/flutter/flutter/tree/master/packages/flutter_localizations

pubspecにプラグインを追記します。

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter

main.dartでMaterialAppを使用しているので、ここでlocalizationsDelegatesとsupportedLocalesプロパティを追記します。

return MaterialApp(
  localizationsDelegates: [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  supportedLocales: [
    Locale('English'),
    Locale('ja')
  ],
  title: 'xxx',
  home: HomeScreen(title: "xxx"),
  //...
);

最後に、iOSアプリで使用するためにInfo.plistに対応言語を追記します。XCodeでInfo.plistを開きます。

  1. Information Property ListLocalizationsを追加
  2. ValueにJapaneseEnglishを追加

結果、このようになりました!(結構苦労しました…)

カテゴリー
Uncategorized

Homebrewでインストールしたmariadbが起動しないとき mysql.server: line 264: No such process

Homebrewでインストールしたmariadbが起動できなくなってしまいました。

hazm@Hazm ~ $ mysql.server start
Starting MariaDB
.201114 00:25:58 mysqld_safe Logging to '/usr/local/var/mysql/Hazm.err'.
201114 00:25:58 mysqld_safe Starting mariadbd daemon with databases from /usr/local/var/mysql
/usr/local/bin/mysql.server: line 264: kill: (8880) - No such process
 ERROR!

結論

ib_logfile0ib_logfile1というInnoDB構成ファイルを削除することで、起動できるようになりました。

調査

まずログファイルを追いました。

hazm@Hazm ~ $ cat /usr/local/var/mysql/Hazm.err
2020-11-14  0:26:41 0 [Warning] The parameter innodb_file_format is deprecated and has no effect. It may be removed in future releases. See https://mariadb.com/kb/en/library/xtradbinnodb-file-format/
2020-11-14  0:26:41 0 [Warning] InnoDB: innodb_open_files 300 should not be greater than the open_files_limit 256
2020-11-14  0:26:41 0 [Note] InnoDB: Uses event mutexes
2020-11-14  0:26:41 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
2020-11-14  0:26:41 0 [Note] InnoDB: Number of pools: 1
2020-11-14  0:26:41 0 [Note] InnoDB: Using crc32 + pclmulqdq instructions
2020-11-14  0:26:41 0 [Note] InnoDB: Initializing buffer pool, total size = 134217728, chunk size = 134217728
2020-11-14  0:26:41 0 [Note] InnoDB: Completed initialization of buffer pool
2020-11-14  0:26:41 0 [ERROR] InnoDB: Upgrade after a crash is not supported. The redo log was created with MariaDB 10.4.13.
2020-11-14  0:26:41 0 [ERROR] InnoDB: Plugin initialization aborted with error Generic error
2020-11-14  0:26:41 0 [Note] InnoDB: Starting shutdown...
2020-11-14  0:26:41 0 [ERROR] Plugin 'InnoDB' init function returned error.
2020-11-14  0:26:41 0 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
2020-11-14  0:26:41 0 [Note] Plugin 'FEEDBACK' is disabled.
2020-11-14  0:26:41 0 [ERROR] Unknown/unsupported storage engine: InnoDB
2020-11-14  0:26:41 0 [ERROR] Aborting

[ERROR] Unknown/unsupported storage engine: InnoDB が怪しいなと思ったので、検索してみたところ、こちらの記事にあたりました。

https://stackoverflow.com/questions/63421566/homebrew-mariadb-10-4-13-not-found-forced-updated-to-10-5-5-and-now-i-cannot-s

こういうとき、まずはダメ元で試してみます。

hazm@Hazm ~ $ ll /usr/local/var/mysql
total 387568
drwxr-xr-x  30 hazm  admin       960 11 14 00:25 .
drwxrwxr-x  10 hazm  admin       320 11 12 23:47 ..
-rw-rw----   1 hazm  admin    154221 11 14 00:25 Hazm.err
-rw-rw----   1 hazm  admin     16384 11 14 00:25 aria_log.00000001
-rw-rw----   1 hazm  admin        52 11 14 00:25 aria_log_control
-rw-r-----   1 hazm  admin      3929 10 28 20:31 ib_buffer_pool
-rw-rw----   1 hazm  admin  50331648 11  2 19:34 ib_logfile0
-rw-rw----   1 hazm  admin  50331648  6  3 23:52 ib_logfile1
-rw-rw----   1 hazm  admin  79691776 10 28 20:31 ibdata1
-rw-rw----   1 hazm  admin  12582912 11  2 19:34 ibtmp1
-rw-rw----   1 hazm  admin         0  1  5  2019 multi-master.info
drwx------  91 hazm  admin      2912  1  5  2019 mysql
drwx------   3 hazm  admin        96  1  5  2019 performance_schema
hazm@Hazm ~ $ rm /usr/local/var/mysql/ib_logfile0
remove /usr/local/var/mysql/ib_logfile0? y
hazm@Hazm ~ $ rm /usr/local/var/mysql/ib_logfile1
remove /usr/local/var/mysql/ib_logfile1? y
hazm@Hazm ~ $ mysql.server start
Starting MariaDB
.201114 00:29:47 mysqld_safe Logging to '/usr/local/var/mysql/Hazm.err'.
201114 00:29:47 mysqld_safe Starting mariadbd daemon with databases from /usr/local/var/mysql
 SUCCESS!

起動した!

ib_logfile0/1は何者?

InnoDB テーブルスペースおよびログファイルの概要
InnoDB ストレージエンジンで管理されている 2 つの重要なディスクベースのリソースは、そのテーブルスペースデータファイルとログファイルです。InnoDB 構成オプションを指定しない場合は、MySQL によって MySQL データディレクトリ内に、わずかに 12M バイトよりも大きい ibdata1 という名前の自動拡張データファイルと、ib_logfile0 および ib_logfile1 という名前の 2 つのログファイルが作成されます。

https://dev.mysql.com/doc/refman/5.6/ja/innodb-configuration.html

なんのことだかさっぱり。別のページを探ってみると…

Redo ログ
クラッシュリカバリ中に、不完全なトランザクションによって書き込まれるデータを訂正するために使用されるディスクベースデータ構造。通常の操作中に、InnoDB テーブルデータを変更するリクエスト (SQL ステートメント、または NoSQL インタフェースからの低レベル API 呼び出しから発生) をエンコードします。予期しないシャットダウン前にデータファイルの更新を終了していない変更は、自動的に再現されます。

Redo ログはファイルセットとして物理的に表され、通常は ib_logfile0 および ib_logfile1 という名前が付けられます。

https://dev.mysql.com/doc/refman/5.6/ja/glossary.html#glos_redo_log

なるほど、クラッシュした際のリカバリ用のログファイルらしいです。

つまり、mysqlサーバーを正常に終了しなかったことと、その後アップグレードしたことで、リカバリがうまく実行できなかった、といったところでしょうか。

今回は開発環境であったため、えいやでファイルを削除してみたが、本番環境ではやってはいけません。ご注意を。

カテゴリー
Uncategorized

AWS LightSailで低コストHTTPS対応WordPress構築

このブログはAWS LightSailを使用して構築してみたところ、低コストかつ手間なく高速にWordPressブログを立ち上げることができました。今回はこのLightSailについて紹介します。

今どきWordpress?と思う方もいらっしゃるとは思いますが、技術は適材適所だと思います。世の中には多様なニーズが存在し、今WordPressを選択する場合も多々あることでしょう。例えば、ウェブサービスのヘルプページを提供する場合、非エンジニアが加筆編集できるCMSは求められていますし、企業のホームページなどでは未だ多くのニーズがあります。

なぜLightSailを選択したか

今回、ブログの立ち上げに際し、最低限満たしたい要件は以下でした。

  • 低コストで運用できること(1000円/月以下)
  • 独自ドメインを使用できること
  • HTTPS通信ができること

これらの用件を満たすために、当初ConohaVPS等を利用し、証明書を別途契約し、Nginx + php-fpm / MariaDB の構成で運用していくことを考えていましたが、TwitterでLightSailについての呟きを見かけたことをきっかけに調べてみたところ、上記全ての用件を満たせた上で、VPSのようにroot権限が提供されていて自由にサーバーを操作できることと、HTTPSの設定が無料でできることに魅力を感じ、LightSailでの構築を試してみました。

LightSailでやったこと

大まかには下記の通りです。

  1. WordPressイメージでインスタンスを立ち上げる
  2. ドメインを使用してアクセスできるようにする
  3. SSHでログインし、初期設定を行う
  4. Let’sEncryptの自動設定ツールを起動し、HTTPSの設定を行う

上記の操作は、ほぼLightSail画面上と、SSHシェルで実施することができます。Route53やEC2など複数のサービスを横断して操作する必要がないのも魅力の一つです。

構築手順

早速構築を始めましょう。(所要時間30分)

1. WordPressイメージでインスタンスを立ち上げる

LightSail管理画面を開き、インスタンスタブから、「インスタンスの作成」をクリックします。

プラットフォームの選択:Linux
設計図の選択:(アプリ+OS)WordPress 5.4.2
インスタンスプランの選択:$3.5

SSHで接続したい場合は、”SSH キーペアマネージャー”の項目からデフォルトのキーをダウンロードしておきましょう。なお、Web上でコンソールを立ち上げることができるためオプションです。

最後に、インスタンスの作成ボタンをクリックすると、インスタンスが作成されます。

2. ドメインを使用してアクセスできるようにする

独自ドメインでアクセスできるよう設定します。やるべきことは下記の通りです。

  1. 静的IPアドレスの作成(LightSail)
  2. DNZゾーンの作成(LightSail)
  3. ドメインのネームサーバー変更
  4. DNSレコード設定(LightSail)

立ち上げたばかりのインスタンスにはIPアドレスが割り当てられていないため、外部からアクセスができません。まずは静的IPアドレスの作成を行います。

IPアドレスを割り当てるには、LightSail「ネットワーキング」タブの「静的IPの作成」をクリックします。

インスタンスへのアタッチの項目では、先ほど作成したインスタンスを選択します。その後、「作成する」ボタンをクリックします。

次に、DNSゾーンの作成を行います。LightSail「ネットワーキング」タブの「DNSゾーンの作成」をクリックします。登録済みドメインの入力の蘭には、自分で管理している独自ドメイン名を入力します。今回は、hazm.jpを設定しました。

「DNSゾーンの作成」ボタンをタップすると、「ネットワーク」タブの「グローバル」にゾーンが作成されますので、ここをクリックします。

画面下部にネームサーバーが表示されていますので、ドメインのネームサーバー設定でこちらを設定します。

今回、私はお名前.comで契約しているので、そちらの管理画面で設定しました。お名前.com管理画面「ドメイン>ドメイン設定>ネームサーバー設定」で設定を行いました。

次に、DNSレコード設定を行います。ドメインがどのIPアドレスに紐付け(解決)させるかを設定します。推奨の設定は下記の通りです。@ドメイン名そのものを意味します。つまりhttps://hazm.jpをルーティングします。wwwは多用されるサブドメインですが、近年ではサブドメインなしへリダイレクトさせてしまうことが多いと思います。今回立ち上げるWordPressイメージでは、初回起動時にこのリダイレクト設定を行えるので、設定しておくことをお勧めします。

@.hazm.jp -> 先ほど設定した静的IP
www.hazm.jp -> 先ほど設定した静的IP

Let’sEncryptの自動設定ツールを起動し、HTTPSの設定を行う

ここからはサーバーコンソールにログインして設定を行っていきます。LightSail管理画面のアイコンをクリックすることでコンソールが立ち上がります。インスタンスを作成する際にSSHキーをダウンロードしている場合は、そのキーを使用してSSHクライアントからログインすることができます。

ログインすると表示されている文字に注目します。インスタンスイメージはbitnamiが提供しており、便利なツールを用意してくれています。その中のLet’sEncrypt設定を行います。

sudo /opt/bitnami/bnhelper-tool
Domains

Please provide a valid space-separated list of domains for which you wish to 
configure your web server.

// アクセスされるドメイン名を入力
Domain list []: hazm.jp www.hazm.jp

----------------------------------------------------------------------------
Enable/disable redirections

Please select the redirections you wish to enable or disable on your Bitnami 
installation.

// HTTPをHTTPSにリダイレクトするか?
Enable HTTP to HTTPS redirection [Y/n]: Y

// hazm.jpをwww.hazm.jpにリダイレクトするか?
Enable non-www to www redirection [Y/n]: n

// www.hazm.jpをhazm.jpにリダイレクトするか?
Enable www to non-www redirection [y/N]: y

----------------------------------------------------------------------------
Changes to perform

The following changes will be performed to your Bitnami installation:

1. Stop web server
2. Configure web server to use a free Let's Encrypt certificate for the domains: 
hazm.jp www.hazm.jp
3. Configure a cron job to automatically renew the certificate each month
4. Configure web server name to: hazm.jp
5. Enable HTTP to HTTPS redirection (example: redirect http://hazm.jp to 
https://hazm.jp)
6. Enable www to non-www redirection (example: redirect www.hazm.jp to 
hazm.jp)
7. Start web server once all changes have been performed

// Yを入力
Do you agree to these changes? [Y/n]: Y

下記のように警告が出る場合は、DNSが浸透するまで少々時間を置いて再度試してください。私の環境では30分ほどで進めるようになりました。

Warning: The domain 'hazm.jp' does not resolve, please fix its DNS entries or 
remove it.

続きまして指示通りに入力を進めます。

----------------------------------------------------------------------------
Create a free HTTPS certificate with Let's Encrypt

Please provide a valid e-mail address for which to associate your Let's Encrypt certificate.

Domain list: hazm.jp www.hazm.jp

Server name: hazm.jp

// メールアドレスを入力
E-mail address []: youremailaddress@gmail.com

----------------------------------------------------------------------------
Performing changes to your installation

The Bitnami HTTPS Configuration Tool will perform any necessary actions to your 
Bitnami installation. This may take some time, please be patient.

----------------------------------------------------------------------------
Success

wordpressのパスワードを取得します。

cat bitnami_application_password

あとは、/wp-admin からログインすることができます。

ここまでの操作でhttpsでアクセスできるwordpressを構築完了です。

今回のまとめ

AWS Lightsail を利用すると、低コストで運用可能で、HTTPS接続にも対応したWordpressサイトを高速に構築することができました。HTTPS対応も、自動設定ツールがインストールされていて、証明書を別途用意する必要なく、無料で対応することができました。

レンタルサーバーを利用するのと比べて、root権限を持ったVPSのように利用できるため、自由度の高い環境を作り上げることができます。この部分に関してメリットを感じられる場合、LightSailが選択肢に入ってくるのかなと思います。

それでは。

カテゴリー
Uncategorized

動機

WordPressを立ち上げた動機。

ITエンジニアとして活動する上で、インプットとアウトプットは必要不可欠と考えていますが、日々の自分の生活を省みると、アウトプットが少ないのかなと感じることがあります。特に、自分の考えを上手くまとめることに苦手意識があり、これはまずいなと思うことがあります。

誰かに見てほしいわけではない、むしろ見て欲しくないとまで思っていますが、誰かに見られていると意識することは、アウトプットの質が上がったり、理解しやすい文章を考えたりと、プラスに働く面のあるのかなと考え、インターネット上に公開していくことにしました。

久しぶりにWordPressを立ち上げてみたけど、だいぶ使いやすくなっている気がします。エディタは本当に綺麗ですし。

構築にあたってはAWS LightSailを使用していますが、簡単に立ち上げられ、ランニングコストも抑えられ、良いことづくめだったので、これは別途、記事にしようと思います。

続くかなぁ…