Skip to content

Commit

Permalink
Merge branch 'rpb-46-anniversaries' of https://github.com/hbz/lobid-gnd
Browse files Browse the repository at this point in the history
… into rppd

Resolves #371 (RPB-46)

See https://rppd.lobid.org
  • Loading branch information
fsteeg committed Jan 15, 2024
2 parents a88209c + a973f2d commit cfafbe8
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 24 deletions.
147 changes: 139 additions & 8 deletions app/controllers/HomeController.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
Expand All @@ -37,6 +43,7 @@
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
Expand Down Expand Up @@ -101,8 +108,18 @@ public HomeController(WSClient httpClient) {
@Inject
IndexComponent index;

private Map<String, List<String>> anniversaries = new HashMap<>();

public static final Config CONFIG = ConfigFactory.load();

private static final List<Integer> ROUND_BIRTH = Arrays.asList(50, 70, 75, 100, 125, 150, 200,
250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, 1100,
1200, 1250, 1300, 1400, 1500, 1600, 1700, 1750, 1800, 1900, 2000);

private static final List<Integer> ROUND_DEATH = Arrays.asList(10, 25, 50, 75, 100, 125, 150,
200, 250, 300, 350, 400, 450, 500, 600, 700, 750, 800, 900, 950, 1000, 1100, 1200, 1250,
1300, 1400, 1500, 1600, 1700, 1750, 1800, 1900, 2000, 2100, 2200);

public static String config(String id) {
return CONFIG.getString(id);
}
Expand All @@ -125,19 +142,133 @@ public Result index() {
String queryString = String.format("depiction:* AND NOT gndIdentifier:(%s)",
CONFIG.getStringList("dontShowOnMainPage").stream()
.collect(Collectors.joining(" OR ")));
QueryStringQueryBuilder query = index.queryStringQuery(queryString);
FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(query,
ScoreFunctionBuilders.randomFunction(System.currentTimeMillis()));
SearchRequestBuilder requestBuilder = index.client().prepareSearch(config("index.prod.name"))
.setQuery(functionScoreQuery).setFrom(0).setSize(1);
SearchHits hits = requestBuilder.execute().actionGet().getHits();
QueryBuilder query = randomScoreQuery(index.queryStringQuery(queryString));
SearchHits hits = prepareSearch().setQuery(query).setFrom(0).setSize(1).execute()
.actionGet().getHits();
AuthorityResource entity = null;
if (hits.getTotalHits() > 0) {
SearchHit hit = hits.getAt(0);
entity = entityWithImage(hit.getSourceAsString());
}
JsonNode dataset = Json.parse(readFile(config("dataset.file")));
return ok(views.html.index.render(entity, dataset, allHits()));
return ok(views.html.index.render(entity, dataset, allAnniversaries(), allHits()));
}

private List<String> allAnniversaries() {
// starting with any anniversaries on this day, fill up
// (to 5 overall) with random anniversaries from this month,
// retaining order (today first) and avoiding duplicates:
int fullSize = 5;
List<String> anniversaries = anniversariesFor(thisDay());
if (anniversaries.size() < fullSize) {
List<String> thisMonth = anniversariesFor(thisMonth());
for (int i = 0; anniversaries.size() < fullSize && i < thisMonth.size(); i++) {
if (!anniversaries.contains(thisMonth.get(i))) {
anniversaries.add(thisMonth.get(i));
}
}
}
return anniversaries;
}

private List<String> anniversariesFor(String datePattern) {
// don't query on each reload...
List<String> result = anniversaries.computeIfAbsent(datePattern, list -> {
QueryBuilder query = randomScoreQuery(anniversaryQuery(datePattern));
SearchHits hits = prepareSearch().setQuery(query).setFrom(0).setSize((int) allHits())
.execute().actionGet().getHits();
return Arrays.asList(hits.getHits()).stream().filter(hit -> hasRound(datePattern, hit))
.map(hit -> hitToAnniversary(datePattern, hit)).collect(Collectors.toList());
});
// ...but provide new selection/subset
Collections.shuffle(result);
return result.stream().limit(5).collect(Collectors.toList());

}

private boolean hasRound(String datePattern, SearchHit hit) {
JsonNode json = Json.parse(hit.getSourceAsString());
JsonNode birthNode = json.get("dateOfBirth");
JsonNode deathNode = json.get("dateOfDeath");
return isRound(birthNode, ROUND_BIRTH, datePattern)
|| isRound(deathNode, ROUND_DEATH, datePattern);
}

private boolean isRound(JsonNode node, List<Integer> round, String datePattern) {
return node != null && is(datePattern, node.get(0).asText(), round);
}

private FunctionScoreQueryBuilder randomScoreQuery(QueryBuilder query) {
return QueryBuilders.functionScoreQuery(query,
ScoreFunctionBuilders.randomFunction(System.currentTimeMillis()));
}

private String hitToAnniversary(String datePattern, SearchHit hit) {
JsonNode fullJson = Json.parse("[" + hit.getSourceAsString() + "]");
JsonNode suggestion = Json
.parse(toSuggestions(fullJson,
"preferredName,dateOfBirth-dateOfDeath,professionOrOccupation"))
.elements().next();
JsonNode json = Json.toJson(ImmutableMap.of( //
"label", suggestion.get("label").asText(), //
"url", suggestion.get("id").asText().replace(AuthorityResource.GND_PREFIX, "/"), //
"details", details(datePattern, fullJson)));
return Json
.stringify(json);
}

private String details(String datePattern, JsonNode json) {
String details = "";
JsonNode dateOfBirth = json.findValue("dateOfBirth");
String date;
if (dateOfBirth != null
&& is(datePattern, date = dateOfBirth.get(0).asText(), ROUND_BIRTH)) {
details = String.format("%s. Geburtstag, geb. am %s", //
yearsSince(date), AuthorityResource.germanDate(date));
} else if (is(datePattern, date = json.findValue("dateOfDeath").get(0).asText(), ROUND_DEATH)) {
details = String.format("%s. Todestag, gest. am %s", //
yearsSince(date), AuthorityResource.germanDate(date));
}
return details;
}

private boolean is(String datePattern, String date, List<Integer> round) {
return date.contains(datePattern.replace("*", ""))
&& round.contains((int) yearsSince(date));
}

private SearchRequestBuilder prepareSearch() {
return index.client().prepareSearch(config("index.prod.name"));
}

private QueryStringQueryBuilder anniversaryQuery(String today) {
String queryString = String.format(
"(dateOfBirth:(%s) OR dateOfDeath:(%s)) AND NOT gndIdentifier:(%s) AND _exists_:dateOfDeath",
today, today,
CONFIG.getStringList("dontShowOnMainPage").stream()
.collect(Collectors.joining(" OR ")));
QueryStringQueryBuilder query = index.queryStringQuery(queryString);
return query;
}

private long yearsSince(String date) {
try {
int year = Integer.parseInt(AuthorityResource.cleanDate(date).substring(0, 4));
return ChronoUnit.YEARS.between( //
LocalDate.of(year, 1, 1), LocalDate.of(ZonedDateTime.now().getYear(), 1, 1));
} catch (DateTimeParseException e) {
e.printStackTrace();
return -1;
}
}

public static String thisDay() {
return ZonedDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE).replaceAll("\\d{4}",
"*"); // e.g return "*-01-09";
}

