Browse Source

working first method

Antoine Dorian 2 years ago
parent
commit
2cb59bf3d1

+ 21
- 0
pom.xml View File

@@ -122,6 +122,27 @@
122 122
             <artifactId>spring-boot-starter-test</artifactId>
123 123
             <scope>test</scope>
124 124
         </dependency>
125
+        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-scala -->
126
+        <dependency>
127
+            <groupId>com.fasterxml.jackson.module</groupId>
128
+            <artifactId>jackson-module-scala_2.13</artifactId>
129
+            <version>2.14.0-rc1</version>
130
+        </dependency>
131
+        <!-- https://mvnrepository.com/artifact/org.json4s/json4s-native -->
132
+        <dependency>
133
+            <groupId>org.json4s</groupId>
134
+            <artifactId>json4s-native_2.13</artifactId>
135
+            <version>4.1.0-M1</version>
136
+        </dependency>
137
+        <!-- https://mvnrepository.com/artifact/org.json4s/json4s -->
138
+        <dependency>
139
+            <groupId>org.json4s</groupId>
140
+            <artifactId>json4s_2.11</artifactId>
141
+            <version>3.2.11</version>
142
+        </dependency>
143
+
125 144
     </dependencies>
126 145
 
146
+
147
+
127 148
 </project>

+ 41
- 0
src/main/java/com/mediahub/controller/MovieController.java View File

@@ -0,0 +1,41 @@
1
+package com.mediahub.controller;
2
+
3
+import com.mediahub.JsonCustomMapping;
4
+import com.mediahub.MovieService;
5
+import com.mediahub.MovieServiceTrait;
6
+import org.springframework.beans.factory.annotation.Autowired;
7
+import org.springframework.http.HttpStatus;
8
+import org.springframework.http.ResponseEntity;
9
+import org.springframework.web.bind.annotation.GetMapping;
10
+import org.springframework.web.bind.annotation.RequestMapping;
11
+import org.springframework.web.bind.annotation.RequestParam;
12
+import org.springframework.web.bind.annotation.RestController;
13
+
14
+
15
+@RestController
16
+@RequestMapping("/api")
17
+public class MovieController {
18
+    @Autowired
19
+    MovieServiceTrait movieServiceTrait;
20
+
21
+    @GetMapping("/teamMembers")
22
+    public ResponseEntity getTeamMembers(@RequestParam(required = true) String movieTitle) {
23
+        scala.collection.immutable.List<MovieService.Principal> principalList;
24
+
25
+        try {
26
+            if (movieTitle == null)
27
+                return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
28
+            else {
29
+                principalList = (movieServiceTrait.principalsForMovieName(movieTitle).toList());
30
+            }
31
+
32
+            return new ResponseEntity<>(new JsonCustomMapping().mapper(principalList), HttpStatus.OK);
33
+
34
+        } catch (Exception e) {
35
+            return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
36
+        }
37
+
38
+    }
39
+
40
+
41
+}

+ 0
- 120
src/main/scala/com/mediahub/FileReader.scala View File

