notepad.exe

つまり覚え書き

DBでテーブルのカラムにindexを張るとどれくらい変わるか調べる

SQLをいじっていて気になったので試してみました。 データベースはMySQLを使用しています。

使用するデータはこちらのサイト にあるsubmissionデータのcsvファイルです。

事前設定

csvファイルからデータを読み込むためにmysqlの設定を変更します。 デフォルトではファイルからの読み込みはセキュリティの問題上拒否されるようになっているのでこれを許可します。 my.cnfに以下の設定を追加します。

[mysqld]
loose-local-infile = 1

設定を書いたらサーバを再起動してMySQLにログインします。 ここでもログインコマンドにオプションを設定してログインします。

 $ mysql -u root -p --local-infile=1

データベース、テーブルの作成、データのロードを行います。SQL文は以下の通りです。 テーブル定義は元のデータに合わせて作っていて、idに主キーを設定した状態にします。

CREATE DATABASE IF NOT EXISTS atcoder;
USE atcoder;

DROP TABLE IF EXISTS submissions;
CREATE TABLE submissions (
    id             BIGINT        NOT NULL,
    epoch_second   BIGINT        NOT NULL,
    problem_id     VARCHAR (255) NOT NULL,
    contest_id     VARCHAR (255) NOT NULL,
    user_id        VARCHAR (255) NOT NULL,
    language       VARCHAR (255) NOT NULL,
    point          DOUBLE        NOT NULL,
    length         INT           NOT NULL,
    result         VARCHAR (255) NOT NULL,
    execution_time INT,

    PRIMARY KEY (id)
);

LOAD DATA 
    LOCAL INFILE './atcoder_submissions.csv' 
    INTO TABLE submissions 
    FIELDS TERMINATED BY ',' 
    LINES TERMINATED BY '\n'
    IGNORE 1 LINES;

何も考えずにクエリを発行してみる

まずはそもそもデータが何件あるか取得します。

mysql> select count(*) from submissions;
+----------+
| count(*) |
+----------+
|  3498339 |
+----------+
1 row in set (0.68 sec)

約350万件ですね。

全体のAC数を数えます

mysql> select count(*) from submissions where result='AC';
+----------+
| count(*) |
+----------+
|  1742578 |
+----------+
1 row in set (0.82 sec)

AC数が多いユーザ(重複なし)の上位10名を出してみます。

mysql> select user_id, count(distinct problem_id) as accepted_sum 
    -> from submissions 
    -> group by user_id order by accepted_sum desc limit 10;
+------------+--------------+
| user_id    | accepted_sum |
+------------+--------------+
| kmjp       |         2197 |
| ei13333    |         1930 |
| beet       |         1880 |
| latte0119  |         1810 |
| E869120    |         1652 |
| uwi        |         1573 |
| MAK_culcul |         1540 |
| square1001 |         1510 |
| leafmoon   |         1455 |
| mamekin    |         1426 |
+------------+--------------+
10 rows in set (48.57 sec)

流石に時間かかりますね。

カラムにindexを付ける

ユーザIDの絡むに対してindexをつけます

alter table submissions add index user_id(user_id)

そして同じクエリを実行

mysql> select user_id, count(distinct problem_id) as accepted_sum 
    -> from submissions 
    -> group by user_id order by accepted_sum desc limit 10;
+------------+--------------+
| user_id    | accepted_sum |
+------------+--------------+
| kmjp       |         2197 |
| ei13333    |         1930 |
| beet       |         1880 |
| latte0119  |         1810 |
| E869120    |         1652 |
| uwi        |         1573 |
| MAK_culcul |         1540 |
| square1001 |         1510 |
| leafmoon   |         1455 |
| mamekin    |         1426 |
+------------+--------------+
10 rows in set (22.88 sec)

半分以下になりましたね。

今回はテーブルが一つですが複数テーブルを使うクエリで適切にindexを設定すればより効果が大きく感じられると思います。

2019年の目標

あけましておめでとうございます。
というわけで今年の目標をいくつか上げてみたいと思います。

webサービス開発周りの技術力を向上させる

