Skip to content

MS_DotNetForApacheSparkTutorial

nishi_74322014 edited this page Sep 1, 2026 · 1 revision

.NET for Apache Sparkチュートリアル

概要

チュートリアル

以下のチュートリアルを実施してみた。

Get started in 10 minutes
.NET for Apache Spark 101-α
.NET for Apache Spark ガイド-α
≠ github.com...README.md#get-started

前提

初回

  • OS
    Windows

  • ランタイム

    • .NET:netcoreapp3.1
    • Java:jdk-8u201-windows-x64.exe
  • ミドルウェア

    • Apache Spark

      • ver:2.4.1

      • パス:

        C:\prog\dev\spark\spark-2.4.1-bin-hadoop2.7
        
    • .NET for Apache Spark

      • ver:1.0.0

      • パス:

        C:\prog\dev\spark\Microsoft.Spark.Worker-1.0.0
        
    • winutils.exe
      Windows で利用できる Hadoop バイナリ

      • ver:.../hadoop-2.7.1/bin/winutils.exe

      • パス:

        C:\prog\dev\spark\spark-2.4.1-bin-hadoop2.7\bin
        
  • その他

    • 7-Zip(インストール済み)

Ver-UP 1

  • Apache Spark

    • ver:3.0.1

      • パス:

        C:\prog\dev\spark\spark-3.0.1-bin-hadoop2.7
        
    • .NET for Apache Spark

      • ver:2.0.0

      • パス:

        C:\prog\dev\spark\Microsoft.Spark.Worker-2.0.0
        
  • 実行時、spark-submit の引数に指定する、
    <application-jar> のバージョンを上げておく。

    microsoft-spark-2-4_2.11-1.0.0.jar
    → microsoft-spark-3-0_2.12-2.0.0.jar
    

補足(.NET for Apache Spark は終了): 本プロジェクトは
2024 年 12 月にサポート終了が告知され、アーカイブされた。
.NET から Spark を扱う後継としては、

  • Microsoft Fabric の Spark ランタイム(言語は主に Python / Scala)
  • Azure Databricks + Python / Scala

が案内されている。
本ページは当時の手順の記録として読むこと。

詳細

開発

