Antoine DORIAN 1 year ago
parent
commit
ab6245a427

+ 14
- 21
README.md View File

1
 # mediahub
1
 # mediahub
2
 
2
 
3
+Bilan: 
4
+<br>Voici ma Solution a l"exercice de recherche d'information dans des fichiers TSV en utilisant la bibliotheque Akka Stream realiser en Java et Scala
5
+<br>Le service de recherche est fait en Scala, celui-ci est intègrer dans une solution Springboot en Java
3
 
6
 
4
-Instruction :
5
-Vous allez avoir droit à 5 fichier.
7
+Instruction:
8
+<br>Pour le bon fonctionement du projet, il est necessaire de telecharger les fichiers suivant et de les placer dans le repertoire resources, ne pas dezipper les fichiers (main\resources): 
6
 
9
 
7
-Ces 5 fichiers Charles pense qu'il faudra les charger dans dictionnary, dans 5 map et ensuite vous allez devoir les requêté à l’aide d’akkastream.
10
+- https://datasets.imdbws.com/name.basics.tsv.gz
11
+- https://datasets.imdbws.com/title.episode.tsv.gz
12
+- https://datasets.imdbws.com/title.ratings.tsv.gz
13
+- https://datasets.imdbws.com/title.principals.tsv.gz
14
+- https://datasets.imdbws.com/title.basics.tsv.gz
8
 
15
 
9
-Le principe d’akka est que sa permet de créer un pipe, vous avez la même logique que des streams en java. Donc le principe est que vous avez deux, trois recherche à opérer et vous allez faire un cor ( une api business) qui permet de faire une recherche et qu’il faudra écrire en SCALA.
16
+Afin de lancer la solution, il suffit de lancer MediahubApplication qui se trouve dans la partie Java du projet
10
 
17
 
11
-L’idéal serait d’écrire tous le service en scala, regarder sur internet comment créer un service en scala.
18
+Les deux endpoints disponibles pour tester le service sont:
12
 
19
 
13
-Sinon,  vous faites un springboot qui va appeler ce core dev en scala. Ce qui est certain c’est que le core doit être écrit en scala sur la base de l’api stream AKKA.
20
+- http://localhost:8080/api/teamMembers?movieTitle=Carmencita
21
+- http://localhost:8080/api/tvSeries
14
 
22
 
15
-Le sentiment de Charles est qu’il faut bien montrer le principe du pipe, c’est à dire que vous allez avoir potentiellement 5 map et l’idée est d’avoir un seul stream qui va permettre de les requêtes et de concaténer les  résultats, pour en faire un résultat final qui va être envoyé au service.
16
-
17
-Vous en discuterez lundi avec Charles pour savoir de quelle façon le faire.
18
-
19
-
20
-
21
-Pour résumer :
22
-
23
-Un core qui va être développé en scala au travers de la librairie Akkastream ( akkastream va permettre de requêter les différend fichier comme étant des source de donnée).
24
-
25
-Sur la base de cette source-là vous allez avoir des sources de données que vous allez concaténer au travers d’un stream et c’est sur ce stream là que vous allez faire vos recherches.
26
-
27
-A voir comment vous allez gérer ça lundi avec Charles.
28
-
29
-Ce service, il faudra l’exposer avec un springboot qui prépose juste une API requête qui appellera ce cœur business.

+ 13
- 1
src/main/java/com/mediahub/controller/MovieController.java View File

29
                 principalList = (movieServiceTrait.principalsForMovieName(movieTitle).toList());
29
                 principalList = (movieServiceTrait.principalsForMovieName(movieTitle).toList());
30
             }
30
             }
31
 
31
 
32
-            return new ResponseEntity<>(new JsonCustomMapping().mapper(principalList), HttpStatus.OK);
32
+            return new ResponseEntity<>(new JsonCustomMapping().mapperPrincipal(principalList), HttpStatus.OK);
33
 
33
 
34
         } catch (Exception e) {
34
         } catch (Exception e) {
35
             return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
35
             return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
37
 
37
 
38
     }
38
     }
39
 
39
 
40
+    @GetMapping("/tvSeries")
41
+    public ResponseEntity getTvSeries() {
42
+        scala.collection.immutable.List<MovieService.TvSeries> tvSeriesList;
43
+
44
+        try {
45
+            tvSeriesList = (movieServiceTrait.tvSeriesWithGreatestNumberOfEpisodes().toList());
46
+            return new ResponseEntity<>(new JsonCustomMapping().mapperSeries(tvSeriesList), HttpStatus.OK);
47
+        } catch (Exception e) {
48
+            return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
49
+        }
50
+
51
+    }
40
 
52
 
41
 }
53
 }

+ 4
- 1
src/main/scala/com/mediahub/JsonCustomMapping.scala View File

5
 
5
 
6
 class JsonCustomMapping extends MovieService {
6
 class JsonCustomMapping extends MovieService {
7
 
7
 
8
-  def mapper(list:  List[Principal]): String = {
8
+  def mapperPrincipal(list:  List[Principal]): String = {
9
      Json(DefaultFormats).write(list)
9
      Json(DefaultFormats).write(list)
10
   }
10
   }
11
 
11
 
12
+  def mapperSeries(list: List[TvSeries]): String = {
13
+    Json(DefaultFormats).write(list)
14
+  }
12
 }
15
 }

+ 19
- 23
src/main/scala/com/mediahub/MovieQueryService.scala View File

16
 import scala.concurrent.Await
16
 import scala.concurrent.Await
17
 import scala.concurrent.duration.DurationInt
17
 import scala.concurrent.duration.DurationInt
18
 import scala.language.postfixOps