2019年は転職する流れもあり、JavaからRubyにメインの言語が変わります。 Javaは業務で問題ないレベルでかけますがRubyはまだそうは行かないので、 Railsと合わせてコーディング力を向上させることを目標とします。
あとはDockerなどの周辺技術も知識をちゃんと深くして行ければと。 とりあえず手始めに何かWebサービスを作って公開したいです…

英語と中国語を勉強する

この2つは理解力を上げておくと後々効いてくるので一定レベルまで上げておきたいところ。 英語はTOEIC700~800点あたり、中国語はHSK5級か6級を取っておきたいですね。 とりあえず2月と3月にどちらも受験をする予定なので1、回だけで終わらせずに継続させたいです。

競プロを続ける

そもそも今やっているかと言われると少し怪しいですが…
どうしても仕事やキャリアに向かった技術力に目を向けてしまいがちですが、 趣味もしっかりと頑張りつつほそぼそとやっていきたいですね。 転職して少し落ち着いたらAtCoder青に向けての精進集中期間を作りたいですね。

これ以外にも沢山本を読むとかKaggleやってみたいとか色々ありますが、 あまり目標を立てすぎても達成するのが困難になってしまうだけなのでこれくらいにしておきます。 というわけで、今年もより強い自分を目指して日々努力をしていきます!

Rails と Puma と Nginx と

Railsアプリケーションの本番環境を作ったりするときに Puma とか Nginx だとかいう 単語が出てくるわけですが、何となくわかっているつもりでも意外と説明するのが難しいものです。 というわけで質問されても困らないようにまとめます。

各要素について

Ruby on Rails

Rubyで作られたwebアプリケーションフレームワークアーキテクチャMVCモデルが採用されていて最小限のコードでwebアプリを作成することができる。Modelの部分ではActive Record、Viewの部分ではERBが使われています。

  • Active Record O/Rマッピングシステム内にある「Active Recordパターン」を実装したもの(理論と実装の名前が同じ) Active Recordの機能として大事なのは以下のところです。

    • モデルのデータを表現すること
    • モデル間の関連付けをすること
    • 関連するモデルの階層関係を表現すること
    • DBによって永続化される前にモデルの正当性を検証すること
    • オブジェクト指向の書き方でDBを操作すること
  • ERB 任意のテキストファイルにrubyスクリプトを埋め込むためのライブラリ Rubyの構文を使ってhtmlを繰り返したり、変数の値をテキストとして埋め込むことができます。

Puma

Rubyアプリケーションサーバrails new とコマンドを打ってRailsアプリケーションを作成するとこいつがアプリケーションサーバとして設定されている。 Pumaではリクエストの並列処理を実現するためにスレッドが利用されているのが特徴。 開発環境でrails sとやってサーバを立ち上がっているときに動いているのはこいつ。

Nginx

webサーバー。開発環境のときはPumaで動作させるが、 本番環境などでは一旦Nginxで受け付けてRailsアプリケーションでの処理が必要なものだけを Puma対してリクエストを行う形にする。 Webサーバといえば「Apache」もあげられるが、 こちらのほうが大量のデータ配信や同時接続に耐える設計がなされている。 (同時接続数で言うとApacheの10~100倍くらい可能)

開発環境と本番環境

開発環境でサーバを立ち上げて接続しているときは以下のような形になっています。 f:id:mosmos_21:20181222224329p:plain

しかし本番環境を構築する場合はアプリケーションサーバの前にWebサーバをおきます。Webサーバはアプリケーションサーバの代わりにクライアントからのリクエストを受け付けています。(Nginxがリバースプロキシとして動いている) f:id:mosmos_21:20181222224513p:plain

わざわざ間にサーバを増やさずに直接アプリケーションサーバを公開すればいいのではとなりますが、 そうもいかないのは当然理由があります。

PumaはWorkerとThreadいう単位でリクエストを受け付けて処理を行います。 設定によって変更可能ですがWorkerのおよび、Threadの数だけ並列でリクエストを処理することができます。 とはいえここでの並列受け付けはせいぜい数十程度が限界です。実際にサービスが公開されれば数百~数千、多ければ数万という単位でリクエストが来る可能性が考えられます。そこで同時接続受付の上限が大きいWebサーバを前において、いい感じにアプリケーションサーバに振り分けてもらうことで多くのアクセスに耐えることができるようにします。

