InstitutionSearchDocBuilder.kt 6.68 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 * 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

Jonas Waeber's avatar
Jonas Waeber committed
21
import ch.memobase.rdf.MB
22
import ch.memobase.rdf.NS
23
import com.beust.klaxon.JsonArray
24
25
import com.beust.klaxon.JsonObject
import org.apache.logging.log4j.LogManager
26
import org.memobase.helpers.Date
27
import org.memobase.helpers.ElasticSearchWrapper
28
import org.memobase.helpers.Extract
Jonas Waeber's avatar
Jonas Waeber committed
29
import org.memobase.helpers.Constants
30
import org.memobase.helpers.JsonUtility
31
import org.memobase.helpers.TranslationMappers
Jonas Waeber's avatar
Jonas Waeber committed
32
import org.memobase.model.FacetContainer
33
34
35
import org.memobase.model.InstitutionSearchDoc
import org.memobase.model.LanguageContainer
import org.memobase.model.Schema
36

37

38
39
40
41
class InstitutionSearchDocBuilder(
    private val translationMappers: TranslationMappers,
    private val elasticSearchWrapper: ElasticSearchWrapper
) {
42
43
    private val log = LogManager.getLogger("InstitutionSearchDocBuilder")

44
    fun transform(key: String, input: Map<String, JsonObject>): Schema {
45
        val institution =
46
            input[JsonUtility.institutionTag] ?: throw InvalidInputException("No institution entity found in message $key.")
47
        val identifiers = mutableListOf<JsonObject>()
Jonas Waeber's avatar
Jonas Waeber committed
48
        val cantons = mutableListOf<FacetContainer>()
49
50
51
        val municipalities = mutableListOf<LanguageContainer>()
        val addresses = mutableListOf<String>()
        val postalCodes = mutableListOf<String>()
52

53
        input.values.forEach {
54
            when {
Jonas Waeber's avatar
Jonas Waeber committed
55
                it[Constants.ricoType] == Constants.LocationType.canton -> {
Jonas Waeber's avatar
Jonas Waeber committed
56
                    cantons.add(FacetContainer(extractAdminUnit(it, "canton", "NoCantonFound"), null, emptyList()))
57
                }
Jonas Waeber's avatar
Jonas Waeber committed
58
                it[Constants.ricoType] == Constants.LocationType.municipality -> {
59
60
                    municipalities.add(extractAdminUnit(it, "municipality", "NoCityFound"))
                }
Jonas Waeber's avatar
Jonas Waeber committed
61
                it[Constants.ricoType] == Constants.IdentifierType.main -> {
62
63
                    identifiers.add(it)
                }
Jonas Waeber's avatar
Jonas Waeber committed
64
65
66
                it[Constants.atType] == NS.rico + Constants.Place -> {
                    addresses.addAll(Extract.listOfStrings(it[Constants.wikidataAddresses]))
                    postalCodes.addAll(Extract.listOfStrings(it[Constants.wikidataPostalCodes]))
67
                }
68
69
            }
        }
70

Jonas Waeber's avatar
Jonas Waeber committed
71
        val type = institution[Constants.wikidataInstance].let {
72
            when (it) {
73
74
                is String -> listOf(translationMappers.getInstitutionType(it))
                is JsonArray<*> -> it.map { any -> translationMappers.getInstitutionType(any as String) }
75
76
77
78
79
80
81
                else -> {
                    log.error("Found no institution types on institution $key")
                    emptyList()
                }
            }
        }

Jonas Waeber's avatar
Jonas Waeber committed
82
83
84
85
        val name = extractLanguageContainer(institution[Constants.name], "NoNameFound")
        val description = extractLanguageContainer(institution[Constants.descriptiveNote], "NoDescriptionFound")
        val id = Extract.extractIdValue(identifiers, Constants.IdentifierType.main) ?: "NoIdentifierFound"
        val recordSetUris = Extract.listOfStrings(institution[Constants.isHolderOf])
86
        val recordSetIds = recordSetUris.map { it.substringAfterLast("/") }
87

88
        return InstitutionSearchDoc(
89
            institutionId = id,
Jonas Waeber's avatar
Jonas Waeber committed
90
            published = institution[Constants.isPublished].let {
91
                when (it) {
Jonas Waeber's avatar
Jonas Waeber committed
92
                    is Boolean -> it
93
94
95
96
                    is String -> it.toBoolean()
                    else -> {
                        log.error("Found no isPublished property on institution $key. Set to false.")
                        false
97
                    }
98
99
100
101
102
                }
            },
            type = type,
            name = name,
            description = description,
Jonas Waeber's avatar
Jonas Waeber committed
103
104
105
            documentType = recordSetIds.flatMap {
                elasticSearchWrapper.getDocumentTypesFromRecords(
                    it,
Jonas Waeber's avatar
Jonas Waeber committed
106
                    Constants.QueryFields.recordSetFacet
Jonas Waeber's avatar
Jonas Waeber committed
107
108
                )
            }.distinctBy { it.filter },
Jonas Waeber's avatar
Jonas Waeber committed
109
            keyVisualLink = institution[Constants.wikidataImage].let { if (it != null) it as String else "NoKeyVisualLinkDefined" },
110
111
112
113
114
115
116
117
            canton = cantons,
            city = municipalities,
            address = addresses,
            postalCodes = postalCodes,
            numberOfRecordSets = recordSetIds.count(),
            numberOfDocuments = recordSetIds
                .map { value -> elasticSearchWrapper.countNumberOfDocuments(value) }
                .sum(),
Jonas Waeber's avatar
Jonas Waeber committed
118
            teaserColor = institution[MB.institutionTeaserColor.localName].let {
119
                if (it == null) {
Jonas Waeber's avatar
Jonas Waeber committed
120
                    log.warn("No teaser colour found for institution $id.")
121
122
123
124
                    ""
                } else
                    it as String
            },
Jonas Waeber's avatar
Jonas Waeber committed
125
            teaserColorComputed = institution[MB.institutionComputedTeaserColor.localName].let {
126
                if (it == null) {
Jonas Waeber's avatar
Jonas Waeber committed
127
                    log.warn("No computed teaser colour found for institution $id.")
128
129
130
131
132
                    ""
                } else
                    it as String
            },
            lastUpdatedDate = Date.now
133
134
        )
    }
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

    private fun extractLanguageContainer(value: Any?, placeholder: String): LanguageContainer {
        return Extract.languageContainer("institution", value).let { items ->
            when {
                items.isEmpty() -> {
                    LanguageContainer.placeholder(placeholder)
                }
                items.size == 1 -> {
                    items[0]
                }
                else -> {
                    items.reduce { acc, languageContainer -> acc.merge(languageContainer) }
                }
            }
        }
    }

    private fun extractAdminUnit(item: JsonObject, parent: String, placeholder: String): LanguageContainer {
Jonas Waeber's avatar
Jonas Waeber committed
153
        return item[Constants.name].let { name ->
154
155
156
157
158
159
160
161
            Extract.languageContainer(parent, name).let {
                when {
                    it.isEmpty() -> LanguageContainer.placeholder(placeholder)
                    else -> it.reduce { acc, languageContainer -> acc.merge(languageContainer) }
                }
            }
        }
    }
162
}