private static String thisMonth() {
return thisDay().replaceAll("\\d{2}$", "*"); // e.g. return "*-01-*";
}

/**
Expand Down Expand Up @@ -408,7 +539,7 @@ private Result jsonLines(String q, String filter, SearchResponse response) {
query = query.filter(index.queryStringQuery(filter));
}
TimeValue keepAlive = new TimeValue(60000);
SearchRequestBuilder scrollRequest = index.client().prepareSearch(config("index.prod.name"))
SearchRequestBuilder scrollRequest = prepareSearch()
.addSort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC).setScroll(keepAlive).setQuery(query)
.setSize(100 /* hits per shard for each scroll */);
Logger.debug("Scrolling with query: q={}, request={}", q, scrollRequest);
Expand Down
18 changes: 15 additions & 3 deletions app/models/AuthorityResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -491,9 +492,20 @@ private String process(String field, String value, String label, int i, int size
return withDefaultHidden(field, size, i, result);
}

private String germanDate(String value) {
return LocalDate.from(DateTimeFormatter.ISO_LOCAL_DATE.parse(value))
.format(DateTimeFormatter.ofPattern("dd.MM.uuuu", Locale.GERMAN));
public static String germanDate(String value) {
try {
return LocalDate
.from(DateTimeFormatter.ISO_LOCAL_DATE.parse(cleanDate(value)))
.format(DateTimeFormatter.ofPattern("dd.MM.uuuu", Locale.GERMAN));
} catch (DateTimeParseException e) {
e.printStackTrace();
return value;
}

}

public static String cleanDate(String value) {
return value.replaceAll(".*(\\d{4}-\\d{2}-\\d{2}).*", "$1");
}

private String withDefaultHidden(String field, int size, int i, String result) {
Expand Down
42 changes: 30 additions & 12 deletions app/views/index.scala.html
Original file line number Diff line number Diff line change
@@ -1,27 +1,45 @@
@* Copyright 2015-2018 Fabian Steeg, hbz. Licensed under the EPL 2.0 *@

@(entity: AuthorityResource, dataset: com.fasterxml.jackson.databind.JsonNode, allHits: Long)
@(entity: AuthorityResource, dataset: com.fasterxml.jackson.databind.JsonNode, anniversaries: List[String], allHits: Long)

@import helper._
@import controllers.HomeController.formatCount
@import controllers.HomeController.thisDay
@import play.api.libs.json._
@import controllers.HomeController.CONFIG

@main("", "RPPD", allHits) {
<div class="page-header">
<img class="media-object nrw-logo pull-right" src="@controllers.routes.Assets.versioned("images/wappen.png")" alt="NRW">
<h1>@dataset.get("alternateName").get("de").asText()<br/><small>@formatCount(allHits) Personen aus allen Wissensgebieten <span class="badge">beta</span></small></h1>
</div>
<div class="row">
<div class="col-md-@if(entity!=null){9}else{12} intro">
<p>
@Html(dataset.get("description").get("de").asText())
</p>
</div>
@if(entity!=null){<div class="col-md-3">
<figure>
<a href='@routes.HomeController.authority(entity.getId)'><img width="200px" id="index-image" src='https://lobid.org/[email protected]' alt="Darstellung von @entity.preferredName"/></a>
<figcaption><a href='@routes.HomeController.authority(entity.getId)'>@entity.preferredName</a><br/>@if(entity.imageAttribution!=null){<small>(@Html(entity.imageAttribution))</small>}</figcaption>
</figure>
</div>}
<div class="col-md-3">
<p><strong>Jubiläen</strong></p>
@for(resource <- anniversaries) {
<div>
<small>
@for(json <- Json.parse(resource).asOpt[JsValue];
label <- (json \ "label").asOpt[String];
details <- (json \ "details").asOpt[String];
url = (json \ "url").asOpt[String]) {
<a href="@url">@label</a>
<p>@details</p>
}
</small>
</div>
}
<p><a href='@routes.HomeController.search(date=thisDay)'>Aktuelle Jahrestage</a></p>
</div>
<div class="col-md-@if(entity!=null){6}else{9} intro">
@Html(dataset.get("description").get("de").asText())
</div>
@if(entity!=null){<div class="col-md-3">
<figure>
<a href='@routes.HomeController.authority(entity.getId)'><img width="200px" id="index-image" src='https://lobid.org/[email protected]' alt="Darstellung von @entity.preferredName"/></a>
<figcaption><a href='@routes.HomeController.authority(entity.getId)'>@entity.preferredName</a><br/>@if(entity.imageAttribution!=null){<small>(@Html(entity.imageAttribution))</small>}</figcaption>
</figure>
</div>}
</div>
<script type="application/ld+json">
{
Expand Down
2 changes: 1 addition & 1 deletion public/stylesheets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ h1 small .label {
figure {
display: table;
float: right;
margin-top: 10px;
margin-top: 5px;
}

figcaption {
Expand Down
1 change: 1 addition & 0 deletions transformAndIndexRppd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ cd ../rpb
bash transformRppd.sh
cd -
sbt "runMain apps.Index baseline"
curl -S -s -o /dev/null https://rppd.lobid.org

0 comments on commit cfafbe8

Please sign in to comment.