@@ -1,120 +0,0 @@
1
-package com.mediahub
2
-
3
-import akka.NotUsed
4
-import akka.actor.ActorSystem
5
-import akka.stream.ActorAttributes.supervisionStrategy
6
-import akka.stream.Supervision.resumingDecider
7
-import akka.stream.alpakka.csv.scaladsl.{CsvParsing, CsvToMap}
8
-import akka.stream.scaladsl.{Compression, FileIO, Flow, Sink, Source}
9
-import akka.util.ByteString
10
-import org.springframework.stereotype.Component
11
-
12
-import java.io.File
13
-import java.nio.file.Paths
14
-import scala.collection.immutable
15
-import scala.concurrent.duration.DurationInt
16
-import scala.concurrent.{Await, Future}
17
-import scala.language.postfixOps
18
-
19
-
20
-@Component
21
-class FileReader {
22
-
23
-  implicit val system: ActorSystem = ActorSystem()
24
-
25
-  val titleBasicsResource: File = new File("src/main/resources/title.basics.tsv.gz")
26
-  val titlePrincipalsResource: File = new File("src/main/resources/title.principals.tsv.gz")
27
-  val nameBasicsResource: File = new File("src/main/resources/name.basics.tsv.gz")
28
-
29
-  def fileSource(file: File): Source[ByteString, NotUsed] = {
30
-    Source.single(file)
31
-      .flatMapConcat(f => FileIO.fromPath(Paths.get(f.getPath), 1 * 1024 * 1024 * 2))
32
-      .via(Compression.gunzip())
33
-  }
34
-
35
-  val lineParser: Flow[ByteString, Map[String, String], NotUsed] = {
36
-    CsvParsing
37
-      .lineScanner(CsvParsing.Tab, CsvParsing.DoubleQuote, CsvParsing.DoubleQuote)
38
-      .via(CsvToMap.toMapAsStringsCombineAll(headerPlaceholder = Option.empty))
39
-  }
40
-
41
-  //working search not optimized
42
-  val titleId: String = getIdOfTitleAsync(titleBasicsResource, "Carmencita")
43
-  println("value ", titleId)
44
-
45
-  val personsIdList: List[String] = getIdOfPersonsAsync(titlePrincipalsResource, titleId).toList.flatten
46
-  println("value ", personsIdList)
47
-
48
-  val personsList = getPersons(nameBasicsResource, personsIdList)
49
-  println("value ", personsList)
50
-
51
-
52
-  def getIdOfTitleAsync(file: File, titleName: String): String = {
53
-    val result = fileSource(file)
54
-      .mapAsync(50) {
55
-        res =>
56
-          Source.single(res)
57
-            .via(lineParser)
58
-            .filter(row => row.getOrElse("primaryTitle", "") == titleName)
59
-            .map(a => a.get("tconst"))
60
-            .withAttributes(supervisionStrategy(resumingDecider))
61
-            .runWith(Sink.head)
62
-      }
63
-      .withAttributes(supervisionStrategy(resumingDecider))
64
-      .runWith(Sink.head)
65
-
66
-    Await.result(result, 5 minutes)
67
-    result.value.get.get.get
68
-  }
69
-
70
-  def getIdOfPersonsAsync(file: File, titleId: String): immutable.Iterable[Option[String]] = {
71
-    val te = fileSource(file)
72
-      .mapAsync(50) {
73
-        res =>
74
-          Source.single(res)
75
-            .via(lineParser)
76
-            .filter(row => row.getOrElse("tconst", "") == titleId)
77
-            .map(a => a.get("nconst"))
78
-            .withAttributes(supervisionStrategy(resumingDecider))
79
-            .runWith(Sink.collection)
80
-      }
81
-      .withAttributes(supervisionStrategy(resumingDecider))
82
-      .runWith(Sink.head)
83
-
84
-    Await.result(te, 5 minutes)
85
-  }
86
-
87
-  def getPersons(file: File, personsIdList: List[String]): List[String] = {
88
-    val result: Future[immutable.Iterable[Option[String]]] = Source.single(file)
89
-      .flatMapConcat(f => FileIO.fromPath(Paths.get(f.getPath), 1 * 1024 * 1024))
90
-      .via(Compression.gunzip())
91
-      .via(CsvParsing.lineScanner(CsvParsing.Tab, CsvParsing.DoubleQuote, CsvParsing.DoubleQuote))
92
-      .via(CsvToMap.toMapAsStringsCombineAll(headerPlaceholder = Option.empty))
93
-      .filter(row => personsIdList.contains(row.getOrElse("nconst", "")))
94
-      .map(a => a.get("primaryName"))
95
-      .runWith(Sink.collection)
96
-
97
-    Await.result(result, 5 minutes)
98
-    result.value.get.get.toList.flatten
99
-  }
100
-
101
- /* def getPersonsAsync(file: File, personsIdList: List[String]) = {
102
-    val test = Source.single(file)
103
-      .flatMapConcat(f => FileIO.fromPath(Paths.get(f.getPath), 1 * 1024 * 1024))
104
-      .via(Compression.gunzip())
105
-      .mapAsync(2) {
106
-        res =>
107
-          Source.single(res)
108
-            .via(CsvParsing.lineScanner(CsvParsing.Tab, CsvParsing.DoubleQuote, CsvParsing.DoubleQuote))
109
-            .via(CsvToMap.toMapAsStringsCombineAll(headerPlaceholder = Option.empty))
110
-            .filter(row => row.getOrElse("nconst", "") == personsIdList.head)
111
-            .map(a => a.get("primaryName"))
112
-            .runWith(Sink.collection)
113
-      }
114
-      .runWith(Sink.collection)
115
-
116
-    Await.result(test, 5 minutes)
117
-    test.value.get.get.toList.flatten
118
-  }
119
-  */
120
-}

