Commit b31def5d authored by Jonas Waeber's avatar Jonas Waeber
Browse files

Minor fixes & refactor

Fix carrier type map.
Refactor helper functions [WIP]
Document helper functions [WIP]
Improve logging for helper functions [WIP]
Update tests
parent 4e653dbf
...@@ -20,7 +20,9 @@ package org.memobase ...@@ -20,7 +20,9 @@ package org.memobase
import com.beust.klaxon.JsonObject import com.beust.klaxon.JsonObject
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import org.memobase.helpers.CarrierType
import org.memobase.helpers.Extract import org.memobase.helpers.Extract
import org.memobase.helpers.Filter
import org.memobase.helpers.ReuseStatementMap import org.memobase.helpers.ReuseStatementMap
import org.memobase.model.LanguageContainer import org.memobase.model.LanguageContainer
import org.memobase.model.NameContainer import org.memobase.model.NameContainer
...@@ -36,35 +38,35 @@ class SearchDocTransform { ...@@ -36,35 +38,35 @@ class SearchDocTransform {
val id = record["@id"] as String val id = record["@id"] as String
val recordIdentifiers = Extract.getEntitiesFromIds("identifiedBy", record, input) val recordIdentifiers = Filter.entitiesByProperty("identifiedBy", record, input)
val recordTitles = Extract.getEntitiesFromIds("hasTitle", record, input) val recordTitles = Filter.entitiesByProperty("hasTitle", record, input)
val recordLanguages = Extract.getEntitiesFromIds("hasLanguage", record, input) val recordLanguages = Filter.entitiesByProperty("hasLanguage", record, input)
val recordRules = Extract.getEntitiesFromIds("regulatedBy", record, input) val recordRules = Filter.entitiesByProperty("regulatedBy", record, input)
val datesCreated = Extract.getEntitiesFromIds("created", record, input) val datesCreated = Filter.entitiesByProperty("created", record, input)
val datesIssued = Extract.getEntitiesFromIds("issued", record, input) val datesIssued = Filter.entitiesByProperty("issued", record, input)
val temporal = Extract.getEntitiesFromIds("temporal", record, input) val temporal = Filter.entitiesByProperty("temporal", record, input)
val placesRelated = Extract.getEntitiesFromIds("spatial", record, input) val placesRelated = Filter.entitiesByProperty("spatial", record, input)
val placeCaptured = Extract.getEntitiesFromIds("P60556", record, input) val placeCaptured = Filter.entitiesByProperty("P60556", record, input)
val genre = Extract.getEntitiesFromIds("hasGenre", record, input) val genre = Filter.entitiesByProperty("hasGenre", record, input)
val subjects = Extract.getEntitiesFromIds("hasSubject", record, input) val subjects = Filter.entitiesByProperty("hasSubject", record, input)
val publishers = Extract.getEntitiesFromIds("publishedBy", record, input) val publishers = Filter.entitiesByProperty("publishedBy", record, input)
val producers = Extract.getEntitiesFromIds("P60441", record, input) val producers = Filter.entitiesByProperty("P60441", record, input)
val creationRelationAgents = val creationRelationAgents =
Extract.getEntitiesFromIds("recordResourceOrInstantiationIsSourceOfCreationRelation", record, input) Filter.entitiesByProperty("recordResourceOrInstantiationIsSourceOfCreationRelation", record, input)
val digitalRules = Extract.getEntitiesFromIds("regulatedBy", digitalObject, input) val digitalRules = Filter.entitiesByProperty("regulatedBy", digitalObject, input)
val physicalRules = Extract.getEntitiesFromIds("regulatedBy", physicalObject, input) val physicalRules = Filter.entitiesByProperty("regulatedBy", physicalObject, input)
val physicalIdentifiers = Extract.getEntitiesFromIds("identifiedBy", physicalObject, input) val physicalIdentifiers = Filter.entitiesByProperty("identifiedBy", physicalObject, input)
val accessPhysical = Extract.typedEntityByType(physicalRules, "type", "access", "name").flatMap { it.toList() } val accessPhysical = Extract.typedEntityByType(physicalRules, "type", "access", "name").flatMap { it.toList() }
val accessDigital = Extract.typedEntityByType(digitalRules, "type", "access", "name").flatMap { it.toList() } val accessDigital = Extract.typedEntityByType(digitalRules, "type", "access", "name").flatMap { it.toList() }
val usageDigital = Extract.typedEntityByType(digitalRules, "type", "usage", "sameAs").flatMap { it.toList() } val usageDigital = Extract.typedEntityByType(digitalRules, "type", "usage", "sameAs").flatMap { it.toList() }
val format = Extract.carrierType(Extract.getEntitiesFromIds("hasCarrierType", physicalObject, input)) val format = CarrierType.extract(Filter.entitiesByProperty("hasCarrierType", physicalObject, input))
if (format.isEmpty()) { if (format.isEmpty()) {
log.error("Found no carrier types for record $id.") log.error("Found no carrier types for record $id.")
} }
...@@ -81,7 +83,7 @@ class SearchDocTransform { ...@@ -81,7 +83,7 @@ class SearchDocTransform {
"NoSourceIdFound" "NoSourceIdFound"
}, },
sameAs = Extract.listOfStrings(record["sameAs"]), sameAs = Extract.listOfStrings(record["sameAs"]),
abstract = Extract.extractLanguageContainer("abstract", record["abstract"]), abstract = Extract.languageContainer("abstract", record["abstract"]),
id = id, id = id,
institution = listOf( institution = listOf(
NameContainer( NameContainer(
...@@ -93,10 +95,10 @@ class SearchDocTransform { ...@@ -93,10 +95,10 @@ class SearchDocTransform {
LanguageContainer(listOf("Bestand"), listOf("collection"), listOf("fondo"), emptyList()), LanguageContainer(listOf("Bestand"), listOf("collection"), listOf("fondo"), emptyList()),
listOf("https://memobase.ch/recordSet/EXAMPLE") listOf("https://memobase.ch/recordSet/EXAMPLE")
), ),
descriptiveNote = Extract.extractLanguageContainer("descriptiveNote", record["descriptiveNote"]), descriptiveNote = Extract.languageContainer("descriptiveNote", record["descriptiveNote"]),
scopeAndContent = Extract.extractLanguageContainer("scopeAndContent", record["scopeAndContent"]), scopeAndContent = Extract.languageContainer("scopeAndContent", record["scopeAndContent"]),
relatedMaterial = Extract.extractLanguageContainer("relation", record["relation"]), relatedMaterial = Extract.languageContainer("relation", record["relation"]),
source = Extract.extractLanguageContainer("source", record["source"]), source = Extract.languageContainer("source", record["source"]),
temporal = Extract.extractDate(temporal), temporal = Extract.extractDate(temporal),
dateCreated = Extract.extractDate(datesCreated), dateCreated = Extract.extractDate(datesCreated),
dateIssued = Extract.extractDate(datesIssued), dateIssued = Extract.extractDate(datesIssued),
...@@ -167,19 +169,19 @@ class SearchDocTransform { ...@@ -167,19 +169,19 @@ class SearchDocTransform {
accessDigital = accessDigital, accessDigital = accessDigital,
durationDigital = Extract.listOfStrings(digitalObject?.get("duration")), durationDigital = Extract.listOfStrings(digitalObject?.get("duration")),
colourDigital = Extract.listOfStrings(digitalObject?.get("P60558")), colourDigital = Extract.listOfStrings(digitalObject?.get("P60558")),
digitalObjectNote = Extract.extractLanguageContainer("descriptiveNote", digitalObject?.get("descriptiveNote")), digitalObjectNote = Extract.languageContainer("descriptiveNote", digitalObject?.get("descriptiveNote")),
locator = Extract.listOfStrings(digitalObject?.get("locator")), locator = Extract.listOfStrings(digitalObject?.get("locator")),
usageConditionsDigital = Extract.extractLanguageContainer("conditionsOfUse", digitalObject?.get("conditionsOfUse")), usageConditionsDigital = Extract.languageContainer("conditionsOfUse", digitalObject?.get("conditionsOfUse")),
usageDigital = usageDigital, usageDigital = usageDigital,
usageDigitalGroup = usageDigital.map { ReuseStatementMap.getValue(it) }, usageDigitalGroup = usageDigital.map { ReuseStatementMap.getValue(it) },
// PHYSICAL // PHYSICAL
accessPhysical = accessPhysical, accessPhysical = accessPhysical,
durationPhysical = Extract.listOfStrings(physicalObject?.get("duration")), durationPhysical = Extract.listOfStrings(physicalObject?.get("duration")),
colourPhysical = Extract.extractLanguageContainer("P60558", physicalObject?.get("P60558")), colourPhysical = Extract.languageContainer("P60558", physicalObject?.get("P60558")),
physicalCharacteristics = Extract.extractLanguageContainer("physicalCharacteristics", physicalObject?.get("physicalCharacteristics")), physicalCharacteristics = Extract.languageContainer("physicalCharacteristics", physicalObject?.get("physicalCharacteristics")),
physicalObjectNote = Extract.extractLanguageContainer("descriptiveNote", physicalObject?.get("descriptiveNote")), physicalObjectNote = Extract.languageContainer("descriptiveNote", physicalObject?.get("descriptiveNote")),
usageConditionsPhysical = Extract.extractLanguageContainer("conditionsOfUse", physicalObject?.get("conditionsOfUse")), usageConditionsPhysical = Extract.languageContainer("conditionsOfUse", physicalObject?.get("conditionsOfUse")),
usagePhysical = Extract.typedEntityByType(physicalRules, "type", "usage", "sameAs").flatMap { it.toList() }, usagePhysical = Extract.typedEntityByType(physicalRules, "type", "usage", "sameAs").flatMap { it.toList() },
callNumber = Extract.typedEntityByType(physicalIdentifiers, "type", "callNumber", "identifier").flatMap { it.toList() }, callNumber = Extract.typedEntityByType(physicalIdentifiers, "type", "callNumber", "identifier").flatMap { it.toList() },
format = format format = format
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
package org.memobase package org.memobase
import kotlin.system.exitProcess
import org.apache.kafka.streams.KafkaStreams import org.apache.kafka.streams.KafkaStreams
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import org.memobase.settings.SettingsLoader import org.memobase.settings.SettingsLoader
...@@ -41,6 +42,9 @@ class Service(file: String = "app.yml") { ...@@ -41,6 +42,9 @@ class Service(file: String = "app.yml") {
log.info("Service is running.") log.info("Service is running.")
Thread.sleep(10_000L) Thread.sleep(10_000L)
} }
it.cleanUp()
} }
log.error("The streams application ended.")
exitProcess(1)
} }
} }
/*
* search-doc-service
* Copyright (C) 2020 Memoriav
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.memobase.helpers
import com.beust.klaxon.JsonObject
import org.memobase.model.NameContainer
object CarrierType {
fun extract(items: List<JsonObject>): List<NameContainer> {
return items.map {
Extract.listOfStrings(it["sameAs"]).let { value ->
val name = Extract.languageContainer("carrierType", it["name"]).reduce { acc, languageContainer -> acc.merge(languageContainer) }
if (value.isEmpty()) {
NameContainer(name, emptyList())
} else {
NameContainer(name, value)
}
}
}
}
}
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
package org.memobase.helpers package org.memobase.helpers
import com.beust.klaxon.JsonArray
import com.beust.klaxon.JsonObject import com.beust.klaxon.JsonObject
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import org.memobase.model.CreatorNameContainer import org.memobase.model.CreatorNameContainer
...@@ -28,9 +27,9 @@ import org.memobase.model.NameContainer ...@@ -28,9 +27,9 @@ import org.memobase.model.NameContainer
import org.memobase.rdf.NS import org.memobase.rdf.NS
object Extract { object Extract {
private val log = LogManager.getLogger("ExtractionHelper") private val log = LogManager.getLogger("ExtractSearchDoc")
private fun extractLanguageTag(entity: JsonObject, language: String): List<String> { private fun languageTag(entity: JsonObject, language: String): List<String> {
return entity["@value"].let { return entity["@value"].let {
if (entity["@language"] == language && it != null) if (entity["@language"] == language && it != null)
listOf(it as String) listOf(it as String)
...@@ -39,15 +38,15 @@ object Extract { ...@@ -39,15 +38,15 @@ object Extract {
} }
} }
fun extractLanguageContainer(parent: String, entity: Any?): List<LanguageContainer> { fun languageContainer(parent: String, entity: Any?): List<LanguageContainer> {
return when (entity) { return when (entity) {
is String -> listOf(LanguageContainer(emptyList(), emptyList(), emptyList(), listOf(entity))) is String -> listOf(LanguageContainer(emptyList(), emptyList(), emptyList(), listOf(entity)))
is JsonObject -> is JsonObject ->
listOf( listOf(
LanguageContainer( LanguageContainer(
de = extractLanguageTag(entity, "de"), de = languageTag(entity, "de"),
fr = extractLanguageTag(entity, "fr"), fr = languageTag(entity, "fr"),
it = extractLanguageTag(entity, "it"), it = languageTag(entity, "it"),
un = emptyList() un = emptyList()
) )
) )
...@@ -58,9 +57,9 @@ object Extract { ...@@ -58,9 +57,9 @@ object Extract {
LanguageContainer(emptyList(), emptyList(), emptyList(), listOf(subEntity)) LanguageContainer(emptyList(), emptyList(), emptyList(), listOf(subEntity))
is JsonObject -> is JsonObject ->
LanguageContainer( LanguageContainer(
de = extractLanguageTag(subEntity, "de"), de = languageTag(subEntity, "de"),
fr = extractLanguageTag(subEntity, "fr"), fr = languageTag(subEntity, "fr"),
it = extractLanguageTag(subEntity, "it"), it = languageTag(subEntity, "it"),
un = emptyList() un = emptyList()
) )
else -> { else -> {
...@@ -71,6 +70,10 @@ object Extract { ...@@ -71,6 +70,10 @@ object Extract {
}.reduce { acc, languageContainer -> }.reduce { acc, languageContainer ->
acc.merge(languageContainer) acc.merge(languageContainer)
}) })
null -> {
log.info("No items in $parent found.")
emptyList()
}
else -> { else -> {
log.error("Could not extract language container from entity: $entity in parent $parent.") log.error("Could not extract language container from entity: $entity in parent $parent.")
emptyList() emptyList()
...@@ -115,13 +118,13 @@ object Extract { ...@@ -115,13 +118,13 @@ object Extract {
annotationField: String annotationField: String
): List<LanguageContainer> { ): List<LanguageContainer> {
return entities.filter { it[field] == type }.flatMap { return entities.filter { it[field] == type }.flatMap {
extractLanguageContainer(it["@id"] as String, it[annotationField]) languageContainer(it["@id"] as String, it[annotationField])
} }
} }
fun facetEntity(entities: List<JsonObject>, property: String): List<NameContainer> { fun facetEntity(entities: List<JsonObject>, property: String): List<NameContainer> {
return entities.mapNotNull { return entities.mapNotNull {
val lang = extractLanguageContainer(it["@id"] as String, it[property]) val lang = languageContainer(it["@id"] as String, it[property])
if (lang.isEmpty()) { if (lang.isEmpty()) {
null null
} else { } else {
...@@ -132,7 +135,7 @@ object Extract { ...@@ -132,7 +135,7 @@ object Extract {
fun extractPlaces(entities: List<JsonObject>): List<LanguageContainer> { fun extractPlaces(entities: List<JsonObject>): List<LanguageContainer> {
return entities.flatMap { return entities.flatMap {
extractLanguageContainer(it["@id"] as String, it["name"]) languageContainer(it["@id"] as String, it["name"])
} }
} }
...@@ -152,10 +155,10 @@ object Extract { ...@@ -152,10 +155,10 @@ object Extract {
val creationRelationType = creationRelation["type"] as String val creationRelationType = creationRelation["type"] as String
if (creationRelationTypeParam != creationRelationType) return@mapNotNull null if (creationRelationTypeParam != creationRelationType) return@mapNotNull null
val name = creationRelation["name"] as String val name = creationRelation["name"] as String
val agent = getEntitiesFromIds("creationRelationHasTarget", creationRelation, input).first() val agent = Filter.entitiesByProperty("creationRelationHasTarget", creationRelation, input).first()
val agentType = agent["@type"] as String val agentType = agent["@type"] as String
if (agentType != agentTypeParam) return@mapNotNull null if (agentType != agentTypeParam) return@mapNotNull null
val agentName = extractLanguageContainer(agent["@id"] as String, agent["name"]) val agentName = languageContainer(agent["@id"] as String, agent["name"])
if (agentName.isEmpty()) { if (agentName.isEmpty()) {
log.error("Agent/Person/CorporateBody without rico:name found: ${agent["@id"]}.") log.error("Agent/Person/CorporateBody without rico:name found: ${agent["@id"]}.")
null null
...@@ -165,25 +168,6 @@ object Extract { ...@@ -165,25 +168,6 @@ object Extract {
} }
} }
fun getEntitiesFromIds(item: String, resource: JsonObject?, input: Map<String, JsonObject>): List<JsonObject> {
if (resource == null) return emptyList()
return resource[item].let {
if (it != null) {
when (it) {
is String -> listOf(input[it] as JsonObject)
is JsonObject -> listOf(input[it["@id"]] as JsonObject)
is JsonArray<*> ->
it.mapChildren { child ->
input[child["@id"]] }.filterNotNull()
else -> {
log.error("Could not parse $it to retrieve entities from input by id.")
emptyList()
}
}
} else emptyList()
}
}
fun listOfStrings(value: Any?): List<String> { fun listOfStrings(value: Any?): List<String> {
return when (value) { return when (value) {
is String -> listOf(value) is String -> listOf(value)
...@@ -196,17 +180,4 @@ object Extract { ...@@ -196,17 +180,4 @@ object Extract {
emptyList() emptyList()
} }
} }
fun carrierType(items: List<JsonObject>): List<NameContainer> {
return items.map {
listOfStrings(it["sameAs"]).let { value ->
val name = extractLanguageContainer("carrierType", it["name"]).reduce { acc, languageContainer -> acc.merge(languageContainer) }
if (value.isEmpty()) {
NameContainer(name, emptyList())
} else {
NameContainer(name, value)
}
}
}
}
} }
/*
* search-doc-service
* Copyright (C) 2020 Memoriav
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.memobase.helpers
import com.beust.klaxon.JsonArray
import com.beust.klaxon.JsonObject
import org.apache.logging.log4j.LogManager
object Filter {
private val log = LogManager.getLogger("SearchDocFilter")
/**
*
*
* @param sourceProperty
* @param sourceResource
* @param fullGraph
* @return The list of de-referenced JSON Objects.
*/
fun entitiesByProperty(sourceProperty: String, sourceResource: JsonObject?, fullGraph: Map<String, JsonObject>): List<JsonObject> {
if (sourceResource == null) {
log.info("No results collected from property $sourceProperty, because resource does not exist.")
return emptyList()
}
return sourceResource[sourceProperty].let {
when (it) {
is String -> listOf(fullGraph[it] as JsonObject)
is JsonObject -> listOf(fullGraph[it["@id"]] as JsonObject)
is JsonArray<*> ->
it.mapNotNull { child ->
when (child) {
is String -> fullGraph[child]
is JsonObject -> fullGraph[child["@id"]]
else -> null
}
}
null -> {
log.info("Property $sourceProperty is not defined in resource ${sourceResource["@id"]}.")
emptyList()
}
else -> {
log.error("Unexpected JSON structure for property $sourceProperty in resource ${sourceResource["@id"]}.")
emptyList()
}
}
}
}
}
...@@ -187,13 +187,13 @@ class Test { ...@@ -187,13 +187,13 @@ class Test {
1, 1,
"kafkaTest1.yml", "kafkaTest1.yml",
"key" "key"
)/*, ),
TestParam( TestParam(
"test-2", "test-2",
2, 2,
"kafkaTest1.yml", "kafkaTest1.yml",
"key" "key"
), )/*,
TestParam( TestParam(
"test-3", "test-3",
3, 3,
......
{"type":"Film","sourceID":"NoSourceIdFound","id":"https://memobase.ch/record/SFW-CJS_0451-4_d","abstract":[{"de":[],"fr":["Communiqué : <br> Pendant la Semaine Suisse un grand magasin de Zurich a consacré à l’aviation une exposition particulièrement bien documentée. <br> <br> Commentaire : <br> Pendant la Semaine Suisse, dans un grand magasin de Zurich une exposition aéronautique évoque les pionniers de notre aviation : le célèbre zinc de Dufaux, / un mémorable décollage de Taddeoli. / Ailleurs nos pilotes militaires, leurs avions et leur premier chef, / Oscar Bider, héros de la jeunesse, comme, plus tard, Walter Mittelholzer. / Une autre œuvre de pionnier : l’avion sans queue de Soldenhoff, le premier appareil de ce genre qui soit utilisable. / Le vol à voile est aussi représenté de façon captivante : un modèle sert à la démonstration des courants thermiques ascendants. / Rien ne manque dans cette exposition pas même une soufflerie. / Rarement tests aérodynamiques furent aussi éloquents. / Notre compagnie nationale d’aviation expose une maquette de sa plus récente acquisition, faite avec l’aide de la Confédération, et voici Kloten terminé, du moins en miniature. / <br> <br> <![CDATA[<a href=\"https://media.zem.ch/01WS/1950/Communique_0451.pdf\" target=\"_blank\">Communiqué_0451.pdf</a>]]>"],"it":[],"un":[]}],"descriptiveNote":[{"de":[],"fr":["Source à mentionner dans des citations et publications : <br> Archives fédérales suisses, J2.143#1996/386#451-2#4*, Ciné-Journal suisse du 03.11.1950, Les ailes (0451-4)"],"it":[],"un":[]}],"rightsHolder":[{"de":[],"fr":[],"it":[],"un":["Cinémathèque suisse, Archives fédérales suisses"]}],"sameAs":["https://www.recherche.bar.admin.ch/recherche/#/fr/recherche/plan-d-archivage/30689062"],"genre":[{"name":{"de":[],"fr":["Cinéjournal"],"it":[],"un":[]},"facet":["Cinéjournal"]}],"corporateBodyCreator":[{"name":{"de":[],"fr":["Ciné-Journal suisse (CJS)"],"it":[],"un":[]},"relation":"Autor"}],"placeRelated":[{"de":[],"fr":["Europe occidentale"],"it":[],"un":[]}],"placeCapture":[{"de":[],"fr":["Zürich, ZH (Schweiz)"],"it":[],"un":[]}],"place":[{"name":{"de":[],"fr":["Zürich, ZH (Schweiz)"],"it":[],"un":[]},"facet":["Zürich, ZH (Schweiz)"]},{"name":{"de":[],"fr":["Europe occidentale"],"it":[],"un":[]},"facet":["Europe occidentale"]}],"dateIssued":[{"date":"18570","facet":[]}],"institution":[{"name":{"de":["Institution"],"fr":["institution"],"it":["istituzione"],"un":[]},"facet":["https://memobase.ch/institution/MEMORIAV"]}],"recordSet":{"name":{"de":["Bestand"],"fr":["collection"],"it":["fondo"],"un":[]},"facet":["https://memobase.ch/recordSet/EXAMPLE"]},"memoriavClaim":true,"locator":["<![CDATA[https://media.zem.ch/01WS/1950/CJS_0451_d.mp4?start=249&end=320]]>"],"durationPhysical":["71"],"colourPhysical":[{"de":[],"fr":["NB"],"it":[],"un":[]}]} {"title":[{"de":[],"fr":["Les ailes (0451-4)"],"it":[],"un":[]}],"seriesTitle":[{"de":[],"fr":["Ciné-Journal suisse"],"it":[],"un":[]}],"broadcastTitle":[{"de":[],"fr":["Ciné-Journal suisse du 03.11.1950"],"it":[],"un":[]}],"type":"Film","sourceID":"CJS_0451-4_d","id":"https://memobase.ch/record/SFW-CJS_0451-4_d","abstract":[{"de":[],"fr":["Communiqué : <br> Pendant la Semaine Suisse un grand magasin de Zurich a consacré à l’aviation une exposition particulièrement bien documentée. <br> <br> Commentaire : <br> Pendant la Semaine Suisse, dans un grand magasin de Zurich une exposition aéronautique évoque les pionniers de notre aviation : le célèbre zinc de Dufaux, / un mémorable décollage de Taddeoli. / Ailleurs nos pilotes militaires, leurs avions et leur premier chef, / Oscar Bider, héros de la jeunesse, comme, plus tard, Walter Mittelholzer. / Une autre œuvre de pionnier : l’avion sans queue de Soldenhoff, le premier appareil de ce genre qui soit utilisable. / Le vol à voile est aussi représenté de façon captivante : un modèle sert à la démonstration des courants thermiques ascendants. / Rien ne manque dans cette exposition pas même une soufflerie. / Rarement tests aérodynamiques furent aussi éloquents. / Notre compagnie nationale d’aviation expose une maquette de sa plus récente acquisition, faite avec l’aide de la Confédération, et voici Kloten terminé, du moins en miniature. / <br> <br> <![CDATA[<a href=\"https://media.zem.ch/01WS/1950/Communique_0451.pdf\" target=\"_blank\">Communiqué_0451.pdf</a>]]>"],"it":[],"un":[]}],"descriptiveNote":[{"de":[],"fr":["Source à mentionner dans des citations et publications : <br> Archives fédérales suisses, J2.143#1996/386#451-2#4*, Ciné-Journal suisse du 03.11.1950, Les ailes (0451-4)"],"it":[],"un":[]}],"rightsHolder":[{"de":[],"fr":[],"it":[],"un":["Cinémathèque suisse, Archives fédérales suisses"]}],"sameAs":["https://www.recherche.bar.admin.ch/recherche/#/fr/recherche/plan-d-archivage/30689062"],"genre":[{"name":{"de":[],"fr":["Cinéjournal"],"it":[],"un":[]},"facet":["Cinéjournal"]}],"keywords":[{"name":{"de":[],"fr":["TRANSPORT, AVION"],"it":[],"un":[]},"facet":["TRANSPORT, AVION"]},{"name":{"de":[],"fr":["CULTURE, EXPOSITION"],"it":[],"un":[]},"facet":["CULTURE, EXPOSITION"]}],"languageContent":[{"de":[],"fr":["allemand"],"it":[],"un":[]}],"languageCaption":[{"de":[],"fr":["français"],"it":[],"un":[]}],"language":[{"name":{"de":[],"fr":["français"],"it":[],"un":[]},"facet":["français"]},{"name":{"de":[],"fr":["allemand"],"it":[],"un":[]},"facet":["allemand"]}],"corporateBodyCreator":[{"name":{"de":[],"fr":["Ciné-Journal suisse (CJS)"],"it":[],"un":[]},"relation":"Autor"}],"placeRelated":[{"de":[],"fr":["Europe occidentale"],"it":[],"un":[]}],"placeCapture":[{"de":[],"fr":["Zürich, ZH (Schweiz)"],"it":[],"un":[]}],"place":[{"name":{"de":[],"fr":["Zürich, ZH (Schweiz)"],"it":[],"un":[]},"facet":["Zürich, ZH (Schweiz)"]},{"name":{"de":[],"fr":["Europe occidentale"],"it":[],"un":[]},"facet":["Europe occidentale"]}],"dateIssued":[{"date":"18570","facet":[]}],"institution":[{"name":{"de":["Institution"],"fr":["institution"],"it":["istituzione"],"un":[]},"facet":["https://memobase.ch/institution/MEMORIAV"]}],"recordSet":{"name":{"de":["Bestand"],"fr":["collection"],"it":["fondo"],"un":[]},"facet":["https://memobase.ch/recordSet/EXAMPLE"]},"memoriavClaim":true,"locator":["<![CDATA[https://media.zem.ch/01WS/1950/CJS_0451_d.mp4?start=249&end=320]]>"],"accessDigital":["public"],"usageDigital":["http://rightsstatements.org/vocab/InC/1.0/"],"usageDigitalGroup":["Weiternutzbar unter Bedingungen (Copyright)"],"durationPhysical":["71"],"callNumber":["J2.143#1996/386#451-2#4*"],"colourPhysical":[{"de":[],"fr":["NB"],"it":[],"un":[]}],"format":[{"name":{"de":[],"fr":["nitrate de cellulose 35mm"],"it":[],"un":[]},"facet":[]},{"name":{"de":["35 mm Film"],"fr":[],"it":[],"un":[]},"facet":["http://www.wikidata.org/entity/Q226528"]}],"access":["public"]}
\ No newline at end of file \ No newline at end of file
{ {
"@context": {
"dc": "http://purl.org/dc/elements/1.1/",
"dct": "http://purl.org/dc/terms/",
"ebucore": "http://www.ebu.ch/metadata/ontologies/ebucore/ebucore#",
"rdau": "http://rdaregistry.info/Elements/u/",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"rico": "https://www.ica.org/standards/RiC/ontology#",
"schema": "http://schema.org/",
"skos": "http://www.w3.org/2004/02/skos/core#"
},
"@graph": [ "@graph": [
{ {
"@id": "https://memobase.ch/record/SFW-CGS_0641-6", "@id": "https://memobase.ch/instantiation/digital/SFW-SFW_0694-1-1",
"@type": "rico:Record", "@type": "https://www.ica.org/standards/RiC/ontology#Instantiation",
"dct:abstract": { "locator": "https://media.zem.ch/01WS/1955/SFW_0694.mp4?end=129",
"@language": "it", "identifiedBy": "https://memobase.ch/instantiation/digital/SFW-SFW_0694-1-1#genidea2c82a9-8671-4261-ac18-9128f6c06312",
"@value": "Comunicato: &lt;br&gt; Campionati estivi dell'esercito a Friburgo. &lt;br&gt; &lt;br&gt; Commento: &lt;br&gt; Campionati estivi dell’esercito a Friburgo: le cento migliori nostre pattuglie si sgranchiscono alla granata: primo esercizio dalla gara. / È la classica prova che riassume sul suo percorso tutte le difficoltà, come le fasi delle grammatiche: la licenza del grigioverde. Altro passaggio obbligato: valutare distanza in campagna posizione controsole proibiti strumenti. / La traduzione libera della corsa richiede spesso il dizionario dei tratti difficili./ Gli addetti militari stranieri s'allenano a stare assieme in previsione dell’esercito europeo: apprezzano le vaste conoscenze tecniche dei nostri soldati. / Dopo la marcia al compasso il tiro, sempre decisivo per la vittoria. / E infine, sulla scia dei garretti, un esercizio d’osservazione: inserire sello schizzo i bersagli individuati. / I volontari in grigioverde lottano fino all’ultima energia. Davanti ai 400 giovani e forti, l'on. Kobelt e il comandante di corpo Corbaz felicitano i fucilieri bernesi della II/29, vincitori! / &lt;br&gt; &lt;br&gt; <![CDATA[<a href=\"https://media.zem.ch/01WS/1954/Communique_0641.pdf\" target=\"_blank\">Communiqué_0641.pdf</a>]]>" "instantiates": "https://memobase.ch/record/SFW-SFW_0694-1",
}, "isDerivedFromInstantiation": "https://memobase.ch/instantiation/physical/SFW-SFW_0694-1-0",
"dct:spatial": { "regulatedBy": [
"@id": "_:Na47667314cf5471a85d513c4ca27fcbd" "https://memobase.ch/instantiation/digital/SFW-SFW_0694-1-1#genid34b5b56e-9735-46b1-a900-6c57538a5288",
}, "https://memobase.ch/instantiation/digital/SFW-SFW_0694-1-1#genid877bd6d8-4a4a-43df-9728-cd9d547e0f35"
"ebucore:hasGenre": { ],
"@id": "_:Na196ebb5c3ed4fac8702b66b291363ec" "type": "digitalObject"
}, },
"rdau:P60441": { {
"@id": "_:N67bb7a92e3ff4e0687f797358fb1d647" "@id": "https://memobase.ch/instantiation/digital/SFW-SFW_0694-1-1#genid34b5b56e-9735-46b1-a900-6c57538a5288",
"@type": "https://www.ica.org/standards/RiC/ontology#Rule",
"sameAs": "http://rightsstatements.org/vocab/InC/1.0/",
"name": "In Copyright (InC)",
"regulates": "https://memobase.ch/instantiation/digital/SFW-SFW_0694-1-1",
"type": "usage"
},
{
"@id": "https://memobase.ch/instantiation/digital/SFW-SFW_0694-1-1#genid877bd6d8-4a4a-43df-9728-cd9d547e0f35",
"@type": "https://www.ica.org/standards/RiC/ontology#Rule",
"name": "public",
"regulates": "https://memobase.ch/instantiation/digital/SFW-SFW_0694-1-1",
"type": "access"
},
{
"@id": "https://memobase.ch/instantiation/digital/SFW-SFW_0694-1-1#genidea2c82a9-8671-4261-ac18-9128f6c06312",
"@type": "https://www.ica.org/standards/RiC/ontology#Identifier",
"identifier": "https://memobase.ch/instantiation/digital/SFW-SFW_0694-1-1",
"type": "main"
},
{
"@id": "https://memobase.ch/instantiation/physical/SFW-SFW_0694-1-0",
"@type": "https://www.ica.org/standards/RiC/ontology#Instantiation",
"P60558": {
"@language": "de",
"@value": "SW"
}, },
"rdau:P60451": { "duration": "128",