覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

Kotlinの特徴

「Kotlinスタートブック」を読み始めたので、とりあえずKotlinの特徴として押さえておきたい点をメモしておきます。

Kotlinスタートブック -新しいAndroidプログラミング

Kotlinスタートブック -新しいAndroidプログラミング


開発元

JetBrains社


JVM言語である

KotlinはJVM言語であるため、JVM上で動作する。また既存のJava用のライブラリやフレームワークといった資産を利用できる。
JetBrains社は、"KotlinとJavaの相互運用は100%"と謳っている。
Kotlinで記述したプログラムから、Javaで記述されたプログラムを呼び出すこともできるし、その逆もできる。


簡潔さ

Kotlinはコードの見た目とそのはたらきの面で簡潔である。
セミコロンや型の指定の省略、データクラスや拡張関数等の機能を提供している。また記述されたコードは直観のままに動く。
簡潔であることで学習コストが小さく、プログラマの習熟レベルの違いによるコードのばらつきを抑えることができる。


安全性

KolinはJavaよりも安全に設計されている。型やnullの扱いが厳格。
特にnullにまつわる安全性確保の仕組みを「Null安全」と言う。


静的型付け

Kotlinで記述したソースコードはJavaバイトコードに変換される。


オブジェクト指向

Kotlinはクラスベースのオブジェクト指向言語である。Javaと同じように定義されたクラスのインスタンスを生成することができる。
ただし、intやcharなどのプリミティブ型は存在しない、全てがオブジェクトである。


関数型

第一級オブジェクトとしての関数が存在する。関数を通常の値と同様に関数の引数にしたり、戻り値として返したりすることができる。
これにより小さな粒度での再利用が可能となる。

ただし、Kotlinは関数型言語ではない。


採用実績

国内外に採用実績が広がっている。特にAndroidアプリの開発での利用が目立つ。

HR Tech x 機械学習 x AWS(Machine Learning)活用事例紹介に行ってきた

HR Tech x 機械学習 x AWS(Machine Learning)活用事例紹介 に参加してきました。

以下自分用のメモです。


概要

AWS Machine Learningを使用した機械学習を中心としたAIの導入事例を紹介

  • 日時: 2017/03/13(木)19:30〜
  • 場所: 株式会社ビズリーチ

HRMOSでのAI導入事例紹介

仲田大記 氏 (ビズリーチ HRMOS事業部)

  • HR領域のSaaS HRMOS の紹介
    • 人工知能×ビッグデータでの企業戦略
    • 人事データベースを中心に採用管理や勤怠管理、評価管理,,,etc
    • Deep Learningで人事領域の作業を効率化
    • ビズリーチがHR Techをやる強み
      • 人材サービスを展開していく中で得た知見
      • 大量の採用データを持っている
  • 機械学習の技術をどのように導入、活用しているか
    • 応募書類評価予測を作った理由
      • 声かけ1000人 ⇒ 面接設定85人 ⇒ 採用10人
      • 大量の応募情報を見る必要がある。面接、面談の属人化しがち
      • 書類選考の一次振り分け(優先順位付け)で利用される
    • 実装方法
      • python
      • R
      • scikit-learn
    • 使った技術・手法
      • 自然言語処理
      • 決定木
      • SVM
      • 多項ロジスティック回帰
    • はじめにやること
      • 統計解析などの数学的アプローチをとり、優位性があるかないかを確認する
      • 決定木のモデルを作ってみて、どこのどんなキーワードまたは数値が書類選考の結果に強い影響を持つか調べる
    • どうやってやっているか
      • elasticsearchを使ってデータを形態素解析する
  • AWS Machine Learning
    • DataSource, Model, Evaluation, Batch Prediction
    • Amazonは、cross-validationを提供してくれてはいない
      学習データをシャッフルすることで疑似的なcross-validationを実現できる
    • 精度が高くないときは、パス数の設定と正則化。パス数の設定が結構効く



関連エントリ

PostgreSQL - DBのデータをCSVに出力したい

DBのデータをCSV出力したいという場面は多々あると思います。

PostgreSQLにpsqlで接続して特定のコマンドを実行すればCSVファイルへの出力ができます。


テーブルの全データをCSVに出力する

単純に特定のテーブルの全データをCSV出力する場合は以下のコマンドを実行すれば可能です

\COPY {table名} TO '{出力先csvファイルのフルパス}' WITH CSV DELIMITER ',';

■実行例

\COPY sampletbl1 TO '/tmp/sampletbl1.csv' WITH CSV DELIMITER ',';

これを実行すると対象としたテーブルの全データが指定のcsvファイルに出力されます


CSVに出力するカラムを絞る

最初の例に従うと対象テーブルの全カラムが出力対象となります。
出力するカラムを指定したい場合は以下のようにします