全体を通すと本番環境にアクセスしたときの流れは以下のようになります。

まとめ

最小限の説明だけにすると上のような説明になると思います。 ただ、調べていく中でほかにもいろいろな要素が出てきたので(RackとかUnicornとか、あとRubyの処理系についても)、 実際に動かしたり追加で調べたりしながら理解を深めようと思います。

エンジニアを職業にするということ

この記事は「貴族会 Advent Calendar 2018」の9日目の記事です。

はじめに

11月にサボり癖がついてしまい長らく記事を書いていませんでした。 そういえばアドベントカレンダーに登録したなと思っていつだっけとカレンダーを見たら今日だったので、 大急ぎで書いています。

エンジニアという職業

私は今エンジニアとして日々働いています。 とはいえ別に昔から強い思い入れがあったからエンジニアをしているというわけではなく、 いろいろあって専門学校に行くことになったのでそのままそのスキルを一番活かせるエンジニアの道に進んだだけです。

とは言え、社会人になってエンジニアとして働くうちに楽しくなっていろいろなスキルを付けるようになりました。 その中で勉強会に行ったりいろいろなエンジニアと話したりしていくうちに、 このエンジニアという職業についていろいろ考える機会があったのでそのうちの一つだけまとめます。

なぜ新しい技術を学びスキルを付けるのか

大抵のエンジニアは日々勉強していると思います。 「日々勉強していること」それは何を「目的」としているのでしょうか。

技術を身に着けるのが楽しくなって技術を身に着けることが目的となっている人がいますが、 それは違うと思っています。技術をつけた先に何かしたいことがあるからこそその技術を学んでいるので、 技術を学ぶことはあくまで一つの「目標」なのです。

何か達成したいことがあるからこそそれを実現するための技術が必要となり、そのために毎日勉強をしている。 それが答えだと思います。

エンジニアとしての目的とはなにか

まず、エンジニアに限らす社会人(企業そのものも含む)としての目的ですが、 何らかの問題を解決、または価値を与えることだと思います。 この目的はエンジニアに絞っても同じままだと思います。 エンジニアはあくまでその手段が技術を使うということになっただけです。 その問題や価値をより大きいものにするために日々技術の勉強をしているわけですね。

自分ができること

価値を提供するとか問題を解決するとか聞くと難しく聞こえてしまいますが実際はそんなことはありません。 小さな価値の提供であれば、例えばブログを書くことも読んだ人にとって何かしらの収穫があれば、 そのブログの記事は価値を提供していると考えることができるのです。

たしかに目的を意識することは大切ではありますが、あまり意識を強く持ちすぎずとりあえず何かしらの物を他人に提供するだけでも一つの成果となります。 提供してみなければ問題を解決できるかもわからないし、価値の提供をおこなえるかどうかもわかりません。

そのためにも、とりあえず行動をする・とりあえず勉強をするといったことは大切になってくるわけですね。

まとめ

  • スキルを身に着けることは目的に対する一つの手段である
  • 目的には問題解決や価値提供などの形が考えられる
  • 目的を考えて日々の勉強をする
  • とはいえ意識しすぎずとりあえずやってみるのは大事

社内プロコンの問題作ったよ!(2回目)

というわけで前回に引き続き社内プロコン(一般)の問題を作りました。

問題は全部で4問で配点はこんな感じ。

  問題 満点
A Bring Boarding Pass 50
B Rita in Roma 100
C Boarding is Boring 150
D Souvenir Sequence 200

難易度は ABC を意識した難易度で作っていて、時間は3時間です。 すべての問題について部分点がかならず設定されていて、 一部でもあっていれば点数が入るようなテストデータになっています。

実はなんと今回D問題の案は けんちょんさん に作っていただきました!!!
ありがとうございました!!
本当にレベルも高い問題で感謝も大きく勉強することも多かったです。

A - Bring Boarding Pass

