ドメインのWHOISやサイトの情報を調べることのできるサービスDomainWatchですが、7月半ばからシステムに問題が発生し、新規にドメインのWHOISを照会する機能を停止していました。

広告

具体的に言うと、DomainWatchのデータベースはMySQL(MariaDB)を、全文検索にはMySQL用のストレージエンジンMroongaを採用していたのですが、件数が多すぎたせいでMroongaはキーのサイズが4GBまでという制限に引っかかってしまいました。

(MySQLの上限と書いていますが、Mroongaの制限が正しいですね)

そこでMroongaではもうあかんということになり、長らく検討していたElasticsearchへの移行を決めました。Elasticsearch自体は別のプロジェクト(非公開)で使用しており、ある程度ノウハウはありました。

Elasticsearchのアナライザー(データ格納時に指定した処理をなんかかんやしてくれるやつ)はこんな感じにしています。

{
  "analysis": {
    "analyzer": {
      "whois_analyzer": {
        "type": "custom",
        "tokenizer": "icu_tokenizer",
        "filter": "ngram"
      }
    }
  }
}

ICU TokenizerとN-gramを合わせるとハイブリッドでいいらしいです。
(8/20):検索精度が悪いため、結局N-gramはやめました

KuromojiなどではなくICUを選んだ理由としては、WHOIS情報は日本語だけでなく全言語の文字をサポートする必要があるためです。

MySQLのデータをElasticsearchに移行するにあたっては、Logstashを利用しました。

sudo yum install logstash

(Elasticsearchのリポジトリを追加する必要あり)

適当な .conf を作ります。

input {
  jdbc {
    jdbc_driver_library => "/usr/share/java/mysql-connector-java.jar"
    jdbc_driver_class => "com.mysql.jdbc.Driver"
    jdbc_connection_string => "jdbc:mysql://localhost:3306/{database}"
    jdbc_user => "{username}"
    jdbc_password => "{password}"
    jdbc_paging_enabled => true
    jdbc_page_size => 100000
    statement => "SELECT * FROM whois"
  }
}
output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "whois"
    pipeline => "date_pipeline"
  }
}

こんな感じで実行

/usr/share/logstash/bin/logstash -f mysql2elasticsearch.conf

データが400万件以上あるため、 jdbc_page_size を指定して10万行ごとに処理するようにしたところ、うまくいきました。 statement ではインポートするレコードを指定しています(テーブル whois の全レコード)。

また、MySQLでは日付文字列をDATETIMEの Y-m-d H:i:s 形式で格納していたため、これをElasticsearchの型 date_time_no_millis の yyyy-MM-dd’T’HH:mm:ssZZ 形式に直す必要がありました。これにはIngest機能を使い、Pipelineを作成しました。

{
  "description" : "date pipeline",
  "processors" : [
    {
      "gsub" : {
        "field": "created_at",
        "pattern": " ",
        "replacement": "T",
        "ignore_missing": true
      }
    },
    {
      "gsub" : {
        "field": "updated_at",
        "pattern": " ",
        "replacement": "T",
        "ignore_missing": true
      }
    },
    {
      "gsub" : {
        "field": "expires_at",
        "pattern": " ",
        "replacement": "T",
        "ignore_missing": true
      }
    },
    {
      "gsub" : {
        "field": "added_at",
        "pattern": " ",
        "replacement": "T",
        "ignore_missing": true
      }
    }
  ]
}

Elasticsearchへの格納時に日付フィールドの文字列に含まれる半角スペースをTに変換しているだけですね。

Elasticsearchに移行したことで、複雑なクエリも検索できるようになりました。

例: domain:*tokyo* AND domain:*2020*

新しくなったDomainWatchを今後もご活用ください。

広告

投稿をシェア

記事の内容が面白いと思ったら、SNSでシェアしていただけると記事を投稿するモチベーションにつながります。

ディスカッションに参加

7件のコメント

  1. 他のと違ってCAPTCHAがないのでサクッと調べられてありがたい。

  2. 2点、要望と質問があります

    1. DomainWatchで、CIDR内に属するドメインを表示するよう、「検索機能」を改善してほしい。
    例→ cidr:1.2.3.4/24 (この範囲内の全ドメイン)

    2. 検索結果に「APIあります」という表示がありますが、domainwat.chはCloudflareをつかっており、TorやAPIを使うプログラム(curl/py)をブロックするのではないでしょうか?
    「https://domainwat.ch/api/search?」がブロックされるとAPIの意味がない(使えない)のでは。
    1のCIDR検索ができるようになれば、APIを使ってみようと思ってます。

    1. 1. 検索はドメインのWHOISしか有効になっていないので、別で作ることを検討します。
      2. Tor経由のcURLだとブロックされる可能性はあります。

コメントを残す

匿名 にコメントする コメントをキャンセル

メールアドレスが公開されることはありません。

広告