\COPY {table名}({column名1}, {column名2}, {column名3}) TO '{出力先csvファイルのフルパス}' WITH CSV DELIMITER ','

■実行例

\COPY users(id, name, age) TO '/tmp/users.csv' WITH CSV DELIMITER ','

これを実行すると対象としたテーブルの指定のカラムのデータだけがcsvファイルに出力されます


カラム名もCSVに出力したい

これまでの例は、カラム名はCSVファイルに出力されません。
CSVの先頭行(ヘッダ)にカラム名を出力する場合は、HEADER という指定をします

\COPY {table名}({column名1}, {column名2}, {column名3}) TO '{出力先csvファイルのフルパス}' WITH CSV DELIMITER ',' HEADER

■実行例

\COPY users(id, name, age) TO '/tmp/users.csv' WITH CSV DELIMITER ',' HEADER

これを実行するとデータだけではなくcsvファイルのヘッダにカラム名も出力されます


SQLの実行結果をCSV出力する

CSVに出力したいデータの絞り込みや並び替えなど各種条件を指定したい場合は、SQLを実行した結果をCSVに出力するのが早いです。
以下のようにして実行します

\COPY ({SQL文(SELECT文)}) TO '{出力先csvファイルのフルパス}' WITH CSV DELIMITER ',' HEADER

■実行例

\COPY (SELECT id, name, age, where type = 0 order by registerdate limit 100) TO '/tmp/users.csv' WITH CSV DELIMITER ',' HEADER

これを実行するとSQLで得られた結果がcsvファイルに出力されます


値をダブルクォートで囲みたい

CSVに出力するデータをダブルクォート(")で囲みたい場合は FORCE QUOTE * という指定をします

\COPY ({SQL文(SELECT文)}) TO '{出力先csvファイルのフルパス}' WITH CSV DELIMITER ',' HEADER FORCE QUOTE *

■実行例

\COPY (SELECT id, name, age, where type = 0) TO '/tmp/users.csv' WITH CSV DELIMITER ',' HEADER FORCE QUOTE *

日付のフォーマット処理する時にどれだけメモリ消費するの?

業務アプリケーションを作成する上で、日時を取り扱うのは日常茶飯事だと思います。
例えば、生成した日付オブジェクトを特定のフォーマットパターンで文字列化する という処理の流れは大体どんなシステムでも実施されます。

これをJavaで実現する場合、現在日時を文字列化するなら以下のようにするのが一般的かと思います。

  • Java7以下の場合
    • java.util.Dateのオブジェクトを生成 ⇒ SimpleDateFormat#format で文字列化
  • Java8以上の場合
    • LocalDateTimeのオブジェクトを生成 ⇒ LocalDateTime#format(DateTimeFormatter) で文字列化


では、日時をフォーマットするための肝となっているSimpleDateFormatやらDateTimeFormatterは、どのくらいメモリを食うのだろうかとふと思い、確認してみました。


今回は以下の2パターンのフォーマットパターンを対象としました

  • yyyy/MM/dd HH:mm:ss
  • yyyy/MM/dd HH


また、メモリ消費量の確認にはJOLを利用しました


LocalDateTimeをDateTimeFormatterでフォーマット

LocalDateTime#nowで現在日時を生成し、DateTimeFormatterを利用してLocalDateTime#formatで所定の形式の文字列にするという流れです


■測定用コード

import org.openjdk.jol.info.GraphLayout;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;


LocalDateTime dateTime = LocalDateTime.now();
DateTimeFormatter format1 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
DateTimeFormatter format2 = DateTimeFormatter.ofPattern("yyyy/MM/dd");

String dateTimeStr1 = dateTime.format(format1);
String dateTimeStr2 = dateTime.format(format2);


System.out.println("LocalDateTime totalSize(byte) -> " + GraphLayout.parseInstance(dateTime).totalSize());
System.out.println("LocalDateTime footprint -> \n" + GraphLayout.parseInstance(dateTime).toFootprint());

System.out.println("------------");

System.out.println("DateTimeFormatter(yyyy/MM/dd HH:mm:ss) totalSize(byte) -> " + GraphLayout.parseInstance(format1).totalSize());
System.out.println("DateTimeFormatter(yyyy/MM/dd HH:mm:ss) footprint -> \n" + GraphLayout.parseInstance(format1).toFootprint());

System.out.println("------------");

System.out.println("DateTimeFormatter(yyyy/MM/dd) totalSize(byte) -> " + GraphLayout.parseInstance(format2).totalSize());
System.out.println("DateTimeFormatter(yyyy/MM/dd) footprint -> \n" + GraphLayout.parseInstance(format2).toFootprint());

■実行結果

LocalDateTime totalSize(byte) -> 72
LocalDateTime footprint -> 
java.time.LocalDateTime@6576fe71d footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1        24        24   java.time.LocalDate
         1        24        24   java.time.LocalDateTime
         1        24        24   java.time.LocalTime
         3                  72   (total)


------------
DateTimeFormatter(yyyy/MM/dd HH:mm:ss) totalSize(byte) -> 3688
DateTimeFormatter(yyyy/MM/dd HH:mm:ss) footprint -> 
java.time.format.DateTimeFormatter@4361bd48d footprint:
     COUNT       AVG       SUM   DESCRIPTION
        38        34      1296   [C
         1        64        64   [Ljava.time.format.DateTimeFormatterBuilder$DateTimePrinterParser;
        38        24       912   java.lang.String
         7        24       168   java.time.Duration
         1        40        40   java.time.format.DateTimeFormatter
         5        16        80   java.time.format.DateTimeFormatterBuilder$CharLiteralPrinterParser
         1        24        24   java.time.format.DateTimeFormatterBuilder$CompositePrinterParser
         6        32       192   java.time.format.DateTimeFormatterBuilder$NumberPrinterParser
         1        24        24   java.time.format.DecimalStyle
         1        24        24   java.time.format.ResolverStyle
         2        24        48   java.time.format.SignStyle
         6        40       240   java.time.temporal.ChronoField
         7        32       224   java.time.temporal.ChronoUnit
         6        48       288   java.time.temporal.ValueRange
         1        32        32   java.util.Locale
         1        32        32   sun.util.locale.BaseLocale
       122                3688   (total)


------------
DateTimeFormatter(yyyy/MM/dd) totalSize(byte) -> 2184
DateTimeFormatter(yyyy/MM/dd) footprint -> 
java.time.format.DateTimeFormatter@64cee07d footprint:
     COUNT       AVG       SUM   DESCRIPTION
        23        32       752   [C
         1        40        40   [Ljava.time.format.DateTimeFormatterBuilder$DateTimePrinterParser;
        23        24       552   java.lang.String
         4        24        96   java.time.Duration
         1        40        40   java.time.format.DateTimeFormatter
         2        16        32   java.time.format.DateTimeFormatterBuilder$CharLiteralPrinterParser
         1        24        24   java.time.format.DateTimeFormatterBuilder$CompositePrinterParser
         3        32        96   java.time.format.DateTimeFormatterBuilder$NumberPrinterParser
         1        24        24   java.time.format.DecimalStyle
         1        24        24   java.time.format.ResolverStyle
         2        24        48   java.time.format.SignStyle
         3        40       120   java.time.temporal.ChronoField
         4        32       128   java.time.temporal.ChronoUnit
         3        48       144   java.time.temporal.ValueRange
         1        32        32   java.util.Locale
         1        32        32   sun.util.locale.BaseLocale
        74                2184   (total)

結果(メモリサイズ)は以下のようになっています

  • yyyy/MM/dd HH:mm:ss形式のDateTimeFormatter ・・・ 3688byte
  • yyyy/MM/dd 形式のDateTimeFormatter ・・・ 2184byte
  • LocalDateTime ・・・ 72byte

結果を見てわかる通りですが、yyyy/MM/dd HH:mm:ss か yyyy/MM/dd かでDateTimeFormatterのサイズが大きく異なっています


java.util.DateをSimpleDateFormatでフォーマット

java.util.Dateのコンストラクタで現在日時を生成し、SimpleDateFormat#formatで所定の形式の文字列にするという流れです


■測定用コード

import org.openjdk.jol.info.GraphLayout;

import java.text.SimpleDateFormat;
import java.util.Date;


Date dateTime = new Date();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy/MM/dd");

String dateTimeStr1 = sdf1.format(dateTime);
String dateTimeStr2 = sdf2.format(dateTime);

System.out.println("java.util.Date totalSize(byte) -> " + GraphLayout.parseInstance(dateTime).totalSize());
System.out.println("java.util.Date footprint -> \n" + GraphLayout.parseInstance(dateTime).toFootprint());

System.out.println("------------");

System.out.println("SimpleDateFormat(yyyy/MM/dd HH:mm:ss) totalSize(byte) -> " + GraphLayout.parseInstance(sdf1).totalSize());
System.out.println("SimpleDateFormat(yyyy/MM/dd HH:mm:ss) footprint -> \n" + GraphLayout.parseInstance(sdf1).toFootprint());

System.out.println("------------");

System.out.println("SimpleDateFormat(yyyy/MM/dd) totalSize(byte) -> " + GraphLayout.parseInstance(sdf2).totalSize());
System.out.println("SimpleDateFormat(yyyy/MM/dd) footprint -> \n" + GraphLayout.parseInstance(sdf2).toFootprint());

■実行結果

java.util.Date totalSize(byte) -> 24
java.util.Date footprint -> 
java.util.Date@3f99bd52d footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1        24        24   java.util.Date
         1                  24   (total)


------------
SimpleDateFormat(yyyy/MM/dd HH:mm:ss) totalSize(byte) -> 4616
SimpleDateFormat(yyyy/MM/dd HH:mm:ss) footprint -> 
java.text.SimpleDateFormat@1963006ad footprint:
     COUNT       AVG       SUM   DESCRIPTION
        65        25      1656   [C
         4        58       232   [I
         1        96        96   [J
         6        48       288   [Ljava.lang.String;
         1        40        40   [Z
        63        24      1512   java.lang.String
         1        24        24   java.math.RoundingMode
         1        64        64   java.text.DateFormatSymbols
         1       144       144   java.text.DecimalFormat
         1        64        64   java.text.DecimalFormatSymbols
         1        40        40   java.text.DigitList
         1        64        64   java.text.SimpleDateFormat
         1        24        24   java.util.Currency
         1        24        24   java.util.Date
         1       112       112   java.util.GregorianCalendar
         1        32        32   java.util.Locale
         1        16        16   sun.util.calendar.Gregorian
         1        96        96   sun.util.calendar.Gregorian$Date
         1        56        56   sun.util.calendar.ZoneInfo
         1        32        32   sun.util.locale.BaseLocale
       154                4616   (total)


------------
SimpleDateFormat(yyyy/MM/dd) totalSize(byte) -> 4592
SimpleDateFormat(yyyy/MM/dd) footprint -> 
java.text.SimpleDateFormat@61baa894d footprint:
     COUNT       AVG       SUM   DESCRIPTION
        65        25      1632   [C
         4        58       232   [I
         1        96        96   [J
         6        48       288   [Ljava.lang.String;
         1        40        40   [Z
        63        24      1512   java.lang.String
         1        24        24   java.math.RoundingMode
         1        64        64   java.text.DateFormatSymbols
         1       144       144   java.text.DecimalFormat
         1        64        64   java.text.DecimalFormatSymbols
         1        40        40   java.text.DigitList
         1        64        64   java.text.SimpleDateFormat
         1        24        24   java.util.Currency
         1        24        24   java.util.Date
         1       112       112   java.util.GregorianCalendar
         1        32        32   java.util.Locale
         1        16        16   sun.util.calendar.Gregorian
         1        96        96   sun.util.calendar.Gregorian$Date
         1        56        56   sun.util.calendar.ZoneInfo
         1        32        32   sun.util.locale.BaseLocale
       154                4592   (total)

結果(メモリサイズ)は以下のようになっています

  • yyyy/MM/dd HH:mm:ss形式のSimpleDateFormat ・・・ 4616byte
  • yyyy/MM/dd 形式のSimpleDateFormat ・・・ 4592byte
  • java.util.Date ・・・ 24byte

SimpleDateFormatはフォーマットパターン(形式)によるメモリサイズの差があまりありません。


まとめとか補足

  • 日時をフォーマットするためのクラスのメモリサイズはでかい
  • SimpleDateFormatDateTimeFormatterに比べてサイズが大きい
  • DateTimeFormatterはフォーマットパターン(形式)によってメモリサイズが大きく異なる
  • SimpleDateFormatはフォーマットパターン(形式)によるメモリサイズの差があまりない
  • DateTimeFormatterスレッドセーフSimpleDateFormatスレッドアンセーフ



関連エントリ

Linuxでよくお世話になるスペシャルファイルに関するメモ

開発やテストの際などによくお世話になるLinuxのスペシャルファイル(の中の疑似デバイス)に関するメモです


/dev/null

書かれたデータは捨てられる。

null スペシャルファイルを読むと常に end of file が返される。


/dev/zero

書かれたデータは捨てられる。

常に \0 文字(null 文字)が返される


例えば、以下を実行するとnull文字で埋められた10MBのファイルを生成することができる

dd if=/dev/zero of=sample_10MB.dat bs=10M count=1


/dev/full

/dev/full デバイスへの書き込みは ENOSPC エラーとなり失敗する。
この動作を使ってプログラムがディスクフルのエラーをどのように処理するかをテストできる。

[root]# echo "Hello world" > /dev/full
-bash: echo: write error: デバイスに空き領域がありません


/dev/random

可変長の擬似乱数文字列を生成する(ブロックする)


/dev/urandom

可変長の擬似乱数文字列を生成する(ブロックしない)


例えば、以下を実行するとランダムな値で埋められた10MBのファイルを生成することができる

dd if=/dev/urandom of=sample_10MB.dat bs=10M count=1