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

Implements person facet builder.

parent 105918af
/*
* 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
object KEYS {
const val atType = "@type"
const val ricoType = "type"
const val firstName = "firstName"
const val lastName = "lastName"
const val name = "name"
const val agentIsTargetOfCreationRelation = "agentIsTargetOfCreationRelation"
const val contributor = "contributor"
const val creator = "creator"
const val Person = "Person"
const val Instantiation = "Instantiation"
}
/*
* 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.builders
import com.beust.klaxon.JsonObject
interface IFieldBuilder {
fun filter(jsonObject: JsonObject, map: Map<String, JsonObject>): Boolean
fun append(jsonObject: JsonObject): String
fun build(): List<String>
}
/*
* 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.builders
import com.beust.klaxon.JsonObject
import org.memobase.KEYS
import org.memobase.helpers.AsciiFolder
import org.memobase.helpers.Extract
import org.memobase.rdf.NS
class PersonFacetBuilder(private val ricoType: String) : IFieldBuilder {
private val separator = "~"
private val terminator = "#"
private val level1 = "0"
private val level2 = "1"
private val isAlphaChar = Regex("[A-Za-z]")
private val personFacetValues = mutableSetOf<String>()
override fun filter(jsonObject: JsonObject, map: Map<String, JsonObject>): Boolean {
return if (jsonObject[KEYS.atType].let {
when (it) {
is String -> it == NS.rico + KEYS.Person
else -> false
}
}) {
val ids = Extract.identifier(jsonObject[KEYS.agentIsTargetOfCreationRelation])
ids
.map { map[it] }
.map { it?.get(KEYS.ricoType) }
.any { it != null && it is String && it == ricoType }
} else {
false
}
}
override fun append(jsonObject: JsonObject): String {
val name = when {
jsonObject.containsKey("lastName") -> {
jsonObject["lastName"] as String
}
jsonObject.containsKey("name") -> {
jsonObject["name"] as String
}
else -> {
return "Failed to process person ${jsonObject["@id"]} for person facet, because the person does not have a name."
}
}
val displayName = jsonObject["lastName"].let { lastName ->
when (lastName) {
is String -> lastName + jsonObject["firstName"].let { if (it is String) ", $it" else "" }
else -> jsonObject["name"]
}
}
val foldedName = AsciiFolder.foldToASCII(name)
val firstChar = foldedName.first { isAlphaChar.matches(it.toString()) }
val capitalLetter = firstChar.toUpperCase()
personFacetValues.add("$level1$separator$capitalLetter$separator$terminator")
personFacetValues.add("$level2$separator$capitalLetter$separator$displayName$separator$terminator")
return "Successfully added person to facet list."
}
override fun build(): List<String> {
return personFacetValues.toList().sortedBy { v -> v.substring(2) }
}
}
This diff is collapsed.
......@@ -18,6 +18,7 @@
package org.memobase.helpers
import com.beust.klaxon.JsonArray
import com.beust.klaxon.JsonObject
import org.apache.logging.log4j.LogManager
import org.memobase.model.CreatorNameContainer
......@@ -186,4 +187,24 @@ object Extract {
emptyList()
}
}
fun identifier(value: Any?): List<String> {
return when (value) {
is String -> listOf(value)
is JsonObject -> value["@id"].let { if (it is String) listOf(it) else emptyList() }
is JsonArray<*> ->
value.mapNotNull { item ->
when (item) {
is String -> item
is JsonObject -> value["@id"].let { id: Any? ->
if (id is String)
id
else null
}
else -> null
}
}
else -> emptyList()
}
}
}
......@@ -29,7 +29,7 @@ import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.memobase.helpers.DateFacetBuilder
import org.memobase.params.TestParam
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class Test {
......@@ -40,123 +40,6 @@ class Test {
return File("$resourcePath/$fileName").readText(Charset.defaultCharset())
}
@ParameterizedTest
@MethodSource("testDates")
fun `test date facet`(date: TestDate) {
val result = when (date.type) {
"single" ->
DateFacetBuilder.buildFromNormalizedSingleDate(date.date)
"range" ->
DateFacetBuilder.buildFromNormalizedDateRange(date.date)
else ->
emptyList()
}
assertThat(result)
.isEqualTo(date.result)
}
private fun testDates() = Stream.of(
TestDate(
"1921-09-14",
"single",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921/1922",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921-05-01/02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921-05-01/06-02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921/1931",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#", "1~20.Jahrhundert~1931-1940~#")
),
TestDate(
"1921-04-01/1931-05-02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#", "1~20.Jahrhundert~1931-1940~#")
),
TestDate(
"1921/1951",
"range",
listOf(
"0~20.Jahrhundert~",
"1~20.Jahrhundert~1921-1930~#",
"1~20.Jahrhundert~1931-1940~#",
"1~20.Jahrhundert~1941-1950~#",
"1~20.Jahrhundert~1951-1960~#"
)
),
TestDate(
"1721/1951",
"range",
listOf(
"0~18.Jahrhundert~",
"0~19.Jahrhundert~",
"0~20.Jahrhundert~",
"1~18.Jahrhundert~1721-1730~#",
"1~18.Jahrhundert~1731-1740~#",
"1~18.Jahrhundert~1741-1750~#",
"1~18.Jahrhundert~1751-1760~#",
"1~18.Jahrhundert~1761-1770~#",
"1~18.Jahrhundert~1771-1780~#",
"1~18.Jahrhundert~1781-1790~#",
"1~18.Jahrhundert~1791-1800~#",
"1~19.Jahrhundert~1801-1810~#",
"1~19.Jahrhundert~1811-1820~#",
"1~19.Jahrhundert~1821-1830~#",
"1~19.Jahrhundert~1831-1840~#",
"1~19.Jahrhundert~1841-1850~#",
"1~19.Jahrhundert~1851-1860~#",
"1~19.Jahrhundert~1861-1870~#",
"1~19.Jahrhundert~1871-1880~#",
"1~19.Jahrhundert~1881-1890~#",
"1~19.Jahrhundert~1891-1900~#",
"1~20.Jahrhundert~1901-1910~#",
"1~20.Jahrhundert~1911-1920~#",
"1~20.Jahrhundert~1921-1930~#",
"1~20.Jahrhundert~1931-1940~#",
"1~20.Jahrhundert~1941-1950~#",
"1~20.Jahrhundert~1951-1960~#"
)
),
TestDate(
"1721/1822",
"range",
listOf(
"0~18.Jahrhundert~",
"0~19.Jahrhundert~",
"1~18.Jahrhundert~1721-1730~#",
"1~18.Jahrhundert~1731-1740~#",
"1~18.Jahrhundert~1741-1750~#",
"1~18.Jahrhundert~1751-1760~#",
"1~18.Jahrhundert~1761-1770~#",
"1~18.Jahrhundert~1771-1780~#",
"1~18.Jahrhundert~1781-1790~#",
"1~18.Jahrhundert~1791-1800~#",
"1~19.Jahrhundert~1801-1810~#",
"1~19.Jahrhundert~1811-1820~#",
"1~19.Jahrhundert~1821-1830~#"
)
)
)
@ParameterizedTest
@MethodSource("testParams")
fun `integration tests`(params: TestParam) {
......
/*
* 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
import com.beust.klaxon.json
import java.util.stream.Stream
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.assertAll
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import org.memobase.builders.PersonFacetBuilder
import org.memobase.helpers.DateFacetBuilder
import org.memobase.params.PersonFacetBuilderParams
import org.memobase.params.TestDate
import org.memobase.rdf.NS
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TestFacetBuilders {
@ParameterizedTest
@MethodSource("testPersons")
fun `test person facet builder`(params: PersonFacetBuilderParams) {
val builder = PersonFacetBuilder(params.ricoType)
if (builder.filter(params.source, params.map)) {
val log = builder.append(params.source)
val result = builder.build()
assertAll("",
{ assertThat(log).isEqualTo(params.log) },
{ assertThat(params.result).containsAll(result) }
)
} else {
assertThat(params.source)
.hasEntrySatisfying("@type") { value -> value.let { if (it is String) NS.rico + "Person" == it else false } }
}
}
private fun testPersons() = Stream.of(
PersonFacetBuilderParams(
json { obj(Pair("@type", NS.rico + "Record")) },
mapOf(),
"",
"",
emptyList()
),
PersonFacetBuilderParams(
json {
obj(
Pair(KEYS.atType, NS.rico + "Person"),
Pair(KEYS.name, "Einstein, Albert"),
Pair(KEYS.agentIsTargetOfCreationRelation, "identifier")
)
},
mapOf(Pair("identifier", json { obj(Pair(KEYS.ricoType, KEYS.creator)) })),
KEYS.creator,
"Successfully added person to facet list.",
listOf(
"0~E~#",
"1~E~Einstein, Albert~#"
)
),
PersonFacetBuilderParams(
json {
obj(
Pair("@type", NS.rico + "Person"),
Pair(KEYS.name, "Albert Einstein"),
Pair(KEYS.lastName, "Einstein"),
Pair(KEYS.agentIsTargetOfCreationRelation, "identifier")
)
},
mapOf(Pair("identifier", json { obj(Pair(KEYS.ricoType, KEYS.contributor)) })),
KEYS.contributor,
"Successfully added person to facet list.",
listOf(
"0~E~#",
"1~E~Einstein~#"
)
)
)
@Test
fun `test multiple person facet builder`() {
val builder = PersonFacetBuilder("creator")
builder.append(json {
obj(
Pair(KEYS.atType, NS.rico + "Person"),
Pair(KEYS.name, "Einstein, Albert"),
Pair(KEYS.agentIsTargetOfCreationRelation, "identifier")
)
})
builder.append(json {
obj(
Pair(KEYS.atType, NS.rico + "Person"),
Pair(KEYS.name, "Albert, Einstein"),
Pair(KEYS.agentIsTargetOfCreationRelation, "identifier")
)
})
val result = builder.build()
assertThat(result)
.isSortedAccordingTo { s, s2 -> s.substring(2).compareTo(s2.substring(2)) }
.containsAll(
listOf(
"0~A~#", "1~A~Albert, Einstein~#", "0~E~#", "1~E~Einstein, Albert~#"
)
)
}
@ParameterizedTest
@MethodSource("testDates")
fun `test date facet`(date: TestDate) {
val result = when (date.type) {
"single" ->
DateFacetBuilder.buildFromNormalizedSingleDate(date.date)
"range" ->
DateFacetBuilder.buildFromNormalizedDateRange(date.date)
else ->
emptyList()
}
Assertions.assertThat(result)
.isEqualTo(date.result)
}
private fun testDates() = Stream.of(
TestDate(
"1921-09-14",
"single",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921/1922",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921-05-01/02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921-05-01/06-02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#")
),
TestDate(
"1921/1931",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#", "1~20.Jahrhundert~1931-1940~#")
),
TestDate(
"1921-04-01/1931-05-02",
"range",
listOf("0~20.Jahrhundert~", "1~20.Jahrhundert~1921-1930~#", "1~20.Jahrhundert~1931-1940~#")
),
TestDate(
"1921/1951",
"range",
listOf(
"0~20.Jahrhundert~",
"1~20.Jahrhundert~1921-1930~#",
"1~20.Jahrhundert~1931-1940~#",
"1~20.Jahrhundert~1941-1950~#",
"1~20.Jahrhundert~1951-1960~#"
)
),
TestDate(
"1721/1951",
"range",
listOf(
"0~18.Jahrhundert~",
"0~19.Jahrhundert~",
"0~20.Jahrhundert~",
"1~18.Jahrhundert~1721-1730~#",
"1~18.Jahrhundert~1731-1740~#",
"1~18.Jahrhundert~1741-1750~#",
"1~18.Jahrhundert~1751-1760~#",
"1~18.Jahrhundert~1761-1770~#",
"1~18.Jahrhundert~1771-1780~#",
"1~18.Jahrhundert~1781-1790~#",
"1~18.Jahrhundert~1791-1800~#",
"1~19.Jahrhundert~1801-1810~#",
"1~19.Jahrhundert~1811-1820~#",
"1~19.Jahrhundert~1821-1830~#",
"1~19.Jahrhundert~1831-1840~#",
"1~19.Jahrhundert~1841-1850~#",
"1~19.Jahrhundert~1851-1860~#",
"1~19.Jahrhundert~1861-1870~#",
"1~19.Jahrhundert~1871-1880~#",
"1~19.Jahrhundert~1881-1890~#",
"1~19.Jahrhundert~1891-1900~#",
"1~20.Jahrhundert~1901-1910~#",
"1~20.Jahrhundert~1911-1920~#",
"1~20.Jahrhundert~1921-1930~#",
"1~20.Jahrhundert~1931-1940~#",
"1~20.Jahrhundert~1941-1950~#",
"1~20.Jahrhundert~1951-1960~#"
)
),
TestDate(
"1721/1822",
"range",
listOf(
"0~18.Jahrhundert~",
"0~19.Jahrhundert~",
"1~18.Jahrhundert~1721-1730~#",
"1~18.Jahrhundert~1731-1740~#",
"1~18.Jahrhundert~1741-1750~#",
"1~18.Jahrhundert~1751-1760~#",
"1~18.Jahrhundert~1761-1770~#",
"1~18.Jahrhundert~1771-1780~#",
"1~18.Jahrhundert~1781-1790~#",
"1~18.Jahrhundert~1791-1800~#",
"1~19.Jahrhundert~1801-1810~#",
"1~19.Jahrhundert~1811-1820~#",
"1~19.Jahrhundert~1821-1830~#"
)
)
)
}
/*
* 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.params
import com.beust.klaxon.JsonObject
data class PersonFacetBuilderParams(
val source: JsonObject,
val map: Map<String, JsonObject>,
val ricoType: String,
val log: String,
val result: List<String>
)
......@@ -15,7 +15,7 @@
* 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
package org.memobase.params
data class TestDate(
val date: String,
......
......@@ -15,7 +15,7 @@
* 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
package org.memobase.params
data class TestParam(
val name: String,
......