Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions Examples/app/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// swift-tools-version: 6.0
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//

import PackageDescription

let package = Package(
name: "SparkConnectSwiftApp",
platforms: [
.macOS(.v15)
],
dependencies: [
.package(url: "https://github.com/apache/spark-connect-swift.git", branch: "v0.1.0")
],
targets: [
.executableTarget(
name: "SparkConnectSwiftApp",
dependencies: [.product(name: "SparkConnect", package: "spark-connect-swift")]
)
]
)
33 changes: 33 additions & 0 deletions Examples/app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# A Swift Application with Apache Spark Connect Swift Client

This is an example Swift application to show how to use Apache Spark Connect Swift Client library.

## How to run

Run this Swift application.

```
$ swift run
...
Connected to Apache Spark 4.0.0 Server
EXECUTE: DROP TABLE IF EXISTS t
EXECUTE: CREATE TABLE IF NOT EXISTS t(a INT) USING ORC
EXECUTE: INSERT INTO t VALUES (1), (2), (3)
SELECT * FROM t
+---+
| a |
+---+
| 2 |
| 1 |
| 3 |
+---+
+----+
| id |
+----+
| 2 |
| 6 |
| 0 |
| 8 |
| 4 |
+----+
```
41 changes: 41 additions & 0 deletions Examples/app/Sources/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//

import SparkConnect

let spark = try await SparkSession.builder.getOrCreate()
print("Connected to Apache Spark \(await spark.version) Server")

let statements = [
"DROP TABLE IF EXISTS t",
"CREATE TABLE IF NOT EXISTS t(a INT) USING ORC",
"INSERT INTO t VALUES (1), (2), (3)",
]

for s in statements {
print("EXECUTE: \(s)")
_ = try await spark.sql(s).count()
}
print("SELECT * FROM t")
try await spark.sql("SELECT * FROM t").cache().show()

try await spark.range(10).filter("id % 2 == 0").write.mode("overwrite").orc("/tmp/orc")
try await spark.read.orc("/tmp/orc").show()

await spark.stop()
52 changes: 52 additions & 0 deletions Examples/web/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// swift-tools-version:6.0
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
import PackageDescription

let package = Package(
name: "SparkConnectSwiftWebapp",
platforms: [
.macOS(.v15)
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.110.1"),
// 🔵 Non-blocking, event-driven networking for Swift. Used for custom executors
.package(url: "https://github.com/apple/swift-nio.git", from: "2.65.0"),
.package(url: "https://github.com/apache/spark-connect-swift.git", branch: "v0.1.0"),
],
targets: [
.executableTarget(
name: "SparkConnectSwiftWebapp",
dependencies: [
.product(name: "Vapor", package: "vapor"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "SparkConnect", package: "spark-connect-swift"),
],
swiftSettings: swiftSettings
)
]
)

var swiftSettings: [SwiftSetting] {
[
.enableUpcomingFeature("ExistentialAny")
]
}
89 changes: 89 additions & 0 deletions Examples/web/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# A Swift Application with Apache Spark Connect Swift Client

This project is designed to illustrate a Swift-based HTTP WebServer with Apache Spark Connect.

- https://swiftpackageindex.com/apache/spark-connect-swift
- https://swiftpackageindex.com/vapor/vapor

## Create a Swift project

```
brew install vapor
vapor new spark-connect-swift-web -n
```

## Use `Apache Spark Connect Swift Client` package.

