Search on the blog

2018年4月28日土曜日

español 19

¡Hola, amigo!
Me llamo Kenji. Estoy aprendiendo español.

今日は、mi amigaとレストランに行くことを想像しつつ、レストランでの会話の練習をした。

Tengo hambre.
お腹すいたよ。
- tengo = (I) have

Tengo sed. ¿Tienes algo de tomar?
喉が乾いた。何か飲み物もってる?
- algo = something
- tomar = drink

¿Tiene una mesa para dos?
二人ですが、テーブル空いてますか?
- mesa = table

¿Fumadores o no fumadores?
喫煙席ですか?禁煙席ですか?
- o = or

Lo siento. Hemos cerrado.
ごめんなさい。閉店しています。
- hemos = (we) have
- cerrado = closed

Estamos llenos. Hay que esperar.
満席です。待たないといけません。
- llenos = full
- hay que = one must
- esperar = wait

¿Cuánto hay que esperar?
どれくらい待たないといけませんか?
- cuánto = how long

¿Tiene un menú en inglés?
英語のメニューはありますか?

Quiero esto.
これください。
- quiero = (I) want
- esto = this

¿Qué me recomienda?
何がオススメですか?
- qué = what

¿Que están comiendo ellos?
彼らは何を食べているのですか?

¿Qué lleva este plato?
この料理には何が入っていますか?
- lleva = (it) carries
- este = this
- plato = dish


2018年4月21日土曜日

A Survey on Real Time Bidding Advertising

元ネタ
A Survey on Real Time Bidding Advertising

気付き
- DSPはSSPから広告枠を買い付けていると思っていたが、厳密にはAd Exchangeから買っているらしい。SSPと思っていたサービスのサイトをよく見ると、確かにAd Exchangeと書いていた。

- 広告主からマージンをもらって儲けるOpen DSPと、自社の様々な事業の広告を配信して事業の売り上げ増加を目指すNative DSPでは戦略が違うので、その辺りを意識してサーベイする必要がある。

メモ
RTB広告の成長
- 2017年にはディスプレイ広告予算の29%を占める見込み
- 昔: プレミアムな在庫はオフラインで、残りはRTBで
- 最近: プレミアムな在庫もRTBで

DSPでは効率的な入札アルゴリズムが重要
- 最適な広告を選択する
- 最適な入札額を決める

DSPが目指すパフォーマンスの最大化
- インプレッション数
- クリック数
- コンバージョン数

DSPの時間制約
- 10〜100 milli sec
- 入札戦略を最適化するオフラインコンポーネント
- 前もって最適化された戦略を実行するオンラインコンポーネント

予算配分
- 複数の媒体
- DSP業者
- キャンペーン

オークション方式
- Vickery (セカンドプライス)
- OSP (オプショナルセカンドプライス)

フリークエンシーキャップの最適化
- RTBでは個々のクッキーに対してフリークエンシーを制御できる
- 広告主の予算の浪費を抑える

2018年4月19日木曜日

Apache Beam: 正常データ、異常データを別々に処理

 Beam 1.xのときは、side outputを使って異常系のデータをDLQに別途出力するということができた。Beam 2.xになってからside outputがなくなっていたので、どうやるかを試してみた。以下のようにPTransformの中でタグをつけて出力すれば良さそう。

 今回はDLQとしてキューじゃないけどGCSを使ってみた。UnboundedなデータをBoundedな場所に格納することになるのでややこしそうだけど、windowを使えば簡単に実現できる。

サンプルコード

package com.kenjih.sample.side_output;

import org.apache.beam.runners.dataflow.options.DataflowPipelineOptions;
import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.io.TextIO;
import org.apache.beam.sdk.io.gcp.pubsub.PubsubIO;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.apache.beam.sdk.transforms.DoFn;
import org.apache.beam.sdk.transforms.ParDo;
import org.apache.beam.sdk.transforms.windowing.FixedWindows;
import org.apache.beam.sdk.transforms.windowing.Window;
import org.apache.beam.sdk.values.PCollection;
import org.apache.beam.sdk.values.PCollectionTuple;
import org.apache.beam.sdk.values.TupleTag;
import org.apache.beam.sdk.values.TupleTagList;
import org.joda.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * GCS-based Dead letter queue example
 *
 * @see <a href="https://stackoverflow.com/questions/45173668/gcp-dataflow-2-0-pubsub-to-gcs/45256314#45256314">GCP Dataflow 2.0 PubSub to GCS</a>
 * @see <a href="https://cloud.google.com/blog/big-data/2016/01/handling-invalid-inputs-in-dataflow">Handling Invalid Inputs in Dataflow</a>
 */
public class Main {

  private static final Logger LOG = LoggerFactory.getLogger(Main.class);

  private static class ParseToIntDoFn extends DoFn<String, String> {

    private final TupleTag<String> successTag;
    private final TupleTag<String> invalidTag;

    public ParseToIntDoFn(TupleTag<String> successTag, TupleTag<String> invalidTag) {
      this.successTag = successTag;
      this.invalidTag = invalidTag;
    }

    @ProcessElement
    public void processElement(ProcessContext c) {
      String s = c.element();
      try {
        Integer i = Integer.parseInt(s);
        c.output(successTag, i.toString());
      } catch (Exception e) {
        LOG.error("cannot convert {} to an integer", s);
        c.output(invalidTag, s);
      }
    }
  }

  private static String createTopicPath(String projectId, String topicName) {
    return String.format("projects/%s/topics/%s", projectId, topicName);
  }

  public static void main(String[] args) {
    LOG.info("begin the application");

    DataflowPipelineOptions options = PipelineOptionsFactory.fromArgs(args).withValidation()
        .as(DataflowPipelineOptions.class);
    options.setStreaming(true);

    Pipeline pipeline = Pipeline.create(options);
    String projectId = options.getProject();

    final TupleTag<String> successTag = new TupleTag<String>() {};
    final TupleTag<String> invalidTag = new TupleTag<String>() {};

    PCollection<String> input =
        pipeline.apply("read",
            PubsubIO.readStrings().fromTopic(createTopicPath(projectId, "kh-test-in-1")));

    PCollectionTuple outputTuple =
        input.apply("parse", ParDo.of(new ParseToIntDoFn(successTag, invalidTag))
            .withOutputTags(successTag, TupleTagList.of(invalidTag)));

    // write successful data to PubSub
    PCollection<String> success = outputTuple.get(successTag);
    success
        .apply("success-write", PubsubIO.writeStrings()
            .to(createTopicPath(projectId, "kh-test-out-1")));

    // write invalid data to GCS
    PCollection<String> invalid = outputTuple.get(invalidTag);
    invalid
        .apply("windowing", Window.into(FixedWindows.of(Duration.standardMinutes(1))))
        .apply("invalid-write", TextIO.write()
            .to("gs://kh-test/dead-letter/")
            .withNumShards(3)
            .withWindowedWrites());

    pipeline.run();

    LOG.info("end the application");
  }


}

Dataflow Runnerでの実行した結果

2018年4月18日水曜日

español 18

¡Hola a todos!


今日はバールに行って注文する表現を勉強しました。
よく使いそうな単語には個別でメモをつけるようにしました。

Qué van a tomar?
注文は何にしましょうか?
  - qué = what
  - van (3rd person plural of "ir") = go
  - a = to
  - tomar = to take, to drink

Un café con leche, por favor.
ミルクコーヒーをください。

Para mí un té con limón y para mi amigo una limonada.
私はレモンティーで、友達にはレモネードをください。
  - para = for
  - con = with

Quiero un vino tinto (blanco).
赤(白)ワインが欲しいです。
 - quiero (1st person singular of "querer") = want, love

Otro zumo de naranja, por favor.
オレンジジュースをもう一つください。
  - otro = another

Otra Coca Cola, por favor.
コカコーラをもう一つください。
  - otra = otroの女性形

¿Se puede comer aqui?
ここで食べれますか?
  - puede (3rd person singular of "poder") = can

Nos (Me) trae la carta, por favor.
私たちに(私に)メニューを持ってきてください。

Quieren algo más?
他にも注文はありますか?
  - algo = something
  - más = more 

Nos trae más agua con (sin) gas, por favor.
炭酸の入っている(いない)水をもっとください。
  - con = with
  - sin = without

Nos trae la cuenta, por favor.
お会計お願いします。

Gracias y hasta pronto.

2018年4月17日火曜日

Apache Beam: 複数のパイプラインをあげる

 Apache Beamで構築するグラフはDAGじゃないといけないという縛りがありますが、DAGであれば連結なグラフじゃなくてもいいらしいです。(これに気づかなくて数ヶ月悩んでました。)
 
 実際にそのようなサンプルを書いて動作確認してみました。

package com.kenjih.multiple_pipe_line;

import org.apache.beam.runners.dataflow.options.DataflowPipelineOptions;
import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.io.gcp.pubsub.PubsubIO;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.apache.beam.sdk.transforms.DoFn;
import org.apache.beam.sdk.transforms.ParDo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {

  private static final Logger LOG = LoggerFactory.getLogger(Main.class);

  private static class AddPrefixDoFn extends DoFn<String, String> {

    private final String prefix;

    private AddPrefixDoFn(String prefix) {
      this.prefix = prefix;
    }

    @ProcessElement
    public void processElement(ProcessContext context) {
      String element = context.element();
      context.output(prefix + element);
    }
  }

  private String createTopicPath(String projectId, String topicName) {
    return String.format("projects/%s/topics/%s",
        projectId,
        topicName);
  }

  public void run(DataflowPipelineOptions options) {
    Pipeline pipeline = Pipeline.create(options);
    String projectId = options.getProject();

    // a data pipeline
    pipeline
        .apply("read-1",
            PubsubIO.readStrings().fromTopic(createTopicPath(projectId, "kh-test-in-1")))
        .apply("transform-1",
            ParDo.of(new AddPrefixDoFn("transform-1: ")))
        .apply("write-1",
            PubsubIO.writeStrings().to(createTopicPath(projectId, "kh-test-out-1")));

    // another data pipeline
    pipeline
        .apply("read-2",
            PubsubIO.readStrings().fromTopic(createTopicPath(projectId, "kh-test-in-2")))
        .apply("transform-2",
            ParDo.of(new AddPrefixDoFn("transform-2: ")))
        .apply("write-2",
            PubsubIO.writeStrings().to(createTopicPath(projectId, "kh-test-out-2")));

    // yet another data pipeline
    pipeline
        .apply("read-3",
            PubsubIO.readStrings().fromTopic(createTopicPath(projectId, "kh-test-in-3")))
        .apply("transform-3",
            ParDo.of(new AddPrefixDoFn("transform-3: ")))
        .apply("write-3",
            PubsubIO.writeStrings().to(createTopicPath(projectId, "kh-test-out-3")));

    pipeline.run();
  }

  public static void main(String[] args) {
    LOG.info("begin the application");

    DataflowPipelineOptions options = PipelineOptionsFactory.fromArgs(args).withValidation()
        .as(DataflowPipelineOptions.class);
    options.setStreaming(true);

    new Main().run(options);

    LOG.info("end the application");
  }

}

GCPのコンソール画面で見ると以下のようになっています。
BigQueryIOのDynamicDestinationsのようなものがPubSubIOにはなくて困っていましたが、上のように独立したパイプラインを作ることができるので、それを応用することでDynamicDestinations的なことができそうです(パイプライン生成時に静的に決めないといけないのでDynamicとは違いますが、複数の可変的な汎用パイプラインをうまく扱えそうという意味です)。

2018年4月13日金曜日

español 17

Hola a todos.
Me llamo Kenji. So de Japón.
Estoy aprendiendo español.


今日は場所に関する表現を勉強した。
これでスペイン語圏に旅行に行っても迷子になることはないはずだ。

Dónde está el museo?
博物館はどこですか?

¿Por favor, dónde está el baño?
すみません。トイレはどこですか?

Siga todo recto.
まっすぐ行ってください。

Doble a la derecha.
右に曲がってください。

Doble a la izquierda.
左に曲がってください。

¿Hay un restaurante por aquí?
近くにレストランはありますか?

Mi casa está cerca del mercado.
私の家は市場の近くにあります。

El hotel está lejos del aeropuerto.
ホテルは空港から遠いです。

El banco está frente a la cafetería.
銀行はカフェテリアの前にあります。

El bar está al lado de la farmacia.
バーは薬局の隣にあります。

Adiós y gracias.

2018年4月12日木曜日

español 16

¡Hola, buenas noches!

今日は、曜日、月、季節の単語を勉強した。

曜日
月曜日: lunes
火曜日: martes
水曜日: miércoles
木曜日: jueves
金曜日: viernes
土曜日: sábado
日曜日: domingo

Hoy es lunes. 今日は月曜日です。


1月: enero
2月: febrero
3月: marzo
4月: abril
5月: mayo
6月: junio
7月: julio
8月: agosto
9月: septiembre
10月: octubre
11月: noviembre
12月: diciembre

Mi cumpleaños es el doce de abril. 私の誕生日は4/12です。

季節
春: primavera
夏: verano
秋: otoño
冬: invierno

La primavera empieza en marzo. 春は3月から始まる。

2018年4月7日土曜日

GCP上に無料でプロキシーサーバを立てる

 GCPの無料枠が余っていたので、プロキシーサーバを立てて遊んでみた。

1. VMインスタンスを作る
- VMの名前はsquidとしておく
- ゾーンはus-east1-bにしておく

2. 作成したVMにログイン
- gcloud compute ssh squid --zone=us-east1-b

3. squidをインストール
- sudo yum install -y squid

4. 設定ファイルを変更
- sudo diff -u /etc/squid/squid.conf.default /etc/squid/squid.conf

