LoginSignup
1
1

More than 3 years have passed since last update.

PrestoのUDFをscalaで開発する

Last updated at Posted at 2018-09-16

Overview

この記事の対象読者はPrestoでUDFを作ったことがある人です。

PrestoとはFacebookが開発したオープンソースの分散クエリ処理エンジンです。

詳細はこちらを参照。

Prestoはプラグインで拡張することが可能でUDFもプラグインとして導入することが出来ます。

これまでいくつかのUDFをJavaで作って来ましたが、最近何年かぶりにscalaに興味が出てきたのでUDFをscalaで書いてみました。

Sample Code

今回のコードはここにあります。

Update pom.xml

まず、pom.xmlを編集してscalaをコンパイル出来る環境を整えます。

今回は比較のためにJavaでも同じようなUDFを作成するのでJava/Scala混生のmavenプロジェクトのための設定を導入します。

scala-maven-plugin のドキュメントにJava/Scala混在プロジェクトでのビルド方法が書かれているのでそれを参考にします。

次の3つのコードをpom.xmlに追加します。

   <properties>
     <scala.major.version>2.12</scala.major.version>
     <scala.version>${scala.major.version}.0</scala.version>
     <scala.maven.plugin.version>3.4.2</scala.maven.plugin.version>
   </properties>
  <dependencies>
    <!--scala-->
    <dependency>
      <groupId>org.scala-lang</groupId>
      <artifactId>scala-compiler</artifactId>
      <version>${scala.version}</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>

      <plugin>
        <groupId>net.alchim31.maven</groupId>
        <artifactId>scala-maven-plugin</artifactId>
        <version>${scala.maven.plugin.version}</version>
        <executions>
          <execution>
            <id>scala-compile-first</id>
            <phase>process-resources</phase>
            <goals>
              <goal>add-source</goal>
              <goal>compile</goal>
            </goals>
          </execution>
          <execution>
            <id>scala-test-compile</id>
            <phase>process-test-resources</phase>
            <goals>
              <goal>testCompile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

    </plugins>
   </build>    

scala UDFの開発

次にscalaでハローワールドな関数を書きます。

object HelloWorldScalaUDF {
  @Description("Hello World(UDF Practice)")
  @ScalarFunction("hello_worlds")
  @SqlType(StandardTypes.VARCHAR)
  def helloworld(@SqlNullable @SqlType(StandardTypes.VARCHAR) name: Slice): Slice =
    if (name == null || name.toStringUtf8.isEmpty) {
      utf8Slice("Hello World from scala")
    } 
    else {
      utf8Slice(String.format("Hello %s from scala", name.toStringUtf8))
    }
}

ほぼ同じコードをJava版で書くとこちらです。簡単なコードなので関数のコードだけを比べればそれほど大きな差はありません。
return, ()の数が減ったぐらいの差しかありません。

public class HelloWorldUDF
{
    private HelloWorldUDF()
    {
    }

    @Description("Hello World(UDF Practice)")
    @ScalarFunction("hello_world")
    @SqlType(StandardTypes.VARCHAR)
    public static Slice helloworld(@SqlNullable @SqlType(StandardTypes.VARCHAR) Slice name)
    {
        if (name == null || name.toStringUtf8().isEmpty()) {
            return utf8Slice("Hello World");
        }
        else {
            return utf8Slice(String.format("Hello %s", name.toStringUtf8()));
        }
    }
}

最後に UDFPlugin#getFunctions にscalaのクラスを登録して完了です。

public class UdfPlugin implements Plugin {
    @Override
    public Set<Class<?>> getFunctions()
    {
        return ImmutableSet.<Class<?>>builder()
                .add(HelloWorldScalaUDF.class)
                .build();
    }
}

ビルド

あとはこれをmavenでビルドしてjarを作るだけです。

$ ./mvnw clean compile package

scala -> Javaの順番にコンパイルしてあげないとUdfPluginでコンパイルが失敗するのですがscala-maven-pluginがその辺を面倒を見てくれています。

[INFO] --- scala-maven-plugin:3.4.2:add-source (scala-compile-first) @ presto-sample-udf ---
[INFO] Add Source directory: /Users/callistoiv/works/IdeaProjects/prestodb/ecosystem/presto-sample-udf/src/main/scala
[INFO] Add Test Source directory: /Users/callistoiv/works/IdeaProjects/prestodb/ecosystem/presto-sample-udf/src/test/scala
[INFO]
[INFO] --- scala-maven-plugin:3.4.2:compile (scala-compile-first) @ presto-sample-udf ---
[INFO] /Users/callistoiv/works/IdeaProjects/prestodb/ecosystem/presto-sample-udf/src/main/java:-1: info: compiling
[INFO] /Users/callistoiv/works/IdeaProjects/prestodb/ecosystem/presto-sample-udf/src/main/scala:-1: info: compiling
[INFO] Compiling 4 source files to /Users/callistoiv/works/IdeaProjects/prestodb/ecosystem/presto-sample-udf/target/classes at 1537073450711
[INFO] prepare-compile in 0 s
[INFO] compile in 3 s

まとめ

scalaでPresto UDFを作る環境構築の方法を紹介しました。
今回のサンプルコードだとscala化のメリットがあるとは言えませんが業務で作るようなif-else文満載のコードをパターンマッチで置き換えることで
コードの可読性があがるのではないかという可能性を感じました。

また、ユニットテストのscala化も検討したが自分が書くpresto UDFのユニットテストがそんなに複雑なものではなくscala化のメリットが得られそうになかったので見送りました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1