```
$ git diff HEAD
diff --git a/Package.swift b/Package.swift
index 477bcbd..3e7bb06 100644
--- a/Package.swift
+++ b/Package.swift
@@ -4,13 +4,14 @@ import PackageDescription
let package = Package(
name: "SparkConnectSwiftWebapp",
platforms: [
- .macOS(.v13)
+ .macOS(.v15)
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.110.1"),
// 🔵 Non-blocking, event-driven networking for Swift. Used for custom executors
.package(url: "https://github.com/apple/swift-nio.git", from: "2.65.0"),
+ .package(url: "https://github.com/apache/spark-connect-swift.git", branch: "main"),
],
targets: [
.executableTarget(
@@ -19,6 +20,7 @@ let package = Package(
.product(name: "Vapor", package: "vapor"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOPosix", package: "swift-nio"),
+ .product(name: "SparkConnect", package: "spark-connect-swift"),
],
swiftSettings: swiftSettings
),
diff --git a/Sources/SparkConnectSwiftWebapp/routes.swift b/Sources/SparkConnectSwiftWebapp/routes.swift
index 2edcc8f..22313c8 100644
--- a/Sources/SparkConnectSwiftWebapp/routes.swift
+++ b/Sources/SparkConnectSwiftWebapp/routes.swift
@@ -1,4 +1,5 @@
import Vapor
+import SparkConnect

func routes(_ app: Application) throws {
app.get { req async in
@@ -6,6 +7,15 @@ func routes(_ app: Application) throws {
}

app.get("hello") { req async -> String in
- "Hello, world!"
+ return await Task {
+ do {
+ let spark = try await SparkSession.builder.getOrCreate()
+ let response = "Hi, this is powered by the Apache Spark \(await spark.version)."
+ await spark.stop()
+ return response
+ } catch {
+ return "Fail to connect: \(error)"
+ }
+ }.value
}
}
```

## Run this Swift application.

```
$ swift run
```

## Connect to the Swift Web Server to talk with `Apache Spark`.

```
$ curl http://127.0.0.1:8080/
Welcome to the Swift world. Say hello!%
$ curl http://127.0.0.1:8080/hello
Hi, this is powered by the Apache Spark 4.0.0.%
```
29 changes: 29 additions & 0 deletions Examples/web/Sources/SparkConnectSwiftWeb/configure.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//

import Vapor

// configures your application
public func configure(_ app: Application) async throws {
// uncomment to serve files from /Public folder
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))

// register routes
try routes(app)
}
50 changes: 50 additions & 0 deletions Examples/web/Sources/SparkConnectSwiftWeb/entrypoint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//

import Logging
import NIOCore
import NIOPosix
import Vapor

@main
enum Entrypoint {
static func main() async throws {
var env = try Environment.detect()
try LoggingSystem.bootstrap(from: &env)

let app = try await Application.make(env)

// This attempts to install NIO as the Swift Concurrency global executor.
// You can enable it if you'd like to reduce the amount of context switching between NIO and Swift Concurrency.
// Note: this has caused issues with some libraries that use `.wait()` and cleanly shutting down.
// If enabled, you should be careful about calling async functions before this point as it can cause assertion failures.
// let executorTakeoverSuccess = NIOSingletons.unsafeTryInstallSingletonPosixEventLoopGroupAsConcurrencyGlobalExecutor()
// app.logger.debug("Tried to install SwiftNIO's EventLoopGroup as Swift's global concurrency executor", metadata: ["success": .stringConvertible(executorTakeoverSuccess)])

do {
try await configure(app)
try await app.execute()
} catch {
app.logger.report(error: error)
try? await app.asyncShutdown()
throw error
}
try await app.asyncShutdown()
}
}
40 changes: 40 additions & 0 deletions Examples/web/Sources/SparkConnectSwiftWeb/routes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//

import SparkConnect
import Vapor

func routes(_ app: Application) throws {
app.get { req async in
"Welcome to the Swift world. Say hello!"
}

app.get("hello") { req async -> String in
return await Task {
do {
let spark = try await SparkSession.builder.getOrCreate()
let response = "Hi, this is powered by the Apache Spark \(await spark.version)."
await spark.stop()
return response
} catch {
return "Fail to connect: \(error)"
}
}.value
}
}
5 changes: 1 addition & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,7 @@ SELECT * FROM t
+----+
```

You can find this command line example and additional `Swift Web Server` example in the following repositories.

- <https://github.com/dongjoon-hyun/spark-connect-swift-app>
- <https://github.com/dongjoon-hyun/spark-connect-swift-web>
You can find more complete examples including Web Server application in the `Examples` directory.

## How to use `Spark SQL REPL` via `Spark Connect for Swift`

Expand Down
Loading