--- /etc/squid/squid.conf.default
+++ /etc/squid/squid.conf
@@ -10,6 +10,7 @@
 acl localnet src fc00::/7       # RFC 4193 local private network range
 acl localnet src fe80::/10      # RFC 4291 link-local (directly plugged) machines
+acl myhome src xxx.xxx.xxx.xxx  # my home IP

 acl SSL_ports port 443
 acl Safe_ports port 80  # http
@@ -51,6 +52,7 @@
 # from where browsing should be allowed
 http_access allow localnet
 http_access allow localhost
+http_access allow myhome

 # And finally deny all other access to this proxy
 http_access deny all
@@ -71,3 +73,14 @@
 refresh_pattern ^gopher: 1440 0% 1440
 refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
 refresh_pattern .  0 20% 4320
+
+# prevent squid from being detected
+forwarded_for off
+request_header_access Referer deny all
+request_header_access X-Forwarded-For deny all
+request_header_access Via deny all
+request_header_access Cache-Control deny all
+
+# hostname
+visible_hostname squid
+

5. squidを起動
- sudo systemctl start squid

6. firewallの設定
- tcp:3128を開けておく

7. ブラウザ(chrome on Mac)の設定
- 設定 >詳細設定 >プロキシ設定を開く >Webプロキシ(HTTP)
- squidサーバのパブリックIP、ポート(3128)を入力

8. アクセス確認
- ブラウザから適当なサイトにアクセス
- squidのログ確認
- sudo tail -f /var/log/squid/access.log


español 15

¡Hola a todos!


今日はスペイン語の動詞の活用について勉強しました。
スペイン語の動詞は以下の3種類があります。

- ar動詞
- er動詞
- ir動詞

それぞれの動詞で活用形が異なります。

ar動詞
arで終わる動詞です。

hablar(話す)を例に活用形をみてみます。

hablo hablamos
hablas habláis
habla hablan

例文
Yo hablo español.
hablas español.
El habla español.
Nosotros hablamos español.
Vosotros habláis español.
Ellos hablan español.

er動詞
erで終わる動詞です。

comer(食べる)を例に活用形をみてみます。

como comemos
comes coméis
come comen

例文
Yo como.
Tú comes.
Él come.
Nosotros comemos.
Vosotros coméis.
Ellos comen.

ir動詞
irで終わる動詞です。

vivir(住む)を例に活用形をみてみます。

vivo vivimos
vives vivís
vive viven

例文
Yo vivo en Japón.
Tú vives en Japón.
Él vive en Japón.
Nosotros vivimos en Japón.
Vosotros vivís en Japón.
Ellos viven en Japón.

規則的な動詞の活用パターンはそれほど複雑ではないですね。

¡Muchas gracias y hasta luego!

español 14

¡Hola, buenos días!

スペイン語では英語のbe動詞に対応するものが2つあります。
今日はその使い分けについて勉強しました。

Ser
Serの活用形
soy somos
eres soís
es son

Serを使う場面
- 永続的なことについて話すとき
- 職業について話すとき
- 出生地/国籍について話すとき
- 特性について話すとき

Serの例文
- El es abocado. (彼は弁護士です)
- Yo soy de japon. (私は日本出身です)
- ¡Eres alto! (君は背が高いね!)

Estar
Estarの活用形
estoy estamos
estás estáis
está están

Estarを使う場面
- 一時的なことについて話すとき
- 場所について話すとき(※ 永続的な場所について話すときもEstarを使うことに注意)

Estarの例文
- Ella está triste. (彼女は悲しい)
- ¿Estás lista? (準備はいい?)
- Tokio está en Japón. (東京は日本の中にある)


2018年4月5日木曜日

español 13

¡Hola a todos!
Yo soy Kenji. 
Estoy aprendiendo español y me gusta aprender español.

今日は、9999までの数え方を勉強した。
1-99までの数え方を知っていれば、規則性があるので青字のところだけ覚えればOK。
1-99までの数え方はこちらを参照。

999までの数え方

100: ciento
200: doscientos
300: trescientos
400: cuatrocientos 
500: quinientos
600: seiscientos
700: setecientos
800: ochocientos
900: novecientos

十の位以下はそのままつなげて読むだけでOK。

101 ciento uno
125: ciento veinticinco
555: quinientos cincuenta y cinco

9999までの数え方

1000: mil
2000: dos mil
3000: tres mil
4000: cuatro mil
5000: cinco mil
6000: seis mil
7000: siete mil
8000: ocho mil
9000: nueve mil

百の位以下はそのままつなげて読むだけでOK。

9999: nueve mil novecientos noventa y nueve