+ 12
- 0
src/main/scala/com/mediahub/JsonCustomMapping.scala View File

@@ -0,0 +1,12 @@
1
+package com.mediahub
2
+
3
+import org.json4s.DefaultFormats
4
+import org.json4s.native.Json
5
+
6
+class JsonCustomMapping extends MovieService {
7
+
8
+  def mapper(list:  List[Principal]): String = {
9
+     Json(DefaultFormats).write(list)
10
+  }
11
+
12
+}

+ 93
- 16
src/main/scala/com/mediahub/MovieQueryService.scala View File

@@ -1,27 +1,104 @@
1 1
 package com.mediahub
2 2
 
3
-import akka.stream.scaladsl.Source
3
+import akka.NotUsed
4
+import akka.actor.ActorSystem
5
+import akka.stream.ActorAttributes.supervisionStrategy
6
+import akka.stream.Supervision.resumingDecider
7
+import akka.stream.alpakka.csv.scaladsl.{CsvParsing, CsvToMap}
8
+import akka.stream.scaladsl.{Compression, FileIO, Flow, Sink, Source}
9
+import akka.util.ByteString
10
+import org.springframework.stereotype.Component
4 11
 
5
-class MovieQueryService {
12
+import java.io.File
13
+import java.nio.charset.StandardCharsets
14
+import java.nio.file.Paths
15
+import scala.collection.immutable
16
+import scala.concurrent.Await
17
+import scala.concurrent.duration.DurationInt
18
+import scala.language.postfixOps
6 19
 
7
-  final case class Principal(
8
-                              name: String,
9
-                              birthYear: Int,
10
-                              deathYear: Option[Int],
11
-                              profession: List[String])
12 20
 
13
-  final case class TvSeries(
14
-                             original: String,
15
-                             startYear: Int,
16
-                             endYear: Option[Int],
17
-                             genres: List[String])
21
+@Component
22
+class MovieQueryService extends MovieServiceTrait {
18 23
 
19
-  trait MovieService {
20
-    def principalsForMovieName(name: String): Source[Principal, _]
24
+  implicit val system: ActorSystem = ActorSystem()
21 25
 
22
-    def tvSeriesWithGreatestNumberOfEpisodes(): Source[TvSeries, _]
26
+  val titleBasicsResource: File = new File("src/main/resources/title.basics.tsv.gz")
27
+  val titlePrincipalsResource: File = new File("src/main/resources/title.principals.tsv.gz")
28
+  val nameBasicsResource: File = new File("src/main/resources/name.basics.tsv.gz")
29
+
30
+  def fileSource(file: File): Source[ByteString, NotUsed] = {
31
+    Source.single(file)
32
+      .flatMapConcat(f => FileIO.fromPath(Paths.get(f.getPath), 1 * 1024 * 1024 * 2))
33
+      .via(Compression.gunzip())
34
+  }
35
+
36
+  val lineParser: Flow[ByteString, Map[String, String], NotUsed] = {
37
+    CsvParsing
38
+      .lineScanner(CsvParsing.Tab, CsvParsing.DoubleQuote, CsvParsing.DoubleQuote)
39
+      .via(CsvToMap.toMapAsStringsCombineAll(headerPlaceholder = Option.empty))
23 40
   }
24 41
 
25
-}
26 42
 
43
+  override def principalsForMovieName(name: String): List[Principal] = {
44
+
45
+    val titleId: String = getIdOfTitle(titleBasicsResource, name)
46
+    val personsIdList: List[String] = getIdOfPersons(titlePrincipalsResource, titleId).toList.flatten
47
+    val personsList = getPersons(nameBasicsResource, personsIdList)
48
+    personsList
49
+  }
50
+
51
+  override def tvSeriesWithGreatestNumberOfEpisodes(): List[TvSeries] = ???
52
+
53
+
54
+  def getIdOfTitle(file: File, titleName: String): String = {
55
+    val result = fileSource(file)
56
+      .mapAsync(50) {
57
+        res =>
58
+          Source.single(res)
59
+            .via(lineParser)
60
+            .filter(row => row.getOrElse("primaryTitle", "") == titleName)
61
+            .map(a => a.get("tconst"))
62
+            .withAttributes(supervisionStrategy(resumingDecider))
63
+            .runWith(Sink.head)
64
+      }
65
+      .withAttributes(supervisionStrategy(resumingDecider))
66
+      .runWith(Sink.head)
67
+
68
+    Await.result(result, 5 minutes)
69
+    result.value.get.get.get
70
+  }
71
+
72
+  def getIdOfPersons(file: File, titleId: String): immutable.Iterable[Option[String]] = {
73
+    val te = fileSource(file)
74
+      .mapAsync(50) {
75
+        res =>
76
+          Source.single(res)
77
+            .via(lineParser)
78
+            .filter(row => row.getOrElse("tconst", "") == titleId)
79
+            .map(a => a.get("nconst"))
80
+            .withAttributes(supervisionStrategy(resumingDecider))
81
+            .runWith(Sink.collection)
82
+      }
83
+      .withAttributes(supervisionStrategy(resumingDecider))
84
+      .runWith(Sink.head)
85
+
86
+    Await.result(te, 5 minutes)
87
+  }
88
+
89
+
90
+  def getPersons(file: File, personsIdList: List[String]): List[Principal] = {
91
+    val result = Source.single(file)
92
+      .flatMapConcat(f => FileIO.fromPath(Paths.get(f.getPath), 1 * 1024 * 1024))
93
+      .via(Compression.gunzip())
94
+      .via(CsvParsing.lineScanner(CsvParsing.Tab, CsvParsing.DoubleQuote, CsvParsing.DoubleQuote))
95
+      .via(CsvToMap.toMapAsStringsCombineAll(StandardCharsets.UTF_8, Option.empty))
96
+      .filter(row => personsIdList.contains(row.getOrElse("nconst", "")))
97
+      .map(a => Principal(a("primaryName"), a("birthYear").toInt, a("deathYear").toIntOption, a.get("primaryProfession").toList))
98
+      .runWith(Sink.collection)
99
+
100
+    Await.result(result, 5 minutes)
101
+    result.value.get.get.toList
102
+  }
27 103
 
104
+}

+ 20
- 0
src/main/scala/com/mediahub/MovieService.scala View File

@@ -0,0 +1,20 @@
1
+package com.mediahub
2
+
3
+class MovieService {
4
+
5
+  final case class Principal(
6
+                              name: String,
7
+                              birthYear: Int,
8
+                              deathYear: Option[Int],
9
+                              profession: List[String])
10
+
11
+  case class TvSeries(
12
+                       original: String,
13
+                       startYear: Int,
14
+                       endYear: Option[Int],
15
+                       genres: List[String])
16
+
17
+
18
+}
19
+
20
+

+ 8
- 0
src/main/scala/com/mediahub/MovieServiceTrait.scala View File

@@ -0,0 +1,8 @@
1
+package com.mediahub
2
+
3
+
4
+trait MovieServiceTrait extends  MovieService {
5
+    def principalsForMovieName(name: String):  List[Principal]
6
+    def tvSeriesWithGreatestNumberOfEpisodes():  List[TvSeries]
7
+
8
+}

Powered by TurnKey Linux.