入力として  x, a, b が与えられて大きさ  x (S or L) の飛行機の前から  a 番目、 左から  b 番目の座席番号を出力する問題。 小さい飛行機が 33 の座席で大きい飛行機が 343 の座席です。 入力例と出力例はこんな感じ。

  • 入力 L 10 9
  • 出力 10J

これは座席の英字が ABC DEFG HJK と言うようになっているので注意が必要ですねと言う問題でした。

B - Rita in Roma

ローマ数字をアラビア数字に変換する問題。 入力例と出力例はこんな感じ。

  • 入力 MMMCMXCIX
  • 出力 3999

基本的には対応している数字を足していくのですが、4とか9の表記が減算側で表記されているので そこに注意して変換を行えばいい問題でした。

C - Boarding is Boring

数字で遊ぶ問題です。入力として a, b ( 0 \leq a, b \leq 10^5 ) が与えられて、 a に対して以下の3種類を行うことができます。

  •  a に2をかける
  •  a を2で割り小数点以下を切り捨てる
  •  a に1を足す

この3つの各操作を好きな回数行うことができるときに a bにするための最小の操作回数を求めてくださいという問題です。 ちなみに操作を行ったことによるオーバーフローなどは考えないとします。

入力例と出力例はこんな感じ。

  • 入力 17 4
  • 出力 2

この問題はC問題として出したのですが、コンテストが終わってみると通してる人がほとんどいなくてびっくりしました。
(思ったより難しかったみたい?)ちょっと反省

D - Souvenir Sequence

これはけんちょんさんにいただいた問題の原文が一番ようやくとしてわかりやすいのでそれを載せます。

 n 個の整数から成る数列  a_1, a_2, \dots, a_n が与えられる。 これを  K 個の連続する区間に分割して、各区間について総和をとって得られる数  b_1, b_2, \dots, b_K の最大値を最小化したい。

これの最小値を求めてくださいという問題でした。 制約は、

  •  2 \le K \le N \le 5000
  •  0 \le a_i \le 1000

部分点として  K = 1, 2, 3 の時にそれぞれ50, 100, 150 点が入るようになっています。 入力例と出力例はこんな感じ。

  • 入力
5 2
3 6 7 1 9
  • 出力
16

実は、案をいただいた時は  -1000 \le a_i \le 1000 という制約だったのですが、 この制約にすると、満点解法の難易度がAtCoderでいうと500点レベルになります。 これだとさすがに社内で誰も解けないだろう、ということで泣く泣く制約を小さくさせていだたきました… この問題は各部分点に対しての解法がしっかりと考え込まれていて、これが競プロの上位の力かと思い知らされました。(すごい)

問題文と回答例はあとでGitHubにアップします。
上級の方の感想は書くか考え中…

登壇の覚え書き & 転職活動終わりました

二つまとめてメモ

登壇の覚えがき

話したのはこれです

supporterzcolab.com

少し前に話したのとほとんど同じ内容です。 一度やったこともあり、話はかなり落ち着いてすることができたと思います。 内容自体も前回から時間がたち理解度も上がっているのでそのあとの懇親会の中でのお話も 上手くできたように感じます。次回もし同じような内容を話すとしたらもう少しデザインパターンを混ぜこんだ内容にするのもありかなと感じました。 反省は特にないですが、次は月末にもう一回登壇があるのでそちらの準備を頑張らねば…

転職活動終わりました

タイトルの通りです。 転職活動のスタートは前にも載せましたがこのツイートから

このツイートを見ていただいて自分が想像していた以上の方から声をかけていただきました。 その中の1社でご縁ある話をいただけたので転職活動自体は1週間くらいですかね。

次の会社は現職との必要スキルが違う部分が多いので入社までになんとかしておかないとならないので、 今から勉強を頑張ります。

転職活動始めてました

そういえば書いてませんでした。

新しいことをやりたくなったので転職活動を始めました。

とりあえずやっていることはエージェントに登録したことと、 Twitterハッシュタグ付けてつぶやいたことくらいです。

そしたらいくつか面白そうなところからお話しいただいたのでもしかしたらこの中から決めて転職活動終了かも…