18
 import scala.language.postfixOps
19
+import scala.util.Try
19
 
20
 
20
 
21
 
21
 @Component
22
 @Component
40
       .via(CsvToMap.toMapAsStringsCombineAll(headerPlaceholder = Option.empty))
41
       .via(CsvToMap.toMapAsStringsCombineAll(headerPlaceholder = Option.empty))
41
   }
42
   }
42
 
43
 
43
-
44
-  val res = getSeriesTitle(titleEpisodeResource)
45
-  val r = getTitleByIds(titleBasicsResource, res)
46
-  println(r)
47
-
48
   override def principalsForMovieName(name: String): List[Principal] = {
44
   override def principalsForMovieName(name: String): List[Principal] = {
49
 
45
 
50
     val titleId: String = getIdOfTitle(titleBasicsResource, name)
46
     val titleId: String = getIdOfTitle(titleBasicsResource, name)
53
     personsList
49
     personsList
54
   }
50
   }
55
 
51
 
56
-  override def tvSeriesWithGreatestNumberOfEpisodes(): List[TvSeries] = ???
57
-    //val personsIdList: List[String] = getSeriestitle(titleEpisodeResource)
52
+  override def tvSeriesWithGreatestNumberOfEpisodes(): List[TvSeries] = {
53
+    val seriesTitleMap = getSeriesTitle(titleEpisodeResource)
54
+    val titleListMaxEpisode = getTitleByIds(titleBasicsResource, seriesTitleMap)
55
+    titleListMaxEpisode
56
+  }
58
 
57
 
59
 
58
 
60
 
59
 
76
     result.value.get.get.get
75
     result.value.get.get.get
77
   }
76
   }
78
 
77
 
79
-  def getTitleByIds(file: File, titleIdMap: mutable.Map[String, Int]): Seq[Option[String]] = {
80
-    val result = fileSource(file)
81
-      .mapAsync(50) {
82
-        res =>
83
-          Source.single(res)
84
-            .via(lineParser)
85
-            .filter(row => titleIdMap.contains(row.getOrElse("tconst", "")))
86
-            .map(a => a.get("primaryTitle"))
87
-            .withAttributes(supervisionStrategy(resumingDecider))
88
-            .runWith(Sink.collection)
89
-      }
90
-      .withAttributes(supervisionStrategy(resumingDecider))
91
-      .runWith(Sink.head)
78
+  def getTitleByIds(file: File, titleIdMap: mutable.Map[String, Int]): List[TvSeries] = {
79
+    val result = Source.single(file)
80
+      .flatMapConcat(f => FileIO.fromPath(Paths.get(f.getPath), 1 * 1024 * 1024))
81
+      .via(Compression.gunzip())
82
+      .via(CsvParsing.lineScanner(CsvParsing.Tab, CsvParsing.DoubleQuote, CsvParsing.DoubleQuote))
83
+      .via(CsvToMap.toMapAsStringsCombineAll(StandardCharsets.UTF_8, Option.empty))
84
+      .filter(row => titleIdMap.keySet.toList.contains(row.getOrElse("tconst", "")))
85
+      .map(a => TvSeries(a("originalTitle"), Try(a.getOrElse("startYear","").toInt).getOrElse(0), a.getOrElse("endYear","").toIntOption, a.get("genres").toList))
86
+      .runWith(Sink.collection)
92
 
87
 
93
     Await.result(result, 5 minutes)
88
     Await.result(result, 5 minutes)
94
     result.value.get.get.toList
89
     result.value.get.get.toList
95
   }
90
   }
91
+
96
   def getIdOfPersons(file: File, titleId: String): immutable.Iterable[Option[String]] = {
92
   def getIdOfPersons(file: File, titleId: String): immutable.Iterable[Option[String]] = {
97
-    val te = fileSource(file)
93
+    val result = fileSource(file)
98
       .mapAsync(50) {
94
       .mapAsync(50) {
99
         res =>
95
         res =>
100
           Source.single(res)
96
           Source.single(res)
107
       .withAttributes(supervisionStrategy(resumingDecider))
103
       .withAttributes(supervisionStrategy(resumingDecider))
108
       .runWith(Sink.head)
104
       .runWith(Sink.head)
109
 
105
 
110
-    Await.result(te, 5 minutes)
106
+    Await.result(result, 5 minutes)
111
   }
107
   }
112
 
108
 
113
 
109
 
118
       .via(CsvParsing.lineScanner(CsvParsing.Tab, CsvParsing.DoubleQuote, CsvParsing.DoubleQuote))
114
       .via(CsvParsing.lineScanner(CsvParsing.Tab, CsvParsing.DoubleQuote, CsvParsing.DoubleQuote))
119
       .via(CsvToMap.toMapAsStringsCombineAll(StandardCharsets.UTF_8, Option.empty))
115
       .via(CsvToMap.toMapAsStringsCombineAll(StandardCharsets.UTF_8, Option.empty))
120
       .filter(row => personsIdList.contains(row.getOrElse("nconst", "")))
116
       .filter(row => personsIdList.contains(row.getOrElse("nconst", "")))
121
-      .map(a => Principal(a("primaryName"), a("birthYear").toInt, a("deathYear").toIntOption, a.get("primaryProfession").toList))
117
+      .map(a => Principal(a("primaryName"), Try(a("birthYear").toInt).getOrElse(0), a("deathYear").toIntOption, a.get("primaryProfession").toList))
122
       .runWith(Sink.collection)
118
       .runWith(Sink.collection)
123
 
119
 
124
     Await.result(result, 5 minutes)
120
     Await.result(result, 5 minutes)

Powered by TurnKey Linux.