Get started in 10 minutes の実施

  • 概要

    • デモを見た限り、入力は TXT ファイルで単語を数える。
    • メソッド構文の Spark SQLで単語を数え集計して表示
      (いきなりハードル高い)。
  • CMD コピペ用

    • Apache Spark

      • HOME の指定

        setx /M HADOOP_HOME C:\prog\dev\spark\spark-2.4.1-bin-hadoop2.7\
        setx /M SPARK_HOME C:\prog\dev\spark\spark-2.4.1-bin-hadoop2.7\
        setx /M PATH "%PATH%;%HADOOP_HOME%;%SPARK_HOME%bin"
        

        注意\bin とすると、spark-3.0.1-bin-hadoop2.7\\bin となって動かない。

      • 動作確認

        >spark-submit --version
        Welcome to
        
             / __/__  ___ _____/ /__
            _\ \/ _ \/ _ `/ __/  '_/
           /___/ .__/\_,_/_/ /_/\_\   version 2.4.1
              /_/
        
        Using Scala version 2.11.12, Java HotSpot(TM) 64-Bit Server VM, 1.8.0_201
        Branch
        Compiled by user  on 2019-03-26T22:44:44Z
        Revision
        Url
        Type --help for more information.
        
    • .NET for Apache Spark

      • パス設定

        setx /M DOTNET_WORKER_DIR C:\prog\dev\spark\Microsoft.Spark.Worker-1.0.0
        
      • 動作確認
        以下のアプリをビルドして動作させる。

  • アプリ

    • 物体
      https://github.com/OpenTouryoProject/SampleProgram/tree/master/Azure/DotNet4ApacheSpark/MySparkApp

    • 実行

      \MySparkApp\bin\Debug\netcoreapp3.1>spark-submit ^
      --class org.apache.spark.deploy.dotnet.DotnetRunner ^
      --master local ^
      microsoft-spark-2-4_2.11-1.0.0.jar ^
      dotnet MySparkApp.dll input.txt
      ...
      20/11/19 12:39:29 INFO CodeGenerator: Code generated in 10.4659 ms
      +------+-----+
      |  word|count|
      +------+-----+
      |  .NET|    3|
      |Apache|    2|
      |   app|    2|
      |  This|    2|
      | Spark|    2|
      | World|    1|
      |counts|    1|
      |   for|    1|
      | words|    1|
      |  with|    1|
      | Hello|    1|
      |  uses|    1|
      +------+-----+
      
      20/11/19 12:39:29 INFO SparkUI: Stopped Spark web UI at http://nishi.mshome.net:4040
      ...
      
    • SQL の説明(DNET_SparkSQL.md

バッチ処理

  • 概要

  • アプリ

    • 物体
      https://github.com/OpenTouryoProject/SampleProgram/tree/master/Azure/DotNet4ApacheSpark/mySparkBatchApp

    • 実行

      >spark-submit ^
      --class org.apache.spark.deploy.dotnet.DotnetRunner ^
      --master local ^
      microsoft-spark-2-4_2.11-1.0.0.jar ^
      dotnet mySparkBatchApp.dll projects_smaller.csv
      ...
      +----+--------------------+--------+--------------------+--------------------+--------+---------------+-----------+-------+-------------------+
      |  id|                 url|owner_id|                name|          descriptor|language|     created_at|forked_from|deleted|         updated_at|
      +----+--------------------+--------+--------------------+--------------------+--------+---------------+-----------+-------+-------------------+
      |   1|https://api.githu...|       1|           ruote-kit|RESTful wrapper f...|    Ruby|12/8/2009 10:17|          2|      0|     11/5/2015 1:15|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |   4|https://api.githu...|      24|             basemap|                null|     C++|6/14/2012 14:14|          3|      1|0000-00-00 00:00:00|
      |   5|https://api.githu...|      28|           cocos2d-x|Port of cocos2d-i...|     C++|3/12/2012 16:48|          6|      0|   10/22/2015 17:36|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |   7|https://api.githu...|      42|           cocos2d-x|Port of cocos2d-i...|       C|4/23/2012 10:20|          6|      0|    11/1/2015 17:32|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |   9|https://api.githu...|      66|       rake-compiler|Provide a standar...|    Ruby| 8/1/2012 18:33|   14556189|      0|    11/3/2015 19:30|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |  12|https://api.githu...|      70|heroku-buildpack-...|                null|   Shell| 8/2/2012 12:50|         11|      0|     11/2/2015 7:34|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      |null|                null|    null|                null|                null|    null|           null|       null|   null|               null|
      +----+--------------------+--------+--------------------+--------------------+--------+---------------+-----------+-------+-------------------+
      only showing top 20 rows
      
      +--------------------+--------------------+-----------+----------------+-----------+-------+-------------------+
      |                name|          descriptor|   language|      created_at|forked_from|deleted|         updated_at|
      +--------------------+--------------------+-----------+----------------+-----------+-------+-------------------+
      |           ruote-kit|RESTful wrapper f...|       Ruby| 12/8/2009 10:17|          2|      0|     11/5/2015 1:15|
      |           cocos2d-x|Port of cocos2d-i...|        C++| 3/12/2012 16:48|          6|      0|   10/22/2015 17:36|
      |           cocos2d-x|Port of cocos2d-i...|          C| 4/23/2012 10:20|          6|      0|    11/1/2015 17:32|
      |       rake-compiler|Provide a standar...|       Ruby|  8/1/2012 18:33|   14556189|      0|    11/3/2015 19:30|
      |    cobertura-plugin|Jenkins cobertura...|       Java| 7/26/2012 18:46|     193522|      0|    11/1/2015 19:55|
      |     scala-vs-erlang|A performance tes...|     Erlang|12/25/2011 13:51|    1262879|      0|    10/22/2015 4:50|
      |              opencv|OpenCV GitHub Mirror|        C++|  8/2/2012 12:50|         29|      0|    10/26/2015 6:44|
      | redmine_git_hosting|A ChiliProject/Re...|       Ruby| 7/30/2012 12:53|         42|      0|   10/28/2015 10:54|
      | redmine_git_hosting|A ChiliProject/Re...|       Ruby|10/26/2011 23:17|     207450|      0|   10/27/2015 22:43|
      |          OpenCV-iOS|This project is a...|Objective-C|  8/2/2012 12:55|         39|      1|0000-00-00 00:00:00|
      |           browserid|A secure, distrib...| JavaScript| 6/30/2012 22:35|       1589|      0|    10/10/2015 0:34|
      |      protobuf-cmake|CMake build suppo...|         \N|  8/2/2012 14:35|         61|      0|    10/31/2015 1:22|
      |                loso|Chinese segmentat...|     Python|  8/2/2012 12:57|         67|      1|0000-00-00 00:00:00|
      |                yui3| YUI 3.x Source Tree| JavaScript| 7/13/2012 14:48|         55|      1|0000-00-00 00:00:00|
      |         doctag_java|Java library for ...|       Java|  8/2/2012 12:57|         70|      1|0000-00-00 00:00:00|
      |willdurand.github...|        My new blog!| JavaScript|  8/2/2012 12:06|         84|      0|     11/4/2015 9:15|
      |            manaserv|A flexible 2D MMO...|        C++|  8/1/2011 17:05|         90|      0|    10/10/2015 4:42|
      |            manaserv|A flexible 2D MMO...|        C++| 3/24/2011 17:38|         90|      0|   10/16/2015 18:29|
      |               libuv|platform layer fo...|          C|  8/2/2012 12:57|         74|      0|    10/31/2015 8:21|
      |         cucumber-js|Pure Javascript C...| JavaScript| 5/28/2012 15:47|      10457|      1|0000-00-00 00:00:00|
      +--------------------+--------------------+-----------+----------------+-----------+-------+-------------------+
      only showing top 20 rows
      
      +------------+------------------+
      |    language|  avg(forked_from)|
      +------------+------------------+
      |      Racket|       1.2550711E7|
      |    Makefile|         3611689.0|
      |ActionScript|        2474502.75|
      |      Erlang|         1262879.0|
      |          C#|        914767.625|
      |         PHP| 617219.4333333333|
      |         C++| 448911.1538461539|
      |        Ruby|349311.23214285716|
      |        Perl|          298380.0|
      |      Puppet|          253680.5|
      |  JavaScript| 240718.6494845361|
      |        Java|      149923.71875|
      |      Python| 76043.26190476191|
      |       Shell|           13276.6|
      | Objective-C|2281.4761904761904|
      |          \N| 1995.095238095238|
      |           C|1576.4705882352941|
      |       Scala|            1358.5|
      |      Groovy|            1049.0|
      |        HaXe|             829.0|
      +------------+------------------+
      only showing top 20 rows
      
      [2021-06-25T05:26:32.6714551Z] [NISHI] [Debug] [ConfigurationService] Using the environment variable to construct .NET worker path:
      ...\spark\Microsoft.Spark.Worker-1.0.0\Microsoft.Spark.Worker.exe.
      +--------------------+--------------------+-----------+----------------+-----------+-------+-------------------+----------+
      |                name|          descriptor|   language|      created_at|forked_from|deleted|         updated_at|datebefore|
      +--------------------+--------------------+-----------+----------------+-----------+-------+-------------------+----------+
      |           ruote-kit|RESTful wrapper f...|       Ruby| 12/8/2009 10:17|          2|      0|     11/5/2015 1:15|      true|
      |           cocos2d-x|Port of cocos2d-i...|        C++| 3/12/2012 16:48|          6|      0|   10/22/2015 17:36|      true|
      |           cocos2d-x|Port of cocos2d-i...|          C| 4/23/2012 10:20|          6|      0|    11/1/2015 17:32|      true|
      |       rake-compiler|Provide a standar...|       Ruby|  8/1/2012 18:33|   14556189|      0|    11/3/2015 19:30|      true|
      |    cobertura-plugin|Jenkins cobertura...|       Java| 7/26/2012 18:46|     193522|      0|    11/1/2015 19:55|      true|
      |     scala-vs-erlang|A performance tes...|     Erlang|12/25/2011 13:51|    1262879|      0|    10/22/2015 4:50|      true|
      |              opencv|OpenCV GitHub Mirror|        C++|  8/2/2012 12:50|         29|      0|    10/26/2015 6:44|      true|
      | redmine_git_hosting|A ChiliProject/Re...|       Ruby| 7/30/2012 12:53|         42|      0|   10/28/2015 10:54|      true|
      | redmine_git_hosting|A ChiliProject/Re...|       Ruby|10/26/2011 23:17|     207450|      0|   10/27/2015 22:43|      true|
      |          OpenCV-iOS|This project is a...|Objective-C|  8/2/2012 12:55|         39|      1|0000-00-00 00:00:00|     false|
      |           browserid|A secure, distrib...| JavaScript| 6/30/2012 22:35|       1589|      0|    10/10/2015 0:34|     false|
      |      protobuf-cmake|CMake build suppo...|         \N|  8/2/2012 14:35|         61|      0|    10/31/2015 1:22|      true|
      |                loso|Chinese segmentat...|     Python|  8/2/2012 12:57|         67|      1|0000-00-00 00:00:00|     false|
      |                yui3| YUI 3.x Source Tree| JavaScript| 7/13/2012 14:48|         55|      1|0000-00-00 00:00:00|     false|
      |         doctag_java|Java library for ...|       Java|  8/2/2012 12:57|         70|      1|0000-00-00 00:00:00|     false|
      |willdurand.github...|        My new blog!| JavaScript|  8/2/2012 12:06|         84|      0|     11/4/2015 9:15|      true|
      |            manaserv|A flexible 2D MMO...|        C++|  8/1/2011 17:05|         90|      0|    10/10/2015 4:42|     false|
      |            manaserv|A flexible 2D MMO...|        C++| 3/24/2011 17:38|         90|      0|   10/16/2015 18:29|     false|
      |               libuv|platform layer fo...|          C|  8/2/2012 12:57|         74|      0|    10/31/2015 8:21|      true|
      |         cucumber-js|Pure Javascript C...| JavaScript| 5/28/2012 15:47|      10457|      1|0000-00-00 00:00:00|     false|
      +--------------------+--------------------+-----------+----------------+-----------+-------+-------------------+----------+
      only showing top 20 rows
      ...
      
    • SQL の説明(DNET_SparkSQL.md

補足(出力に null の行が並ぶ理由): 1 つ目の表に null だらけの行が
混ざっているのは、CSV の説明文フィールドに改行やカンマが含まれており、
1 レコードが複数行に分かれて読み込まれているためである。
.Option("multiLine", true).Option("escape", "\"") を付けると解消する。
2 つ目以降の表で消えているのは、集計時に落ちているだけで、
データ自体は壊れたままである点に注意する。

構造化ストリーミング

  • 概要
    (別名、マイクロ・バッチ)

    • デモを見た限り、入力は Netcat からのテキスト行で、変換処理を行う。

    • UDFメソッド構文の Spark SQLから利用し、
      エンリッチメントする。

    • なお、ストリーミング処理では、ループを書くのではなく、StreamingQuery を使用する模様。

      • これは、Spark SQL エンジンに基づいた、Structured Streaming による。
      • StreamingQueryStart でアプリケーションが開始する(読込 → 変換 → 書込の逐次実行)。
      • StreamingQueryAwaitTermination でアプリケーションが外部から停止されるまで実行。
  • アプリ

    • 物体
      https://github.com/OpenTouryoProject/SampleProgram/tree/master/Azure/DotNet4ApacheSpark/mySparkStreamingApp

    • 実行

      • nc コマンド(DNET_NcCommand.md)でリスナーを作成(WSLを使用)

        $ nc -lk 9999
        abcdefg
        
      • spark-submit でデプロイ

        >spark-submit ^
        --class org.apache.spark.deploy.dotnet.DotnetRunner ^
        --master local ^
        microsoft-spark-2-4_2.11-1.0.0.jar ^
        dotnet mySparkStreamingApp.dll localhost 9999
        ...
        -------------------------------------------
        Batch: x
        -------------------------------------------
        +---------+
        |      col|
        +---------+
        |  abcdefg|
        |abcdefg 7|
        +---------+
        
    • SQL の説明(DNET_SparkSQL.md

  • 参考

ML.NETでの感情分析

ココから以降、Microsoft.Spark のバージョンを 2.0.0 に上げている。

  • 概要

    • デモを見た限り、入力は yelptest.csv で、感情分析を行う。
    • なお、学習は、yelptrain.csv を使用して行う。
    • 学習の結果、XXXXML.Model プロジェクトが生成されるので、参照を追加する。
    • ML 処理を呼出すUDF
      クエリ構文の Spark SQLから利用する。
  • 学習

    • シナリオ タイルは「感情分析」ではなく「テキストの分類」。

    • また、「トレーニングする時間」が短いと、
      「トレーニング期間が終了しましたが、トレーニングされたモデルがありません。」
      なるエラーが発生することがある(時間を長くすると解決する)。

      GPU Service not found. Falling back to CPU AutoML Service.
      |     Trainer                              MicroAccuracy  MacroAccuracy  Duration #Iteration                     |
      |1    AveragedPerceptronOva                       0.7885         0.7924       5.0          1                     |
      |2    SdcaMaximumEntropyMulti                     0.7966         0.7675       7.2          2                     |
      |3    LightGbmMulti                               0.7442         0.7365      11.4          3                     |
      |4    SymbolicSgdLogisticRegressionOva            0.7115         0.7144       3.4          4                     |
      
      ===============================================Experiment Results=================================================
      ------------------------------------------------------------------------------------------------------------------
      |                                                     Summary                                                    |
      ------------------------------------------------------------------------------------------------------------------
      |ML Task: multiclass-classification                                                                              |
      |Dataset: ...\MLSparkModel\yelptrain.csv                                                                       |
      |Label : Sentiment                                                                                               |
      |Total experiment time : 27.0050593 Secs                                                                         |
      |Total number of models explored: 4                                                                              |
      ------------------------------------------------------------------------------------------------------------------
      
      |                                              Top 4 models explored                                             |
      ------------------------------------------------------------------------------------------------------------------
      |     Trainer                              MicroAccuracy  MacroAccuracy  Duration #Iteration                     |
      |1    SdcaMaximumEntropyMulti                     0.7966         0.7675       7.2          1                     |
      |2    AveragedPerceptronOva                       0.7885         0.7924       5.0          2                     |
      |3    LightGbmMulti                               0.7442         0.7365      11.4          3                     |
      |4    SymbolicSgdLogisticRegressionOva            0.7115         0.7144       3.4          4                     |
      ------------------------------------------------------------------------------------------------------------------
      
      Code Generated
      
  • アプリ

    • 物体
      https://github.com/OpenTouryoProject/SampleProgram/tree/master/Azure/DotNet4ApacheSpark/MLSparkModel

    • 実行

      >spark-submit ^
      --class org.apache.spark.deploy.dotnet.DotnetRunner ^
      --master local ^
      microsoft-spark-3-0_2.12-2.0.0.jar ^
      dotnet MLSparkModelML.ConsoleApp.dll yelptest.csv MLModel.zip
      ...
      +--------------------+---------+
      |          ReviewText|Sentiment|
      +--------------------+---------+
      |Waitress was swee...|        1|
      |I also had to tas...|        1|
      |I'd rather eat ai...|        0|
      |Cant say enough g...|        1|
      |The ambiance was ...|        1|
      |The waitress and ...|        1|
      |I would not recom...|        0|
      |Overall I wasn't ...|        0|
      |My gyro was basic...|        0|
      |   Terrible service!|        0|
      |Thoroughly disapp...|        0|
      |I don't each much...|        1|
      |Give it a try, yo...|        1|
      |By far the BEST c...|        1|
      |Reasonably priced...|        1|
      |Everything was pe...|        1|
      |The food is very ...|        1|
      |it was a drive to...|        0|
      |At first glance i...|        1|
      |Anyway, I do not ...|        0|
      +--------------------+---------+
      only showing top 20 rows
      

    色々と試したが、動かなかった。

    • UDF 仕込んで show するとエラーになったり、
    • Could not load type 'Microsoft.ML.Data.DataViewTypeAttribute' と言うエラーが出たり。
    • SQL の説明(DNET_SparkSQL.md

移行メモ(脱字): 「トレーニする時間」→「トレーニングする時間」を修正した。

補足(Could not load type の原因): 上記のエラーは、
Microsoft.MLMicrosoft.Spark が要求する依存アセンブリの
バージョンが噛み合っていない
ときに出る典型的な症状である。
Spark のワーカーは自前でアセンブリを解決するため、
spark-submit に渡す発行フォルダに
ML.NET 側の依存 DLL が正しいバージョンで揃っている必要がある。
dotnet publish の出力をそのまま配置し、
Microsoft.ML.* のバージョンを揃えるのが対処になる。

ウィンドウ関数の利用

デプロイ

リンク先を読むと解るが差は僅か。

Azure HDInsight へのデプロイ

Azure HDInsight

Azure Databricks へのデプロイ

Azure Databricks

分散環境での入出力

分散環境

  • 基本的には、マネージド・サービスのクラスタを利用する。
  • 分散処理は、Spark SQL により、隠蔽される。(DNET_ApacheSpark.md

入出力

遅延評価で実現されること。

自動的な分散。

分散環境を参照。

ストリーミング。

構造化ストリーミングを参照。

ループで書かない。

補足(遅延評価が効く理由): Spark の変換処理は
その場では実行されず、DAG(処理の設計図)として積まれるだけで、
Show()Start() のようなアクションが呼ばれて初めて実行される。
このため Spark は全体を見渡して
「どこを分散するか」「どの順に評価するか」を決められる。
本節が「自動的な分散」と「ストリーミング」を
遅延評価の帰結として挙げているのはこの意味である。

参考

msdn.com

Channel 9 > .NET for Apache Spark 101

.NET for Apache Spark ガイドのチュートリアル部」を
動画化してある。

補足(Channel 9 は終了): Channel 9 は 2022 年に終了し、
コンテンツは Microsoft Learn および YouTube に移された。
上記の各リンクは現在は繋がらないため、
併記されている YouTube のプレイリストを参照すること。

microsoft.com

Get started in 10 minutes

https://dotnet.microsoft.com/learn/data/spark-tutorial/intro

Microsoft Docs > .NET for Apache Spark ガイド

.NET for Apache Spark

本 Wiki 内


Tags: クラウド, Azure, .NET開発, .NET Core, .NET Standard

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally