diff --git a/search-commons/src/main/java/no/unit/nva/search/constants/ApplicationConstants.java b/search-commons/src/main/java/no/unit/nva/search/constants/ApplicationConstants.java index a246cba64..459715db0 100644 --- a/search-commons/src/main/java/no/unit/nva/search/constants/ApplicationConstants.java +++ b/search-commons/src/main/java/no/unit/nva/search/constants/ApplicationConstants.java @@ -1,5 +1,6 @@ package no.unit.nva.search.constants; +import static no.unit.nva.search2.constant.Words.FUNDING_SOURCE; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; import java.util.stream.Stream; @@ -41,20 +42,19 @@ public final class ApplicationConstants { public static final int DEFAULT_AGGREGATION_SIZE = 100; public static final List>> IMPORT_CANDIDATES_AGGREGATIONS = List.of( - generateSimpleAggregation("importStatus.candidateStatus", - "importStatus.candidateStatus.keyword"), + generateSimpleAggregation("importStatus.candidateStatus", "importStatus.candidateStatus.keyword"), generateSimpleAggregation("publicationYear", "publicationYear.keyword"), generateObjectLabelsAggregation("organizations"), generateHasFileAggregation(), - generateInstanceTypeAggregation(), + generateSimpleAggregation("instanceType", "publicationInstance.type"), generateSimpleAggregation("collaborationType", "collaborationType.keyword"), generateImportedByUserAggregation() ); - public static final TermsAggregationBuilder TYPE_TERMS_AGGREGATION = generateSimpleAggregation("type", - "type.keyword"); - public static final TermsAggregationBuilder STATUS_TERMS_AGGREGATION = generateSimpleAggregation("status", - "status.keyword"); + public static final TermsAggregationBuilder TYPE_TERMS_AGGREGATION = + generateSimpleAggregation("type", "type.keyword"); + public static final TermsAggregationBuilder STATUS_TERMS_AGGREGATION = + generateSimpleAggregation("status", "status.keyword"); public static final List>> TICKETS_AGGREGATIONS = List.of(TYPE_TERMS_AGGREGATION, STATUS_TERMS_AGGREGATION @@ -82,7 +82,8 @@ public final class ApplicationConstants { generateSimpleAggregation("resourceOwner.ownerAffiliation", "resourceOwner.ownerAffiliation.keyword"), generateEntityDescriptionAggregation(), - generateFundingSourceAggregation(), + generateSimpleAggregation(FUNDING_SOURCE, jsonPath(FUNDINGS, SOURCE, IDENTIFIER)) + .subAggregation(generateLabelsAggregation(jsonPath(FUNDINGS, SOURCE))), generateHasFileAggregation(), generateObjectLabelsAggregation(TOP_LEVEL_ORGANIZATIONS) ); @@ -101,18 +102,18 @@ private static String readSearchInfrastructureAuthUri() { private static TermsAggregationBuilder generateSimpleAggregation(String term, String field) { return AggregationBuilders - .terms(term) - .field(field) - .size(DEFAULT_AGGREGATION_SIZE); + .terms(term) + .field(field) + .size(DEFAULT_AGGREGATION_SIZE); } private static FilterAggregationBuilder generateImportedByUserAggregation() { return new FilterAggregationBuilder( "importedByUser", new TermQueryBuilder("importStatus.candidateStatus.keyword", "IMPORTED")) - .subAggregation(AggregationBuilders - .terms("importStatus.setBy") - .field("importStatus.setBy.keyword") - .size(DEFAULT_AGGREGATION_SIZE)); + .subAggregation(AggregationBuilders + .terms("importStatus.setBy") + .field("importStatus.setBy.keyword") + .size(DEFAULT_AGGREGATION_SIZE)); } private static NestedAggregationBuilder generateReferenceAggregation() { @@ -129,7 +130,7 @@ private static NestedAggregationBuilder generateReferenceAggregation() { private static TermsAggregationBuilder generatePublicationInstanceTypeAggregation() { return generateSimpleAggregation( - TYPE, jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_INSTANCE, TYPE, KEYWORD)); + TYPE, jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_INSTANCE, TYPE)); } private static NestedAggregationBuilder generateNestedPublicationInstanceAggregation() { @@ -144,22 +145,22 @@ private static NestedAggregationBuilder generateNestedPublicationContextAggregat private static TermsAggregationBuilder generatePublicationContextPublisherIdAggregation() { return generateSimpleAggregation( - PUBLISHER, jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, PUBLISHER, IDENTIFIER, KEYWORD)); + PUBLISHER, jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, PUBLISHER, IDENTIFIER)); } private static TermsAggregationBuilder generatePublicationContextPublisherNameAggregation() { return generateSimpleAggregation( - NAME, jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, PUBLISHER, NAME, KEYWORD)); + NAME, jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, PUBLISHER, NAME)); } private static TermsAggregationBuilder generatePublicationContextJournalIdAggregation() { return generateSimpleAggregation( - ID, jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, IDENTIFIER, KEYWORD)); + ID, jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, IDENTIFIER)); } private static TermsAggregationBuilder generatePublicationContextJournalNameAggregation() { return generateSimpleAggregation( - NAME, jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, NAME, KEYWORD)); + NAME, jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, NAME)); } private static NestedAggregationBuilder generateEntityDescriptionAggregation() { @@ -168,28 +169,12 @@ private static NestedAggregationBuilder generateEntityDescriptionAggregation() { .subAggregation(generateReferenceAggregation()); } - private static TermsAggregationBuilder generateInstanceTypeAggregation() { - return generateSimpleAggregation(TYPE, jsonPath(PUBLICATION_INSTANCE, TYPE)); - } - - private static NestedAggregationBuilder generateFundingSourceAggregation() { - return - new NestedAggregationBuilder(FUNDINGS, FUNDINGS) - .subAggregation( - generateSimpleAggregation(IDENTIFIER, jsonPath(FUNDINGS, SOURCE, IDENTIFIER, KEYWORD)) - .subAggregation( - generateLabelsAggregation(jsonPath(FUNDINGS, SOURCE))) - ); - } - private static NestedAggregationBuilder generateContributorAggregations() { return generateNestedContributorAggregation() - .subAggregation( - generateNestedIdentityAggregation() - .subAggregation( - generateIdAggregation() - .subAggregation(generateNameAggregation())) + .subAggregation(generateNestedIdentityAggregation() + .subAggregation(generateIdAggregation() + .subAggregation(generateNameAggregation())) ); } @@ -202,12 +187,12 @@ private static NestedAggregationBuilder generateNestedIdentityAggregation() { } private static TermsAggregationBuilder generateIdAggregation() { - return generateSimpleAggregation(ID, jsonPath(ENTITY_DESCRIPTION, CONTRIBUTORS, IDENTITY, ID, KEYWORD)); + return generateSimpleAggregation(ID, jsonPath(ENTITY_DESCRIPTION, CONTRIBUTORS, IDENTITY, ID)); } private static TermsAggregationBuilder generateIdAggregation(String object) { return new TermsAggregationBuilder(ID) - .field(jsonPath(object, ID, KEYWORD)) + .field(jsonPath(object, ID)) .size(DEFAULT_AGGREGATION_SIZE) .subAggregation(generateLabelsAggregation(object)); } diff --git a/search-commons/src/main/java/no/unit/nva/search2/ImportCandidateClient.java b/search-commons/src/main/java/no/unit/nva/search2/ImportCandidateClient.java index 3263ed91f..de39eda76 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/ImportCandidateClient.java +++ b/search-commons/src/main/java/no/unit/nva/search2/ImportCandidateClient.java @@ -13,15 +13,15 @@ import java.net.http.HttpResponse.BodyHandler; import java.nio.charset.StandardCharsets; import no.unit.nva.search.CachedJwtProvider; -import no.unit.nva.search2.model.OpenSearchClient; -import no.unit.nva.search2.model.OpenSearchSwsResponse; -import no.unit.nva.search2.model.QueryBuilderSourceWrapper; +import no.unit.nva.search2.common.OpenSearchClient; +import no.unit.nva.search2.common.QueryContentWrapper; +import no.unit.nva.search2.common.SwsResponse; import nva.commons.core.JacocoGenerated; import nva.commons.secrets.SecretsReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ImportCandidateClient implements OpenSearchClient { +public class ImportCandidateClient extends OpenSearchClient { private static final Logger logger = LoggerFactory.getLogger(ImportCandidateClient.class); @@ -45,7 +45,7 @@ public static ImportCandidateClient defaultClient() { } @Override - public OpenSearchSwsResponse doSearch(ImportCandidateQuery query) { + public SwsResponse doSearch(ImportCandidateQuery query) { return query.createQueryBuilderStream() .map(this::createRequest) @@ -55,7 +55,7 @@ public OpenSearchSwsResponse doSearch(ImportCandidateQuery query) { } @JacocoGenerated - private HttpRequest createRequest(QueryBuilderSourceWrapper qbs) { + private HttpRequest createRequest(QueryContentWrapper qbs) { logger.info(qbs.source().query().toString()); return HttpRequest .newBuilder(qbs.requestUri()) @@ -71,11 +71,11 @@ private HttpResponse fetch(HttpRequest httpRequest) { } @JacocoGenerated - private OpenSearchSwsResponse handleResponse(HttpResponse response) { + private SwsResponse handleResponse(HttpResponse response) { if (response.statusCode() != HTTP_OK) { throw new RuntimeException(response.body()); } - return attempt(() -> singleLineObjectMapper.readValue(response.body(), OpenSearchSwsResponse.class)) + return attempt(() -> singleLineObjectMapper.readValue(response.body(), SwsResponse.class)) .orElseThrow(); } } diff --git a/search-commons/src/main/java/no/unit/nva/search2/ImportCandidateQuery.java b/search-commons/src/main/java/no/unit/nva/search2/ImportCandidateQuery.java index e51779a15..e60978773 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/ImportCandidateQuery.java +++ b/search-commons/src/main/java/no/unit/nva/search2/ImportCandidateQuery.java @@ -2,226 +2,174 @@ import static java.util.Objects.isNull; import static java.util.Objects.nonNull; -import static no.unit.nva.search.constants.ApplicationConstants.IMPORT_CANDIDATES_AGGREGATIONS; -import static no.unit.nva.search.constants.ApplicationConstants.IMPORT_CANDIDATES_INDEX; -import static no.unit.nva.search2.constant.ApplicationConstants.COLON; -import static no.unit.nva.search2.constant.ApplicationConstants.COMMA; -import static no.unit.nva.search2.constant.ApplicationConstants.SEARCH; -import static no.unit.nva.search2.constant.ApplicationConstants.ZERO; +import static no.unit.nva.search2.constant.Defaults.DEFAULT_IMPORT_CANDIDATE_SORT; import static no.unit.nva.search2.constant.Defaults.DEFAULT_OFFSET; +import static no.unit.nva.search2.constant.Defaults.DEFAULT_SORT_ORDER; import static no.unit.nva.search2.constant.Defaults.DEFAULT_VALUE_PER_PAGE; -import static no.unit.nva.search2.constant.Defaults.DEFAULT_VALUE_SORT; -import static no.unit.nva.search2.constant.Defaults.DEFAULT_VALUE_SORT_ORDER; import static no.unit.nva.search2.constant.ErrorMessages.INVALID_VALUE_WITH_SORT; -import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_IGNORE_CASE; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.FIELDS; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.FROM; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.PAGE; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.SEARCH_AFTER; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.SEARCH_ALL; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.SIZE; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.SORT; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.SORT_ORDER; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.VALID_LUCENE_PARAMETER_KEYS; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.keyFromString; -import static no.unit.nva.search2.model.ResourceSortKeys.INVALID; -import static no.unit.nva.search2.model.ResourceSortKeys.validSortKeys; +import static no.unit.nva.search2.constant.ImportCandidate.IMPORT_CANDIDATES_AGGREGATIONS; +import static no.unit.nva.search2.constant.ImportCandidate.IMPORT_CANDIDATES_INDEX_NAME; +import static no.unit.nva.search2.constant.Words.ALL; +import static no.unit.nva.search2.constant.Words.ASTERISK; +import static no.unit.nva.search2.constant.Words.COLON; +import static no.unit.nva.search2.constant.Words.COMMA; +import static no.unit.nva.search2.constant.Words.DOT; +import static no.unit.nva.search2.constant.Words.KEYWORD; +import static no.unit.nva.search2.constant.Words.SEARCH; +import static no.unit.nva.search2.constant.Words.ZERO; +import static no.unit.nva.search2.enums.ImportCandidateParameter.FROM; +import static no.unit.nva.search2.enums.ImportCandidateParameter.PAGE; +import static no.unit.nva.search2.enums.ImportCandidateParameter.SEARCH_AFTER; +import static no.unit.nva.search2.enums.ImportCandidateParameter.SIZE; +import static no.unit.nva.search2.enums.ImportCandidateParameter.SORT; +import static no.unit.nva.search2.enums.ImportCandidateParameter.VALID_LUCENE_PARAMETER_KEYS; +import static no.unit.nva.search2.enums.ImportCandidateParameter.keyFromString; +import static no.unit.nva.search2.enums.ImportCandidateSort.INVALID; +import static no.unit.nva.search2.enums.ImportCandidateSort.fromSortKey; +import static no.unit.nva.search2.enums.ImportCandidateSort.validSortKeys; +import static nva.commons.core.StringUtils.EMPTY_STRING; import static nva.commons.core.paths.UriWrapper.fromUri; -import com.google.common.net.MediaType; import java.net.URI; import java.util.Arrays; import java.util.Collection; -import java.util.Locale; -import java.util.stream.Collectors; +import java.util.Map.Entry; import java.util.stream.Stream; -import no.unit.nva.search.CsvTransformer; -import no.unit.nva.search2.model.OpenSearchQuery; -import no.unit.nva.search2.model.OpenSearchQueryBuilder; -import no.unit.nva.search2.model.OpenSearchSwsResponse; -import no.unit.nva.search2.model.PagedSearchDto; -import no.unit.nva.search2.model.ParameterKey; -import no.unit.nva.search2.model.ParameterKeyImportCandidate; -import no.unit.nva.search2.model.QueryBuilderSourceWrapper; -import no.unit.nva.search2.model.ResourceSortKeys; -import nva.commons.apigateway.exceptions.BadRequestException; +import no.unit.nva.search2.common.Query; +import no.unit.nva.search2.common.QueryBuilder; +import no.unit.nva.search2.common.QueryContentWrapper; +import no.unit.nva.search2.enums.ImportCandidateParameter; +import no.unit.nva.search2.enums.ParameterKey; import nva.commons.core.JacocoGenerated; -import org.jetbrains.annotations.NotNull; -import org.opensearch.common.collect.Tuple; -import org.opensearch.index.query.BoolQueryBuilder; -import org.opensearch.index.query.MultiMatchQueryBuilder; -import org.opensearch.index.query.MultiMatchQueryBuilder.Type; -import org.opensearch.index.query.Operator; import org.opensearch.index.query.QueryBuilders; import org.opensearch.search.builder.SearchSourceBuilder; import org.opensearch.search.sort.SortOrder; -public final class ImportCandidateQuery extends OpenSearchQuery { +public final class ImportCandidateQuery extends Query { ImportCandidateQuery() { super(); } - + static Builder builder() { return new Builder(); } - @Override - public URI getOpenSearchUri() { - return - fromUri(openSearchUri) - .addChild(IMPORT_CANDIDATES_INDEX, SEARCH) - .getUri(); - } - - public String doSearch(ImportCandidateClient queryClient) { - final var response = queryClient.doSearch(this); - return MediaType.CSV_UTF_8.is(this.getMediaType()) - ? toCsvText(response) - : toPagedResponse(response).toJsonString(); - } - - private String toCsvText(OpenSearchSwsResponse response) { - return CsvTransformer.transform(response.getSearchHits()); - } - - PagedSearchDto toPagedResponse(OpenSearchSwsResponse response) { - final var requestParameter = toNvaSearchApiRequestParameter(); - final var source = URI.create(getNvaSearchApiUri().toString().split("\\?")[0]); - - return - PagedSearchDto.Builder.builder() - .withTotalHits(response.getTotalSize()) - .withHits(response.getSearchHits()) - .withAggregations(response.getAggregationsStructured()) - .withIds(source, requestParameter, getValue(FROM).as(), getValue(SIZE).as()) - .withNextResultsBySortKey(QueryBuilderTools.nextResultsBySortKey(response, requestParameter, source)) - .build(); - } - - public Stream createQueryBuilderStream() { + public Stream createQueryBuilderStream() { var queryBuilder = this.hasNoSearchValue() ? QueryBuilders.matchAllQuery() : boolQuery(); - + var builder = new SearchSourceBuilder().query(queryBuilder); - + var searchAfter = removeKey(SEARCH_AFTER); if (nonNull(searchAfter)) { var sortKeys = searchAfter.split(COMMA); builder.searchAfter(sortKeys); } - + if (isFirstPage()) { IMPORT_CANDIDATES_AGGREGATIONS.forEach(builder::aggregation); } - + builder.size(getValue(SIZE).as()); builder.from(getValue(FROM).as()); - getSortStream().forEach(orderTuple -> builder.sort(orderTuple.v1(), orderTuple.v2())); - - return Stream.of(new QueryBuilderSourceWrapper(builder, this.getOpenSearchUri())); - } - - /** - * Creates a boolean query, with all the search parameters. - * - * @return a BoolQueryBuilder - */ - @SuppressWarnings({"PMD.SwitchStmtsShouldHaveDefault"}) - private BoolQueryBuilder boolQuery() { - var bq = QueryBuilders.boolQuery(); - getOpenSearchParameters() - .forEach((key, value) -> { - if (key.equals(SEARCH_ALL)) { - bq.must(multiMatchQuery()); - } else if (key.fieldType().equals(ParameterKey.ParamKind.KEYWORD)) { - QueryBuilderTools.addKeywordQuery(key, value, bq); - } else { - switch (key.searchOperator()) { - case MUST -> bq.must(QueryBuilderTools.buildQuery(key, value)); - case MUST_NOT -> bq.mustNot(QueryBuilderTools.buildQuery(key, value)); - case SHOULD -> bq.should(QueryBuilderTools.buildQuery(key, value)); - case GREATER_THAN_OR_EQUAL_TO, LESS_THAN -> bq.must(QueryBuilderTools.rangeQuery(key, value)); - } - } - }); - return bq; + getSortStream().forEach(entry -> builder.sort(fromSortKey(entry.getKey()).getFieldName(), entry.getValue())); + + return Stream.of(new QueryContentWrapper(builder, this.getOpenSearchUri())); } - - @NotNull - private Stream> getSortStream() { + + @Override + public URI getOpenSearchUri() { return - getOptional(SORT).stream() - .flatMap(sort -> Arrays.stream(sort.split(COMMA))) - .map(sort -> sort.split(COLON)) - .map(QueryBuilderTools::expandSortKeys); + fromUri(openSearchUri) + .addChild(IMPORT_CANDIDATES_INDEX_NAME, SEARCH) + .getUri(); } - - /** - * Creates a multi match query, all words needs to be present, within a document. - * - * @return a MultiMatchQueryBuilder - */ - private MultiMatchQueryBuilder multiMatchQuery() { - var fields = QueryBuilderTools.extractFields(getValue(FIELDS).toString()); - var value = getValue(SEARCH_ALL).toString(); - return QueryBuilders - .multiMatchQuery(value, fields) - .type(Type.CROSS_FIELDS) - .operator(Operator.AND); + + @Override + protected ImportCandidateParameter getFieldsKey() { + return ImportCandidateParameter.FIELDS; + } + + @Override + protected String[] fieldsToKeyNames(String field) { + return ALL.equals(field) || isNull(field) + ? ASTERISK.split(COMMA) // NONE or ALL -> ['*'] + : Arrays.stream(field.split(COMMA)) + .map(ImportCandidateParameter::keyFromString) + .map(ParameterKey::searchFields) + .flatMap(Collection::stream) + .map(fieldPath -> fieldPath.replace(DOT + KEYWORD, EMPTY_STRING)) + .toArray(String[]::new); } - - boolean isFirstPage() { + + @Override + protected boolean isFirstPage() { return ZERO.equals(getValue(FROM).toString()); } - + + @Override + protected Integer getFrom() { + return getValue(FROM).as(); + } + + @Override + protected Integer getSize() { + return getValue(SIZE).as(); + } + + @Override + public String getSort() { + return getValue(SORT).as(); + } + @SuppressWarnings("PMD.GodClass") - protected static class Builder - extends OpenSearchQueryBuilder { - - private static final String ALL = "all"; - public static final Integer EXPECTED_TWO_PARTS = 2; - + protected static class Builder extends QueryBuilder { + Builder() { super(new ImportCandidateQuery()); } - + @Override protected void assignDefaultValues() { requiredMissing().forEach(key -> { switch (key) { case FROM -> setValue(key.fieldName(), DEFAULT_OFFSET); case SIZE -> setValue(key.fieldName(), DEFAULT_VALUE_PER_PAGE); - case SORT -> setValue(key.fieldName(), DEFAULT_VALUE_SORT + COLON + DEFAULT_VALUE_SORT_ORDER); + case SORT -> setValue(key.fieldName(), DEFAULT_IMPORT_CANDIDATE_SORT + COLON + DEFAULT_SORT_ORDER); default -> { } } }); } - + @Override protected void setValue(String key, String value) { var qpKey = keyFromString(key); switch (qpKey) { - case SEARCH_AFTER, FROM, SIZE, PAGE -> query.setQueryValue(qpKey, value); - case FIELDS -> query.setQueryValue(qpKey, expandFields(value)); - case SORT -> addSortQuery(value); - case SORT_ORDER -> addSortOrderQuery(value); + case SEARCH_AFTER, FROM, SIZE, PAGE -> query.setPagingValue(qpKey, value); + case FIELDS -> query.setPagingValue(qpKey, ignoreInvalidFields(value)); + case SORT -> mergeToPagingKey(SORT, trimSpace(value)); + case SORT_ORDER -> mergeToPagingKey(SORT, value); case ADDITIONAL_IDENTIFIERS, ADDITIONAL_IDENTIFIERS_NOT, ADDITIONAL_IDENTIFIERS_SHOULD, - PUBLISHED_BEFORE, PUBLISHED_SINCE, CATEGORY, CATEGORY_NOT, CATEGORY_SHOULD, - COLLABORATION_TYPE, + CREATED_DATE, + COLLABORATION_TYPE, COLLABORATION_TYPE_NOT, COLLABORATION_TYPE_SHOULD, + CONTRIBUTOR, CONTRIBUTOR_NOT, CONTRIBUTOR_SHOULD, DOI, DOI_NOT, DOI_SHOULD, ID, ID_NOT, ID_SHOULD, - OWNER, OWNER_NOT, OWNER_SHOULD, - PUBLISHER, + IMPORT_STATUS, IMPORT_STATUS_NOT, IMPORT_STATUS_SHOULD, + INSTANCE_TYPE, INSTANCE_TYPE_NOT, INSTANCE_TYPE_SHOULD, + PUBLICATION_YEAR, PUBLICATION_YEAR_BEFORE, PUBLICATION_YEAR_SINCE, + PUBLISHER, PUBLISHER_NOT, PUBLISHER_SHOULD, SEARCH_ALL, - TITLE, TITLE_NOT, TITLE_SHOULD -> query.setSearchFieldValue(qpKey, value); + TITLE, TITLE_NOT, TITLE_SHOULD, + TYPE -> query.setSearchingValue(qpKey, value); default -> invalidKeys.add(key); } } - + @JacocoGenerated @Override protected void applyRulesAfterValidation() { @@ -230,85 +178,36 @@ protected void applyRulesAfterValidation() { if (query.isPresent(FROM)) { var page = query.getValue(PAGE).as(); var perPage = query.getValue(SIZE).as(); - query.setQueryValue(FROM, String.valueOf(page.longValue() * perPage.longValue())); + query.setPagingValue(FROM, String.valueOf(page.longValue() * perPage.longValue())); } query.removeKey(PAGE); } } - + + @Override + protected void validateSortEntry(Entry entry) { + + if (fromSortKey(entry.getKey()) == INVALID) { + throw new IllegalArgumentException(INVALID_VALUE_WITH_SORT.formatted(entry.getKey(), validSortKeys())); + } + try { + entry.getValue(); // throws error if invalid value + } catch (IllegalStateException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + @Override protected Collection validKeys() { return VALID_LUCENE_PARAMETER_KEYS.stream() .map(ParameterKey::fieldName) .toList(); } - + @Override - protected void validateSort() throws BadRequestException { - if (!query.isPresent(SORT)) { - return; - } - try { - var sortKeys = query.getValue(SORT).as().split(COMMA); - var validSortKeys = - Arrays.stream(sortKeys) - .map(this::validateSortKey) - .collect(Collectors.joining(COMMA)); - - query.setQueryValue(SORT, validSortKeys); - } catch (IllegalArgumentException e) { - throw new BadRequestException(e.getMessage()); - } - } - - private void addSortOrderQuery(String value) { - query.setQueryValue(SORT, mergeParameters(query.getValue(SORT).as(), value)); - } - - private String validateSortKey(String keySort) { - var sortKeyParts = keySort.split(COLON); - if (sortKeyParts.length > EXPECTED_TWO_PARTS) { - throw new IllegalArgumentException(INVALID_VALUE_WITH_SORT.formatted(keySort, validSortKeys())); - } - - var sortOrder = getSortOrder(sortKeyParts); - - if (!sortOrder.matches(SORT_ORDER.valuePattern())) { - throw new IllegalArgumentException("Invalid sort order: " + sortOrder); - } - - var sortField = sortKeyParts[0]; - var sortKey = ResourceSortKeys.fromSortKey(sortField); - - if (sortKey == INVALID) { - throw new IllegalArgumentException(INVALID_VALUE_WITH_SORT.formatted(sortField, validSortKeys())); - } - return sortKey.name().toLowerCase(Locale.getDefault()) + COLON + sortOrder; - } - - private String getSortOrder(String... sortKeyParts) { - return (sortKeyParts.length == EXPECTED_TWO_PARTS) - ? sortKeyParts[1].toLowerCase(Locale.getDefault()) - : DEFAULT_VALUE_SORT_ORDER; - } - - private void addSortQuery(String value) { - var validFieldValue = - decodeUTF(value) - .replaceAll(PATTERN_IS_IGNORE_CASE + " (asc|desc)", ":$1"); - query.setQueryValue(SORT, mergeParameters(query.getValue(SORT).as(), validFieldValue)); + protected boolean isKeyValid(String keyName) { + return keyFromString(keyName) != ImportCandidateParameter.INVALID; } - private String expandFields(String value) { - return ALL.equals(value) || isNull(value) - ? ALL - : Arrays.stream(value.split(COMMA)) - .filter(this::keyIsValid) - .collect(Collectors.joining(COMMA)); - } - - private boolean keyIsValid(String key) { - return keyFromString(key) != ParameterKeyImportCandidate.INVALID; - } } } \ No newline at end of file diff --git a/search-commons/src/main/java/no/unit/nva/search2/QueryBuilderTools.java b/search-commons/src/main/java/no/unit/nva/search2/QueryBuilderTools.java deleted file mode 100644 index d11fcefa8..000000000 --- a/search-commons/src/main/java/no/unit/nva/search2/QueryBuilderTools.java +++ /dev/null @@ -1,141 +0,0 @@ -package no.unit.nva.search2; - -import static java.util.Objects.isNull; -import static java.util.Objects.nonNull; -import static no.unit.nva.search2.constant.ApplicationConstants.ALL; -import static no.unit.nva.search2.constant.ApplicationConstants.ASTERISK; -import static no.unit.nva.search2.constant.ApplicationConstants.COMMA; -import static no.unit.nva.search2.constant.ErrorMessages.OPERATOR_NOT_SUPPORTED; -import static no.unit.nva.search2.model.ParameterKeyResource.FROM; -import static no.unit.nva.search2.model.ParameterKeyResource.SEARCH_AFTER; -import java.net.URI; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import no.unit.nva.search2.model.OpenSearchSwsResponse; -import no.unit.nva.search2.model.ParameterKey; -import no.unit.nva.search2.model.ParameterKeyResource; -import no.unit.nva.search2.model.ResourceSortKeys; -import nva.commons.core.JacocoGenerated; -import nva.commons.core.paths.UriWrapper; -import org.jetbrains.annotations.NotNull; -import org.opensearch.common.collect.Tuple; -import org.opensearch.index.query.BoolQueryBuilder; -import org.opensearch.index.query.MultiMatchQueryBuilder.Type; -import org.opensearch.index.query.Operator; -import org.opensearch.index.query.QueryBuilder; -import org.opensearch.index.query.QueryBuilders; -import org.opensearch.index.query.RangeQueryBuilder; -import org.opensearch.search.sort.SortOrder; - -public final class QueryBuilderTools { - - private static final Integer SINGLE_FIELD = 1; - - static void addKeywordQuery(ParameterKey key, String value, BoolQueryBuilder bq) { - final var searchFields = key.searchFields().toArray(String[]::new); - final var values = Arrays.stream(value.split(COMMA)) - .map(String::trim) - // .map(ParameterKey::escapeSearchString) - .toArray(String[]::new); - final var multipleFields = hasMultipleFields(searchFields); - - Arrays.stream(searchFields).forEach(searchField -> { - final var termsQuery = QueryBuilders.termsQuery(searchField, values).boost(key.fieldBoost()); - switch (key.searchOperator()) { - case MUST -> { - if (multipleFields) { - bq.should(termsQuery); - } else { - bq.must(termsQuery); - } - } - case MUST_NOT -> bq.mustNot(termsQuery); - case SHOULD -> bq.should(termsQuery); - default -> throw new IllegalArgumentException(OPERATOR_NOT_SUPPORTED); - } - }); - } - - static QueryBuilder buildQuery(ParameterKey key, String value) { - final var values = value.replace(COMMA, " "); - final var searchFields = - key.searchFields().stream() - .map(String::trim) - .map(trimmed -> !key.fieldType().equals(ParameterKey.ParamKind.KEYWORD) - ? trimmed.replace(".keyword", "") - : trimmed) - .toArray(String[]::new); - if (hasMultipleFields(searchFields)) { - return QueryBuilders - .multiMatchQuery(values, searchFields) - .type(Type.BEST_FIELDS) - .operator(operatorByKey(key)); - } - var searchField = searchFields[0]; - return QueryBuilders - .matchQuery(searchField, values) - .boost(key.fieldBoost()) - .operator(operatorByKey(key)); - } - - static RangeQueryBuilder rangeQuery(ParameterKey key, String value) { - final var searchField = key.searchFields().toArray()[0].toString(); - - return switch (key.searchOperator()) { - case MUST, MUST_NOT, SHOULD -> throw new IllegalArgumentException(OPERATOR_NOT_SUPPORTED); - case GREATER_THAN_OR_EQUAL_TO -> QueryBuilders.rangeQuery(searchField).gte(value); - case LESS_THAN -> QueryBuilders.rangeQuery(searchField).lt(value); - }; - } - - static Operator operatorByKey(ParameterKey key) { - return switch (key.searchOperator()) { - case MUST -> Operator.AND; - case SHOULD, MUST_NOT -> Operator.OR; - case GREATER_THAN_OR_EQUAL_TO, LESS_THAN -> throw new IllegalArgumentException(OPERATOR_NOT_SUPPORTED); - }; - } - - @JacocoGenerated - static Tuple expandSortKeys(String... strings) { - var sortOrder = strings.length == 2 ? SortOrder.fromString(strings[1]) : SortOrder.ASC; - var fieldName = ResourceSortKeys.fromSortKey(strings[0]).getFieldName(); - return new Tuple<>(fieldName, sortOrder); - } - - @NotNull - static String[] extractFields(String field) { - return ALL.equals(field) || isNull(field) - ? ASTERISK.split(COMMA) - : Arrays.stream(field.split(COMMA)) - .map(ParameterKeyResource::keyFromString) - .map(ParameterKeyResource::searchFields) - .flatMap(Collection::stream) - .toArray(String[]::new); - } - - static boolean hasMultipleFields(String... swsKey) { - return swsKey.length > SINGLE_FIELD; - } - - static boolean hasPromotedPublications(List promotedPublications) { - return nonNull(promotedPublications) && !promotedPublications.isEmpty(); - } - - static URI nextResultsBySortKey( - OpenSearchSwsResponse response, Map requestParameter, URI gatewayUri) { - - requestParameter.remove(FROM.fieldName()); - var sortedP = - response.getSort().stream() - .map(Object::toString) - .collect(Collectors.joining(COMMA)); - requestParameter.put(SEARCH_AFTER.fieldName(), sortedP); - return UriWrapper.fromUri(gatewayUri) - .addQueryParameters(requestParameter) - .getUri(); - } -} diff --git a/search-commons/src/main/java/no/unit/nva/search2/ResourceClient.java b/search-commons/src/main/java/no/unit/nva/search2/ResourceClient.java index a31129fac..e85544092 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/ResourceClient.java +++ b/search-commons/src/main/java/no/unit/nva/search2/ResourceClient.java @@ -13,15 +13,15 @@ import java.net.http.HttpResponse.BodyHandler; import java.nio.charset.StandardCharsets; import no.unit.nva.search.CachedJwtProvider; -import no.unit.nva.search2.model.OpenSearchClient; -import no.unit.nva.search2.model.OpenSearchSwsResponse; -import no.unit.nva.search2.model.QueryBuilderSourceWrapper; +import no.unit.nva.search2.common.OpenSearchClient; +import no.unit.nva.search2.common.QueryContentWrapper; +import no.unit.nva.search2.common.SwsResponse; import nva.commons.core.JacocoGenerated; import nva.commons.secrets.SecretsReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ResourceClient implements OpenSearchClient { +public class ResourceClient extends OpenSearchClient { private static final Logger logger = LoggerFactory.getLogger(ResourceClient.class); @@ -47,7 +47,7 @@ public static ResourceClient defaultClient() { } @Override - public OpenSearchSwsResponse doSearch(ResourceQuery query) { + public SwsResponse doSearch(ResourceQuery query) { return query.createQueryBuilderStream(userSettingsClient) .map(this::createRequest) @@ -58,7 +58,7 @@ public OpenSearchSwsResponse doSearch(ResourceQuery query) { @JacocoGenerated - private HttpRequest createRequest(QueryBuilderSourceWrapper qbs) { + private HttpRequest createRequest(QueryContentWrapper qbs) { logger.info(qbs.source().query().toString()); return HttpRequest .newBuilder(qbs.requestUri()) @@ -74,11 +74,11 @@ private HttpResponse fetch(HttpRequest httpRequest) { } @JacocoGenerated - private OpenSearchSwsResponse handleResponse(HttpResponse response) { + private SwsResponse handleResponse(HttpResponse response) { if (response.statusCode() != HTTP_OK) { throw new RuntimeException(response.body()); } - return attempt(() -> singleLineObjectMapper.readValue(response.body(), OpenSearchSwsResponse.class)) + return attempt(() -> singleLineObjectMapper.readValue(response.body(), SwsResponse.class)) .orElseThrow(); } diff --git a/search-commons/src/main/java/no/unit/nva/search2/ResourceQuery.java b/search-commons/src/main/java/no/unit/nva/search2/ResourceQuery.java index a3be87045..56c2ba8b0 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/ResourceQuery.java +++ b/search-commons/src/main/java/no/unit/nva/search2/ResourceQuery.java @@ -2,149 +2,92 @@ import static java.util.Objects.isNull; import static java.util.Objects.nonNull; -import static no.unit.nva.search.constants.ApplicationConstants.RESOURCES_AGGREGATIONS; -import static no.unit.nva.search2.QueryBuilderTools.hasPromotedPublications; -import static no.unit.nva.search2.constant.ApplicationConstants.COLON; -import static no.unit.nva.search2.constant.ApplicationConstants.COMMA; -import static no.unit.nva.search2.constant.ApplicationConstants.ZERO; import static no.unit.nva.search2.constant.Defaults.DEFAULT_OFFSET; +import static no.unit.nva.search2.constant.Defaults.DEFAULT_RESOURCE_SORT; +import static no.unit.nva.search2.constant.Defaults.DEFAULT_SORT_ORDER; import static no.unit.nva.search2.constant.Defaults.DEFAULT_VALUE_PER_PAGE; -import static no.unit.nva.search2.constant.Defaults.DEFAULT_VALUE_SORT; -import static no.unit.nva.search2.constant.Defaults.DEFAULT_VALUE_SORT_ORDER; import static no.unit.nva.search2.constant.ErrorMessages.INVALID_VALUE_WITH_SORT; -import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_IGNORE_CASE; -import static no.unit.nva.search2.model.ParameterKeyResource.CONTRIBUTOR_ID; -import static no.unit.nva.search2.model.ParameterKeyResource.FIELDS; -import static no.unit.nva.search2.model.ParameterKeyResource.FROM; -import static no.unit.nva.search2.model.ParameterKeyResource.FUNDING; -import static no.unit.nva.search2.model.ParameterKeyResource.PAGE; -import static no.unit.nva.search2.model.ParameterKeyResource.SEARCH_AFTER; -import static no.unit.nva.search2.model.ParameterKeyResource.SEARCH_ALL; -import static no.unit.nva.search2.model.ParameterKeyResource.SIZE; -import static no.unit.nva.search2.model.ParameterKeyResource.SORT; -import static no.unit.nva.search2.model.ParameterKeyResource.SORT_ORDER; -import static no.unit.nva.search2.model.ParameterKeyResource.VALID_LUCENE_PARAMETER_KEYS; -import static no.unit.nva.search2.model.ParameterKeyResource.keyFromString; -import static no.unit.nva.search2.model.ResourceSortKeys.INVALID; -import static no.unit.nva.search2.model.ResourceSortKeys.validSortKeys; -import com.google.common.net.MediaType; -import java.net.URI; +import static no.unit.nva.search2.constant.Resource.RESOURCES_AGGREGATIONS; +import static no.unit.nva.search2.constant.Words.ALL; +import static no.unit.nva.search2.constant.Words.ASTERISK; +import static no.unit.nva.search2.constant.Words.COLON; +import static no.unit.nva.search2.constant.Words.COMMA; +import static no.unit.nva.search2.constant.Words.DOT; +import static no.unit.nva.search2.constant.Words.ID; +import static no.unit.nva.search2.constant.Words.KEYWORD; +import static no.unit.nva.search2.constant.Words.ZERO; +import static no.unit.nva.search2.enums.ResourceParameter.CONTRIBUTOR_ID; +import static no.unit.nva.search2.enums.ResourceParameter.FIELDS; +import static no.unit.nva.search2.enums.ResourceParameter.FROM; +import static no.unit.nva.search2.enums.ResourceParameter.FUNDING; +import static no.unit.nva.search2.enums.ResourceParameter.PAGE; +import static no.unit.nva.search2.enums.ResourceParameter.SEARCH_AFTER; +import static no.unit.nva.search2.enums.ResourceParameter.SIZE; +import static no.unit.nva.search2.enums.ResourceParameter.SORT; +import static no.unit.nva.search2.enums.ResourceParameter.keyFromString; +import static no.unit.nva.search2.enums.ResourceSort.INVALID; +import static no.unit.nva.search2.enums.ResourceSort.fromSortKey; +import static no.unit.nva.search2.enums.ResourceSort.validSortKeys; +import static nva.commons.core.StringUtils.EMPTY_STRING; +import static nva.commons.core.attempt.Try.attempt; import java.util.Arrays; import java.util.Collection; -import java.util.Locale; -import java.util.stream.Collectors; +import java.util.List; +import java.util.Map.Entry; import java.util.stream.Stream; -import no.unit.nva.search.CsvTransformer; -import no.unit.nva.search2.model.OpenSearchQuery; -import no.unit.nva.search2.model.OpenSearchQueryBuilder; -import no.unit.nva.search2.model.OpenSearchSwsResponse; -import no.unit.nva.search2.model.PagedSearchDto; -import no.unit.nva.search2.model.ParameterKey; -import no.unit.nva.search2.model.ParameterKeyResource; -import no.unit.nva.search2.model.QueryBuilderSourceWrapper; -import no.unit.nva.search2.model.ResourceSortKeys; -import nva.commons.apigateway.exceptions.BadRequestException; +import no.unit.nva.search2.common.Query; +import no.unit.nva.search2.common.QueryBuilder; +import no.unit.nva.search2.common.QueryContentWrapper; +import no.unit.nva.search2.enums.ParameterKey; +import no.unit.nva.search2.enums.ResourceParameter; import nva.commons.core.JacocoGenerated; import org.jetbrains.annotations.NotNull; -import org.opensearch.common.collect.Tuple; import org.opensearch.index.query.BoolQueryBuilder; -import org.opensearch.index.query.MultiMatchQueryBuilder; -import org.opensearch.index.query.MultiMatchQueryBuilder.Type; -import org.opensearch.index.query.Operator; import org.opensearch.index.query.QueryBuilders; import org.opensearch.search.builder.SearchSourceBuilder; import org.opensearch.search.sort.SortOrder; -public final class ResourceQuery extends OpenSearchQuery { +public final class ResourceQuery extends Query { private ResourceQuery() { super(); } - + + static Builder builder() { return new Builder(); } - public String doSearch(ResourceClient queryClient) { - final var response = queryClient.doSearch(this); - return MediaType.CSV_UTF_8.is(this.getMediaType()) - ? toCsvText(response) - : toPagedResponse(response).toJsonString(); - } - - private String toCsvText(OpenSearchSwsResponse response) { - return CsvTransformer.transform(response.getSearchHits()); - } - - PagedSearchDto toPagedResponse(OpenSearchSwsResponse response) { - final var requestParameter = toNvaSearchApiRequestParameter(); - final var source = URI.create(getNvaSearchApiUri().toString().split("\\?")[0]); - - return - PagedSearchDto.Builder.builder() - .withTotalHits(response.getTotalSize()) - .withHits(response.getSearchHits()) - .withAggregations(response.getAggregationsStructured()) - .withIds(source, requestParameter, getValue(FROM).as(), getValue(SIZE).as()) - .withNextResultsBySortKey(QueryBuilderTools.nextResultsBySortKey(response, requestParameter, source)) - .build(); - } - - public Stream createQueryBuilderStream(UserSettingsClient userSettingsClient) { + public Stream createQueryBuilderStream(UserSettingsClient userSettingsClient) { var queryBuilder = this.hasNoSearchValue() ? QueryBuilders.matchAllQuery() - : boolQuery(userSettingsClient); - + : boolQuery(); + + if (isPresent(CONTRIBUTOR_ID)) { + assert queryBuilder instanceof BoolQueryBuilder; + addPromotedPublications(userSettingsClient, (BoolQueryBuilder) queryBuilder); + } + var builder = new SearchSourceBuilder().query(queryBuilder); - + var searchAfter = removeKey(SEARCH_AFTER); if (nonNull(searchAfter)) { var sortKeys = searchAfter.split(COMMA); builder.searchAfter(sortKeys); } - + if (isFirstPage()) { RESOURCES_AGGREGATIONS.forEach(builder::aggregation); } - + builder.size(getValue(SIZE).as()); builder.from(getValue(FROM).as()); - getSortStream().forEach(orderTuple -> builder.sort(orderTuple.v1(), orderTuple.v2())); - - return Stream.of(new QueryBuilderSourceWrapper(builder, this.getOpenSearchUri())); - } - - /** - * Creates a boolean query, with all the search parameters. - * - * @param userSettingsClient UserSettingsClient - * @return a BoolQueryBuilder - */ - @SuppressWarnings({"PMD.SwitchStmtsShouldHaveDefault"}) - private BoolQueryBuilder boolQuery(UserSettingsClient userSettingsClient) { - var bq = QueryBuilders.boolQuery(); - getOpenSearchParameters() - .forEach((key, value) -> { - if (key.equals(SEARCH_ALL)) { - bq.must(multiMatchQuery()); - } else if (key.fieldType().equals(ParameterKey.ParamKind.KEYWORD)) { - QueryBuilderTools.addKeywordQuery(key, value, bq); - } else { - switch (key.searchOperator()) { - case MUST -> bq.must(QueryBuilderTools.buildQuery(key, value)); - case MUST_NOT -> bq.mustNot(QueryBuilderTools.buildQuery(key, value)); - case SHOULD -> bq.should(QueryBuilderTools.buildQuery(key, value)); - case GREATER_THAN_OR_EQUAL_TO, LESS_THAN -> bq.must(QueryBuilderTools.rangeQuery(key, value)); - } - } - if (key.equals(CONTRIBUTOR_ID)) { - addPromotedPublications(userSettingsClient, bq); - } - }); - return bq; + getSortStream().forEach(entry -> builder.sort(fromSortKey(entry.getKey()).getFieldName(), entry.getValue())); + + return Stream.of(new QueryContentWrapper(builder, this.getOpenSearchUri())); } - + private void addPromotedPublications(UserSettingsClient userSettingsClient, BoolQueryBuilder bq) { var promotedPublications = userSettingsClient.doSearch(this).promotedPublications(); if (hasPromotedPublications(promotedPublications)) { @@ -152,95 +95,115 @@ private void addPromotedPublications(UserSettingsClient userSettingsClient, Bool for (int i = 0; i < promotedPublications.size(); i++) { bq.should( QueryBuilders - .matchQuery("id", promotedPublications.get(i)) + .matchQuery(ID, promotedPublications.get(i)) .boost(3.14F + promotedPublications.size() - i) ); } } } - - @NotNull - private Stream> getSortStream() { - return - getOptional(SORT).stream() - .flatMap(sort -> Arrays.stream(sort.split(COMMA))) - .map(sort -> sort.split(COLON)) - .map(QueryBuilderTools::expandSortKeys); + + private boolean hasPromotedPublications(List promotedPublications) { + return nonNull(promotedPublications) && !promotedPublications.isEmpty(); } - - /** - * Creates a multi match query, all words needs to be present, within a document. - * - * @return a MultiMatchQueryBuilder - */ - private MultiMatchQueryBuilder multiMatchQuery() { - var fields = QueryBuilderTools.extractFields(getValue(FIELDS).toString()); - var value = getValue(SEARCH_ALL).toString(); - return QueryBuilders - .multiMatchQuery(value, fields) - .type(Type.CROSS_FIELDS) - .operator(Operator.AND); + + @Override + protected ResourceParameter getFieldsKey() { + return FIELDS; + } + + @NotNull + @Override + protected String[] fieldsToKeyNames(String field) { + return ALL.equals(field) || isNull(field) + ? ASTERISK.split(COMMA) // NONE or ALL -> ['*'] + : Arrays.stream(field.split(COMMA)) + .map(ResourceParameter::keyFromString) + .map(ParameterKey::searchFields) + .flatMap(Collection::stream) + .map(fieldPath -> fieldPath.replace(DOT + KEYWORD, EMPTY_STRING)) + .toArray(String[]::new); } - - boolean isFirstPage() { + + @Override + public boolean isFirstPage() { return ZERO.equals(getValue(FROM).toString()); } - + + @Override + protected Integer getFrom() { + return getValue(FROM).as(); + } + + @Override + protected Integer getSize() { + return getValue(SIZE).as(); + } + + @Override + public String getSort() { + return getValue(SORT).as(); + } + @SuppressWarnings("PMD.GodClass") - protected static class Builder extends OpenSearchQueryBuilder { - - private static final String ALL = "all"; - public static final Integer EXPECTED_TWO_PARTS = 2; - + protected static class Builder extends QueryBuilder { + Builder() { super(new ResourceQuery()); } - + + @Override + protected boolean isKeyValid(String keyName) { + return keyFromString(keyName) != ResourceParameter.INVALID; + } + @Override protected void assignDefaultValues() { requiredMissing().forEach(key -> { switch (key) { case FROM -> setValue(key.fieldName(), DEFAULT_OFFSET); case SIZE -> setValue(key.fieldName(), DEFAULT_VALUE_PER_PAGE); - case SORT -> setValue(key.fieldName(), DEFAULT_VALUE_SORT + COLON + DEFAULT_VALUE_SORT_ORDER); + case SORT -> setValue(key.fieldName(), DEFAULT_RESOURCE_SORT + COLON + DEFAULT_SORT_ORDER); default -> { } } }); } - + @Override protected void setValue(String key, String value) { var qpKey = keyFromString(key); switch (qpKey) { - case SEARCH_AFTER, FROM, SIZE, PAGE -> query.setQueryValue(qpKey, value); - case FIELDS -> query.setQueryValue(qpKey, expandFields(value)); - case SORT -> addSortQuery(value); - case SORT_ORDER -> addSortOrderQuery(value); + case SEARCH_AFTER, FROM, SIZE, PAGE -> query.setPagingValue(qpKey, value); + case FIELDS -> query.setPagingValue(qpKey, ignoreInvalidFields(value)); + case SORT -> mergeToPagingKey(SORT, trimSpace(value)); + case SORT_ORDER -> mergeToPagingKey(SORT, value); case CREATED_BEFORE, CREATED_SINCE, MODIFIED_BEFORE, MODIFIED_SINCE, - PUBLISHED_BEFORE, PUBLISHED_SINCE -> query.setSearchFieldValue(qpKey, expandDate(value)); - case CATEGORY, CATEGORY_NOT, CATEGORY_SHOULD, - CONTRIBUTOR_ID, CONTRIBUTOR, CONTRIBUTOR_NOT, CONTRIBUTOR_SHOULD, + PUBLISHED_BEFORE, PUBLISHED_SINCE -> query.setSearchingValue(qpKey, expandYearToDate(value)); + case CONTEXT_TYPE, CONTEXT_TYPE_NOT, CONTEXT_TYPE_SHOULD, + CONTRIBUTOR_ID, CONTRIBUTOR, CONTRIBUTOR_NOT, DOI, DOI_NOT, DOI_SHOULD, FUNDING, FUNDING_SOURCE, FUNDING_SOURCE_NOT, FUNDING_SOURCE_SHOULD, ID, ID_NOT, ID_SHOULD, + INSTANCE_TYPE, INSTANCE_TYPE_NOT, INSTANCE_TYPE_SHOULD, INSTITUTION, INSTITUTION_NOT, INSTITUTION_SHOULD, ISBN, ISBN_NOT, ISBN_SHOULD, ISSN, ISSN_NOT, ISSN_SHOULD, ORCID, ORCID_NOT, ORCID_SHOULD, + PARENT_PUBLICATION, PARENT_PUBLICATION_SHOULD, PROJECT, PROJECT_NOT, PROJECT_SHOULD, PUBLICATION_YEAR, PUBLICATION_YEAR_SHOULD, SEARCH_ALL, TITLE, TITLE_NOT, TITLE_SHOULD, + TOP_LEVEL_ORGANIZATION, UNIT, UNIT_NOT, UNIT_SHOULD, - USER, USER_NOT, USER_SHOULD -> query.setSearchFieldValue(qpKey, value); + USER, USER_NOT, USER_SHOULD -> query.setSearchingValue(qpKey, value); case LANG -> { // ignore and continue } default -> invalidKeys.add(key); } } - + @JacocoGenerated @Override protected void applyRulesAfterValidation() { @@ -249,91 +212,21 @@ protected void applyRulesAfterValidation() { if (query.isPresent(FROM)) { var page = query.getValue(PAGE).as(); var perPage = query.getValue(SIZE).as(); - query.setQueryValue(FROM, String.valueOf(page.longValue() * perPage.longValue())); + query.setPagingValue(FROM, String.valueOf(page.longValue() * perPage.longValue())); } query.removeKey(PAGE); } query.getOptional(FUNDING) - .ifPresent(funding -> query.setSearchFieldValue(FUNDING, funding.replaceAll(COLON, COMMA))); + .ifPresent(funding -> query.setSearchingValue(FUNDING, funding.replaceAll(COLON, COMMA))); } - - @Override - protected Collection validKeys() { - return VALID_LUCENE_PARAMETER_KEYS.stream() - .map(ParameterKey::fieldName) - .toList(); - } - + @Override - protected void validateSort() throws BadRequestException { - if (!query.isPresent(SORT)) { - return; - } - try { - var sortKeys = query.getValue(SORT).as().split(COMMA); - var validSortKeys = - Arrays.stream(sortKeys) - .map(this::validateSortKey) - .collect(Collectors.joining(COMMA)); - - query.setQueryValue(SORT, validSortKeys); - } catch (IllegalArgumentException e) { - throw new BadRequestException(e.getMessage()); - } - } - - private void addSortOrderQuery(String value) { - query.setQueryValue(SORT, mergeParameters(query.getValue(SORT).as(), value)); - } - - private String validateSortKey(String keySort) { - var sortKeyParts = keySort.split(COLON); - if (sortKeyParts.length > EXPECTED_TWO_PARTS) { - throw new IllegalArgumentException(INVALID_VALUE_WITH_SORT.formatted(keySort, validSortKeys())); - } - - var sortOrder = getSortOrder(sortKeyParts); - - if (!sortOrder.matches(SORT_ORDER.valuePattern())) { - throw new IllegalArgumentException("Invalid sort order: " + sortOrder); + protected void validateSortEntry(Entry entry) { + if (fromSortKey(entry.getKey()) == INVALID) { + throw new IllegalArgumentException(INVALID_VALUE_WITH_SORT.formatted(entry.getKey(), validSortKeys())); } - - var sortField = sortKeyParts[0]; - var sortKey = ResourceSortKeys.fromSortKey(sortField); - - if (sortKey == INVALID) { - throw new IllegalArgumentException(INVALID_VALUE_WITH_SORT.formatted(sortField, validSortKeys())); - } - return sortKey.name().toLowerCase(Locale.getDefault()) + COLON + sortOrder; - } - - private String getSortOrder(String... sortKeyParts) { - return (sortKeyParts.length == EXPECTED_TWO_PARTS) - ? sortKeyParts[1].toLowerCase(Locale.getDefault()) - : DEFAULT_VALUE_SORT_ORDER; - } - - private void addSortQuery(String value) { - var validFieldValue = - decodeUTF(value) - .replaceAll(PATTERN_IS_IGNORE_CASE + " (asc|desc)", ":$1"); - query.setQueryValue(SORT, mergeParameters(query.getValue(SORT).as(), validFieldValue)); - } - - private String expandDate(String value) { - return value.length() == 4 ? value + "-01-01" : value; - } - - private String expandFields(String value) { - return ALL.equals(value) || isNull(value) - ? ALL - : Arrays.stream(value.split(COMMA)) - .filter(this::keyIsValid) - .collect(Collectors.joining(COMMA)); - } - - private boolean keyIsValid(String key) { - return keyFromString(key) != ParameterKeyResource.INVALID; + attempt(entry::getValue) + .orElseThrow(e -> new IllegalArgumentException(e.getException().getMessage())); } } } \ No newline at end of file diff --git a/search-commons/src/main/java/no/unit/nva/search2/UserSettingsClient.java b/search-commons/src/main/java/no/unit/nva/search2/UserSettingsClient.java index b64096133..1f8401c77 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/UserSettingsClient.java +++ b/search-commons/src/main/java/no/unit/nva/search2/UserSettingsClient.java @@ -2,13 +2,13 @@ import static java.net.HttpURLConnection.HTTP_OK; import static no.unit.nva.auth.AuthorizedBackendClient.AUTHORIZATION_HEADER; +import static no.unit.nva.auth.AuthorizedBackendClient.CONTENT_TYPE; import static no.unit.nva.commons.json.JsonUtils.singleLineObjectMapper; import static no.unit.nva.search.utils.UriRetriever.ACCEPT; -import static no.unit.nva.search2.constant.ApplicationConstants.readApiHost; -import static no.unit.nva.search2.model.ParameterKeyResource.CONTRIBUTOR_ID; +import static no.unit.nva.search2.constant.Functions.readApiHost; +import static no.unit.nva.search2.enums.ResourceParameter.CONTRIBUTOR_ID; import static nva.commons.core.attempt.Try.attempt; import com.google.common.net.MediaType; -import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; @@ -16,14 +16,14 @@ import java.util.Collections; import java.util.stream.Stream; import no.unit.nva.search.CachedJwtProvider; -import no.unit.nva.search2.model.OpenSearchClient; -import no.unit.nva.search2.model.UserSettings; +import no.unit.nva.search2.common.OpenSearchClient; +import no.unit.nva.search2.dto.UserSettings; import nva.commons.core.JacocoGenerated; import nva.commons.core.paths.UriWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class UserSettingsClient implements OpenSearchClient { +public class UserSettingsClient extends OpenSearchClient { private static final Logger logger = LoggerFactory.getLogger(UserSettingsClient.class); private final CachedJwtProvider jwtProvider; @@ -41,7 +41,6 @@ public UserSettingsClient(CachedJwtProvider cachedJwtProvider, HttpClient client public UserSettings doSearch(ResourceQuery query) { return createQueryBuilderStream(query) - .map(this::populateSearchRequest) .map(this::createRequest) .map(this::fetch) .map(this::handleResponse) @@ -53,20 +52,18 @@ private Stream createQueryBuilderStream(ResourceQuery query) { return query.getOptional(CONTRIBUTOR_ID).stream(); } - private URI populateSearchRequest(String contributorId) { - return UriWrapper.fromHost(readApiHost()) + @JacocoGenerated + private HttpRequest createRequest(String contributorId) { + logger.info(contributorId); + var userSettingId = UriWrapper.fromHost(readApiHost()) .addChild("person-preferences") .addChild(contributorId) .getUri(); - } - - @JacocoGenerated - private HttpRequest createRequest(URI userSettingId) { - logger.info(userSettingId.toString()); return HttpRequest .newBuilder(userSettingId) .headers( ACCEPT, MediaType.JSON_UTF_8.toString(), + CONTENT_TYPE, MediaType.JSON_UTF_8.toString(), AUTHORIZATION_HEADER, jwtProvider.getValue().getToken()) .GET().build(); } @@ -84,7 +81,7 @@ private UserSettings handleResponse(HttpResponse response) { var settings = attempt(() -> singleLineObjectMapper.readValue(response.body(), UserSettings.class)); return settings.isSuccess() - ? settings.get() - : new UserSettings(Collections.emptyList()); + ? settings.get() + : new UserSettings(Collections.emptyList()); } } diff --git a/search-commons/src/main/java/no/unit/nva/search2/common/AggregationFormat.java b/search-commons/src/main/java/no/unit/nva/search2/common/AggregationFormat.java new file mode 100644 index 000000000..d08e003d1 --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/common/AggregationFormat.java @@ -0,0 +1,118 @@ +package no.unit.nva.search2.common; + +import static no.unit.nva.search2.common.AggregationFormat.Constants.BUCKETS; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_DOC_COUNT_ERROR_UPPER_BOUND; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_SUM_OTHER_DOC_COUNT; +import static no.unit.nva.search2.constant.Words.COUNT; +import static no.unit.nva.search2.constant.Words.ENGLISH_CODE; +import static no.unit.nva.search2.constant.Words.ID; +import static no.unit.nva.search2.constant.Words.LABELS; +import static no.unit.nva.search2.constant.Words.NAME; +import static no.unit.nva.search2.constant.Words.ZERO; +import static nva.commons.core.StringUtils.EMPTY_STRING; +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.Streams; +import java.util.Map; +import java.util.Optional; +import no.unit.nva.commons.json.JsonUtils; +import org.jetbrains.annotations.NotNull; + +public final class AggregationFormat { + public static JsonNode apply(JsonNode aggregations) { + + var outputAggregationNode = JsonUtils.dtoObjectMapper.createObjectNode(); + + Streams.stream(aggregations.fields()) + .filter(AggregationFormat::ignoreDocCountErrors) + .filter(AggregationFormat::ignoreSumOtherDoc) + .map(AggregationFormat::getJsonNodeEntry) + .forEach(entry -> { + if (LABELS.equals(entry.getKey())) { + outputAggregationNode.set(entry.getKey(), formatLabels(entry.getValue())); + } else if (NAME.equals(entry.getKey())) { + outputAggregationNode.set(LABELS, formatName(entry.getValue())); + } else if (entry.getValue().isValueNode()) { + outputAggregationNode.set(entry.getKey(), entry.getValue()); + } else if (entry.getValue().isArray()) { + var arrayNode = JsonUtils.dtoObjectMapper.createArrayNode(); + entry.getValue().forEach(element -> arrayNode.add(apply(element))); + outputAggregationNode.set(entry.getKey(), arrayNode); + } else { + outputAggregationNode.set(entry.getKey(), apply(entry.getValue())); + } + }); + return outputAggregationNode; + } + + @NotNull + private static Map.Entry getJsonNodeEntry(Map.Entry entry) { + return Map.entry(getNormalizedFieldName(entry.getKey()), getBucketOrValue(entry.getValue())); + } + + @NotNull + private static Map.Entry getNormalizedJsonNodeEntry(Map.Entry entry) { + return Map.entry(getNormalizedFieldName(entry.getKey()), entry.getValue()); + } + + private static boolean ignoreSumOtherDoc(Map.Entry item) { + return !item.getKey().matches(PATTERN_IS_SUM_OTHER_DOC_COUNT); + } + + private static boolean ignoreDocCountErrors(Map.Entry item) { + return !item.getKey().matches(PATTERN_IS_DOC_COUNT_ERROR_UPPER_BOUND); + } + + private static JsonNode getBucketOrValue(JsonNode node) { + if (node.at(Constants.ID_BUCKETS).isArray()) { + return node.at(Constants.ID_BUCKETS); + } + if (node.has(BUCKETS)) { + return node.at(Constants.BUCKETS_PTR); + } + return node; + } + + private static JsonNode formatName(JsonNode nodeEntry) { + var outputAggregationNode = JsonUtils.dtoObjectMapper.createObjectNode(); + var keyValue = nodeEntry.at(Constants.BUCKETS_0_KEY_PTR); + outputAggregationNode.set(ENGLISH_CODE, keyValue); + return outputAggregationNode; + } + + private static JsonNode formatLabels(JsonNode value) { + var outputAggregationNode = JsonUtils.dtoObjectMapper.createObjectNode(); + + Streams.stream(value.fields()) + .filter(AggregationFormat::ignoreDocCountErrors) + .filter(AggregationFormat::ignoreSumOtherDoc) + .map(AggregationFormat::getNormalizedJsonNodeEntry) + .filter(entry -> !COUNT.equals(entry.getKey())) + .forEach(node -> { + var keyValue = node.getValue().at(Constants.BUCKETS_0_KEY_PTR); + outputAggregationNode.set(node.getKey(), keyValue); + }); + return outputAggregationNode; + } + + @NotNull + private static String getNormalizedFieldName(String fieldName) { + return Optional.ofNullable(Constants.AGGREGATION_FIELDS_TO_CHANGE.get(fieldName)) + .orElse(fieldName.replaceFirst(Constants.PATTERN_IS_WORD_ENDING_WITH_HASHTAG, EMPTY_STRING)); + } + + static final class Constants { + + public static final String SLASH = "/"; + public static final String BUCKETS = "buckets"; + + public static final String BUCKETS_PTR = SLASH + BUCKETS; + public static final String BUCKETS_0_KEY_PTR = SLASH + BUCKETS + SLASH + ZERO + SLASH + "key"; + public static final String ID_BUCKETS = SLASH + ID + SLASH + BUCKETS; + public static final String PATTERN_IS_WORD_ENDING_WITH_HASHTAG = "[A-za-z0-9]*#"; + + private static final Map AGGREGATION_FIELDS_TO_CHANGE = Map.of( + "docCount", COUNT, + "doc_count", COUNT); + } + +} diff --git a/search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchClient.java b/search-commons/src/main/java/no/unit/nva/search2/common/OpenSearchClient.java similarity index 64% rename from search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchClient.java rename to search-commons/src/main/java/no/unit/nva/search2/common/OpenSearchClient.java index c9dc4eb04..a4be30942 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchClient.java +++ b/search-commons/src/main/java/no/unit/nva/search2/common/OpenSearchClient.java @@ -1,7 +1,7 @@ -package no.unit.nva.search2.model; +package no.unit.nva.search2.common; -import static no.unit.nva.search2.constant.ApplicationConstants.SEARCH_INFRASTRUCTURE_CREDENTIALS; -import static no.unit.nva.search2.constant.ApplicationConstants.readSearchInfrastructureAuthUri; +import static no.unit.nva.search2.constant.Functions.readSearchInfrastructureAuthUri; +import static no.unit.nva.search2.constant.Words.SEARCH_INFRASTRUCTURE_CREDENTIALS; import java.net.URI; import java.util.stream.Stream; import no.unit.nva.auth.CognitoCredentials; @@ -12,27 +12,27 @@ import nva.commons.secrets.SecretsReader; import org.jetbrains.annotations.NotNull; -public interface OpenSearchClient> { +public abstract class OpenSearchClient> { - R doSearch(Q query); + public abstract R doSearch(Q query); @NotNull @JacocoGenerated - static Stream getUsernamePasswordStream(SecretsReader secretsReader) { + public static Stream getUsernamePasswordStream(SecretsReader secretsReader) { return Stream.of( secretsReader.fetchClassSecret(SEARCH_INFRASTRUCTURE_CREDENTIALS, UsernamePasswordWrapper.class)); } @NotNull @JacocoGenerated - static CognitoCredentials getCognitoCredentials(UsernamePasswordWrapper wrapper) { + public static CognitoCredentials getCognitoCredentials(UsernamePasswordWrapper wrapper) { var uri = URI.create(readSearchInfrastructureAuthUri()); return new CognitoCredentials(wrapper::getUsername, wrapper::getPassword, uri); } @NotNull @JacocoGenerated - static CachedJwtProvider getCachedJwtProvider(SecretsReader reader) { + public static CachedJwtProvider getCachedJwtProvider(SecretsReader reader) { return getUsernamePasswordStream(reader) .map(OpenSearchClient::getCognitoCredentials) diff --git a/search-commons/src/main/java/no/unit/nva/search2/common/Query.java b/search-commons/src/main/java/no/unit/nva/search2/common/Query.java new file mode 100644 index 000000000..d819b18fc --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/common/Query.java @@ -0,0 +1,402 @@ +package no.unit.nva.search2.common; + +import static java.util.Objects.isNull; +import static java.util.Objects.nonNull; +import static no.unit.nva.search2.common.QueryBuilderTools.decodeUTF; +import static no.unit.nva.search2.constant.ErrorMessages.UNEXPECTED_VALUE; +import static no.unit.nva.search2.constant.Functions.readSearchInfrastructureApiUri; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_ASC_DESC_VALUE; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_URL_PARAM_INDICATOR; +import static no.unit.nva.search2.constant.Words.AMPERSAND; +import static no.unit.nva.search2.constant.Words.COLON; +import static no.unit.nva.search2.constant.Words.COMMA; +import static no.unit.nva.search2.constant.Words.EQUAL; +import static no.unit.nva.search2.constant.Words.PLUS; +import static nva.commons.core.StringUtils.EMPTY_STRING; +import static nva.commons.core.attempt.Try.attempt; +import static nva.commons.core.paths.UriWrapper.fromUri; +import com.google.common.net.MediaType; +import java.net.URI; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import no.unit.nva.search.CsvTransformer; +import no.unit.nva.search2.constant.Defaults; +import no.unit.nva.search2.constant.Words; +import no.unit.nva.search2.dto.PagedSearch; +import no.unit.nva.search2.dto.PagedSearchBuilder; +import no.unit.nva.search2.enums.ParameterKey; +import no.unit.nva.search2.enums.ParameterKey.ParamKind; +import no.unit.nva.search2.enums.ParameterKey.ValueEncoding; +import nva.commons.core.JacocoGenerated; +import org.jetbrains.annotations.NotNull; +import org.joda.time.DateTime; +import org.opensearch.index.query.BoolQueryBuilder; +import org.opensearch.index.query.MultiMatchQueryBuilder; +import org.opensearch.index.query.Operator; +import org.opensearch.index.query.QueryBuilders; +import org.opensearch.search.sort.SortOrder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class Query & ParameterKey> { + + protected static final Logger logger = LoggerFactory.getLogger(Query.class); + + protected final transient Map pageParameters; + protected final transient Map searchParameters; + protected final transient Set otherRequiredKeys; + protected transient URI openSearchUri = URI.create(readSearchInfrastructureApiUri()); + private transient MediaType mediaType; + private transient URI gatewayUri = URI.create("https://unset/resource/search"); + + protected abstract K getFieldsKey(); + + protected abstract String[] fieldsToKeyNames(String field); + + protected abstract boolean isFirstPage(); + + protected abstract Integer getFrom(); + + protected abstract Integer getSize(); + + public abstract String getSort(); + + + protected Query() { + searchParameters = new ConcurrentHashMap<>(); + pageParameters = new ConcurrentHashMap<>(); + otherRequiredKeys = new HashSet<>(); + mediaType = MediaType.JSON_UTF_8; + } + + public > String doSearch(OpenSearchClient queryClient) { + final var response = queryClient.doSearch((Q) this); + return MediaType.CSV_UTF_8.is(this.getMediaType()) + ? toCsvText((SwsResponse) response) + : toPagedResponse((SwsResponse) response).toJsonString(); + } + + protected String toCsvText(SwsResponse response) { + return CsvTransformer.transform(response.getSearchHits()); + } + + public PagedSearch toPagedResponse(SwsResponse response) { + final var requestParameter = toNvaSearchApiRequestParameter(); + final var source = URI.create(getNvaSearchApiUri().toString().split(PATTERN_IS_URL_PARAM_INDICATOR)[0]); + + return + new PagedSearchBuilder() + .withTotalHits(response.getTotalSize()) + .withHits(response.getSearchHits()) + .withIds(source, requestParameter, getFrom(), getSize()) + .withNextResultsBySortKey(nextResultsBySortKey(response, requestParameter, source)) + .withAggregations(response.getAggregationsStructured()) + .build(); + } + + /** + * Builds URI to query SWS based on post body. + * + * @return an URI to Sws search without parameters. + */ + public URI getOpenSearchUri() { + return + fromUri(openSearchUri) + .addChild(Words.RESOURCES, Words.SEARCH) + .getUri(); + } + + public Map getOpenSearchParameters() { + return searchParameters; + } + + /** + * Query Parameters with string Keys. + * + * @return Map of String and String + */ + public Map toNvaSearchApiRequestParameter() { + var results = new LinkedHashMap(); + Stream.of(searchParameters.entrySet(), pageParameters.entrySet()) + .flatMap(Set::stream) + .sorted(Comparator.comparingInt(o -> o.getKey().ordinal())) + .forEach(entry -> results.put(toNvaSearchApiKey(entry), entry.getValue().replace(Words.SPACE, PLUS))); + return results; + } + + /** + * Get value from Query Parameter Map with key. + * + * @param key to look up. + * @return String content raw + */ + public AsType getValue(K key) { + return new AsType( + searchParameters.containsKey(key) + ? searchParameters.get(key) + : pageParameters.get(key), + key + ); + } + + public Optional getOptional(K key) { + return Optional.ofNullable(searchParameters.containsKey(key) + ? searchParameters.get(key) + : pageParameters.get(key)); + } + + public String removeKey(K key) { + return searchParameters.containsKey(key) + ? searchParameters.remove(key) + : pageParameters.remove(key); + } + + public boolean isPresent(K key) { + return searchParameters.containsKey(key) || pageParameters.containsKey(key); + } + + @JacocoGenerated + public boolean hasNoSearchValue() { + return searchParameters.isEmpty(); + } + + /** + * Add a key value pair to searchable Parameters. + * + * @param key to add to. + * @param value to assign + */ + public void setSearchingValue(K key, String value) { + if (nonNull(value)) { + var decodedValue = key.valueEncoding() != ValueEncoding.NONE ? decodeUTF(value) : value; + searchParameters.put(key, decodedValue); + } + } + + /** + * Add a key value pair to non-searchable Parameters. + * + * @param key to add to. + * @param value to assign + */ + public void setPagingValue(K key, String value) { + if (nonNull(value)) { + pageParameters.put(key, key.valueEncoding() != ValueEncoding.NONE ? decodeUTF(value) : value); + } + } + + private MediaType getMediaType() { + return mediaType; + } + + public void setMediaType(String mediaType) { + if (nonNull(mediaType) && mediaType.contains(Words.TEXT_CSV)) { + this.mediaType = MediaType.CSV_UTF_8; + } else { + this.mediaType = MediaType.JSON_UTF_8; + } + } + + public URI getNvaSearchApiUri() { + return gatewayUri; + } + + public void setNvaSearchApiUri(URI gatewayUri) { + this.gatewayUri = gatewayUri; + } + + public void setOpenSearchUri(URI openSearchUri) { + this.openSearchUri = openSearchUri; + } + + protected String toNvaSearchApiKey(Entry entry) { + return entry.getKey().fieldName().toLowerCase(Locale.getDefault()); + } + + protected static String mergeWithColonOrComma(String oldValue, String newValue) { + if (nonNull(oldValue)) { + var delimiter = newValue.matches(PATTERN_IS_ASC_DESC_VALUE) ? COLON : COMMA; + return String.join(delimiter, oldValue, newValue); + } else { + return newValue; + } + } + + public static Collection> queryToMapEntries(URI uri) { + return queryToMapEntries(uri.getQuery()); + } + + public static Collection> queryToMapEntries(String query) { + return + nonNull(query) + ? Arrays.stream(query.split(AMPERSAND)) + .map(s -> s.split(EQUAL)) + .map(Query::stringsToEntry) + .toList() + : Collections.emptyList(); + } + + /** + * Creates a boolean query, with all the search parameters. + * + * @return a BoolQueryBuilder + */ + @SuppressWarnings({"PMD.SwitchStmtsShouldHaveDefault"}) + protected BoolQueryBuilder boolQuery() { + var bq = QueryBuilders.boolQuery(); + getOpenSearchParameters() + .forEach((key, value) -> { + if (Words.SEARCH_ALL.equals(key.name())) { + + bq.must(multiMatchQuery(key, getFieldsKey())); + } else if (key.fieldType().equals(ParamKind.KEYWORD)) { + QueryBuilderTools.addKeywordQuery(key, value, bq); + } else { + switch (key.searchOperator()) { + case MUST -> bq.must(QueryBuilderTools.buildQuery(key, value)); + case MUST_NOT -> bq.mustNot(QueryBuilderTools.buildQuery(key, value)); + case SHOULD -> bq.should(QueryBuilderTools.buildQuery(key, value)); + case GREATER_THAN_OR_EQUAL_TO, LESS_THAN -> bq.must(QueryBuilderTools.rangeQuery(key, value)); + default -> throw new IllegalStateException(UNEXPECTED_VALUE + key.searchOperator()); + } + } + }); + return bq; + } + + /** + * Creates a multi match query, all words needs to be present, within a document. + * + * @return a MultiMatchQueryBuilder + */ + private MultiMatchQueryBuilder multiMatchQuery(K searchAllKey, K fieldsKey) { + var fields = fieldsToKeyNames(getValue(fieldsKey).toString()); + var value = getValue(searchAllKey).toString(); + return QueryBuilders + .multiMatchQuery(value, fields) + .type(MultiMatchQueryBuilder.Type.CROSS_FIELDS) + .operator(Operator.AND); + } + + @NotNull + public static Entry stringsToEntry(String... strings) { + return new Entry<>() { + @Override + public String getKey() { + return strings[0]; + } + + @Override + public String getValue() { + return attempt(() -> strings[1]).orElse((f) -> EMPTY_STRING); + } + + @Override + @JacocoGenerated + public String setValue(String value) { + return null; + } + }; + } + + public static Entry entryToSortEntry(Entry entry) { + return new Entry<>() { + @Override + public String getKey() { + return entry.getKey(); + } + + @Override + public SortOrder getValue() { + var sortOrder = nonNull(entry.getValue()) && !entry.getValue().isEmpty() + ? entry.getValue() + : Defaults.DEFAULT_SORT_ORDER; + return SortOrder.fromString(sortOrder); + } + + @Override + @JacocoGenerated + public SortOrder setValue(SortOrder value) { + return null; + } + }; + } + + @SuppressWarnings({"PMD.ShortMethodName"}) + public class AsType { + + private final String value; + private final K key; + + public AsType(String value, K key) { + this.value = value; + this.key = key; + } + + public T as() { + if (isNull(value)) { + return null; + } + return (T) switch (key.fieldType()) { + case DATE -> castDateTime(); + case NUMBER -> castNumber(); + default -> value; + }; + } + + public K getKey() { + return key; + } + + @Override + public String toString() { + return value; + } + + private T castDateTime() { + return ((Class) DateTime.class).cast(DateTime.parse(value)); + } + + @NotNull + private T castNumber() { + return (T) attempt(() -> Integer.parseInt(value)).orElseThrow(); + } + } + + // SORTING + protected Stream> getSortStream() { + var optionalSort = Optional.ofNullable(getSort()); + + return optionalSort.isEmpty() + ? Stream.of() + : Arrays.stream(optionalSort.get().split(COMMA)) + .map(sort -> sort.split(COLON)) + .map(Query::stringsToEntry) + .map(Query::entryToSortEntry); + } + + private URI nextResultsBySortKey(SwsResponse response, Map requestParameter, URI gatewayUri) { + + requestParameter.remove(Words.FROM); + var sortedP = + response.getSort().stream() + .map(Object::toString) + .collect(Collectors.joining(COMMA)); + requestParameter.put(Words.SEARCH_AFTER, sortedP); + return fromUri(gatewayUri) + .addQueryParameters(requestParameter) + .getUri(); + } +} diff --git a/search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchQueryBuilder.java b/search-commons/src/main/java/no/unit/nva/search2/common/QueryBuilder.java similarity index 63% rename from search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchQueryBuilder.java rename to search-commons/src/main/java/no/unit/nva/search2/common/QueryBuilder.java index eaaf1411e..7737429c0 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchQueryBuilder.java +++ b/search-commons/src/main/java/no/unit/nva/search2/common/QueryBuilder.java @@ -1,19 +1,31 @@ -package no.unit.nva.search2.model; +package no.unit.nva.search2.common; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; +import static no.unit.nva.search2.common.Query.mergeWithColonOrComma; +import static no.unit.nva.search2.common.QueryBuilderTools.decodeUTF; import static no.unit.nva.search2.constant.ErrorMessages.invalidQueryParametersMessage; import static no.unit.nva.search2.constant.ErrorMessages.requiredMissingMessage; import static no.unit.nva.search2.constant.ErrorMessages.validQueryParameterNamesMessage; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_ASC_OR_DESC_GROUP; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_SELECTED_GROUP; +import static no.unit.nva.search2.constant.Words.ALL; +import static no.unit.nva.search2.constant.Words.COMMA; +import static no.unit.nva.search2.constant.Words.JANUARY_FIRST; +import static no.unit.nva.search2.enums.ResourceParameter.VALID_SEARCH_PARAMETER_KEYS; import java.net.URI; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; +import no.unit.nva.search2.enums.ParameterKey; import nva.commons.apigateway.RequestInfo; import nva.commons.apigateway.exceptions.BadRequestException; import nva.commons.core.JacocoGenerated; +import org.opensearch.search.sort.SortOrder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,12 +34,12 @@ * @param Enum of QueryParameterKeys * @param Instance of OpenSearchQuery */ -public abstract class OpenSearchQueryBuilder & ParameterKey, Q extends OpenSearchQuery> { +public abstract class QueryBuilder & ParameterKey, Q extends Query> { - protected static final Logger logger = LoggerFactory.getLogger(OpenSearchQueryBuilder.class); + protected static final Logger logger = LoggerFactory.getLogger(QueryBuilder.class); protected final transient Set invalidKeys = new HashSet<>(0); - protected final transient OpenSearchQuery query; + protected final transient Query query; protected transient boolean notValidated = true; /** @@ -39,7 +51,7 @@ public abstract class OpenSearchQueryBuilder & ParameterKey, Q * .build() * */ - public OpenSearchQueryBuilder(OpenSearchQuery query) { + public QueryBuilder(Query query) { this.query = query; } @@ -59,12 +71,12 @@ public Q build() throws BadRequestException { * Validator of CristinQuery.Builder. * @throws BadRequestException if parameters are invalid or missing */ - public OpenSearchQueryBuilder validate() throws BadRequestException { + public QueryBuilder validate() throws BadRequestException { assignDefaultValues(); - for (var entry : query.queryParameters.entrySet()) { + for (var entry : query.pageParameters.entrySet()) { validatesEntrySet(entry); } - for (var entry : query.luceneParameters.entrySet()) { + for (var entry : query.searchParameters.entrySet()) { validatesEntrySet(entry); } if (!requiredMissing().isEmpty()) { @@ -73,7 +85,7 @@ public OpenSearchQueryBuilder validate() throws BadRequestException { if (!invalidKeys.isEmpty()) { throw new BadRequestException(validQueryParameterNamesMessage(invalidKeys,validKeys())); } - validateSort(); + validatedSort(); applyRulesAfterValidation(); notValidated = false; return this; @@ -82,7 +94,7 @@ public OpenSearchQueryBuilder validate() throws BadRequestException { /** * Adds query and path parameters from requestInfo. */ - public final OpenSearchQueryBuilder fromRequestInfo(RequestInfo requestInfo) { + public final QueryBuilder fromRequestInfo(RequestInfo requestInfo) { query.setMediaType(requestInfo.getHeaders().get("Accept")); query.setNvaSearchApiUri(requestInfo.getRequestUri()); return fromQueryParameters(requestInfo.getQueryParameters()); @@ -92,7 +104,7 @@ public final OpenSearchQueryBuilder fromRequestInfo(RequestInfo requestInf /** * Adds parameters from query. */ - public OpenSearchQueryBuilder fromQueryParameters(Collection> parameters) { + public QueryBuilder fromQueryParameters(Collection> parameters) { parameters.forEach(this::setEntryValue); return this; } @@ -100,7 +112,7 @@ public OpenSearchQueryBuilder fromQueryParameters(Collection fromQueryParameters(Map parameters) { + public QueryBuilder fromQueryParameters(Map parameters) { parameters.forEach(this::setValue); return this; } @@ -110,13 +122,13 @@ public OpenSearchQueryBuilder fromQueryParameters(Map para * @param requiredParameters comma seperated QueryParameterKeys */ @SafeVarargs - public final OpenSearchQueryBuilder withRequiredParameters(K... requiredParameters) { + public final QueryBuilder withRequiredParameters(K... requiredParameters) { var tmpSet = Set.of(requiredParameters); query.otherRequiredKeys.addAll(tmpSet); return this; } - public final OpenSearchQueryBuilder withMediaType(String mediaType) { + public final QueryBuilder withMediaType(String mediaType) { query.setMediaType(mediaType); return this; } @@ -126,19 +138,12 @@ public final OpenSearchQueryBuilder withMediaType(String mediaType) { * When running docker tests, the current host needs to be specified. * @param uri URI to local docker test instance */ - public final OpenSearchQueryBuilder withOpensearchUri(URI uri) { + public final QueryBuilder withOpensearchUri(URI uri) { query.setOpenSearchUri(uri); return this; } - - - /** - * Validate sort keys. - * - * @throws BadRequestException if sort key is invalid - */ - protected abstract void validateSort() throws BadRequestException; + protected abstract boolean isKeyValid(String keyName); /** * Sample code for assignDefaultValues. @@ -170,11 +175,33 @@ public final OpenSearchQueryBuilder withOpensearchUri(URI uri) { protected abstract void applyRulesAfterValidation(); + protected abstract void validateSortEntry(Entry entry); + + /** + * Validate sort keys. + * + * @throws BadRequestException if sort key is invalid + */ + protected void validatedSort() throws BadRequestException { + var sortEntries = query.getSort(); + if (isNull(sortEntries)) { + return; + } + try { + query.getSortStream().forEach(this::validateSortEntry); + } catch (IllegalArgumentException e) { + throw new BadRequestException(e.getMessage()); + } + } /** - * returns T.VALID_LUCENE_PARAMETER_KEYS + * returns T.VALID_SEARCH_PARAMETER_KEYS */ - protected abstract Collection validKeys(); + protected Collection validKeys() { + return VALID_SEARCH_PARAMETER_KEYS.stream() + .map(ParameterKey::fieldName) + .toList(); + } @JacocoGenerated protected boolean invalidQueryParameter(K key, String value) { @@ -192,15 +219,14 @@ protected Set getMissingKeys() { protected Set required() { return query.otherRequiredKeys; - } @JacocoGenerated protected Set requiredMissing() { return required().stream() - .filter(key -> !query.luceneParameters.containsKey(key)) - .filter(key -> !query.queryParameters.containsKey(key)) + .filter(key -> !query.searchParameters.containsKey(key)) + .filter(key -> !query.pageParameters.containsKey(key)) .collect(Collectors.toSet()); } @@ -221,4 +247,25 @@ private void setEntryValue(Map.Entry entry) { setValue(entry.getKey(), entry.getValue()); } + protected void mergeToPagingKey(K key, String value) { + query.setPagingValue(key, mergeWithColonOrComma(query.getValue(key).as(), value)); + } + + protected String trimSpace(String value) { + return decodeUTF(value) + .replaceAll(PATTERN_IS_ASC_OR_DESC_GROUP, PATTERN_IS_SELECTED_GROUP); + } + + protected String ignoreInvalidFields(String value) { + return ALL.equals(value) || isNull(value) + ? ALL + : Arrays.stream(value.split(COMMA)) + .filter(this::isKeyValid) // ignoring invalid keys + .collect(Collectors.joining(COMMA)); + } + + public String expandYearToDate(String value) { + return value.length() == 4 ? value + JANUARY_FIRST : value; + } + } \ No newline at end of file diff --git a/search-commons/src/main/java/no/unit/nva/search2/common/QueryBuilderTools.java b/search-commons/src/main/java/no/unit/nva/search2/common/QueryBuilderTools.java new file mode 100644 index 000000000..709ee13ef --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/common/QueryBuilderTools.java @@ -0,0 +1,93 @@ +package no.unit.nva.search2.common; + +import static no.unit.nva.search2.constant.ErrorMessages.OPERATOR_NOT_SUPPORTED; +import static no.unit.nva.search2.constant.Words.COMMA; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import no.unit.nva.search2.enums.ParameterKey; +import org.opensearch.index.query.BoolQueryBuilder; +import org.opensearch.index.query.MultiMatchQueryBuilder.Type; +import org.opensearch.index.query.Operator; +import org.opensearch.index.query.QueryBuilder; +import org.opensearch.index.query.QueryBuilders; +import org.opensearch.index.query.RangeQueryBuilder; + +public final class QueryBuilderTools { + + private static final Integer SINGLE_FIELD = 1; + + public static String decodeUTF(String encoded) { + return URLDecoder.decode(encoded, StandardCharsets.UTF_8); + } + + public static void addKeywordQuery(ParameterKey key, String value, BoolQueryBuilder bq) { + final var searchFields = key.searchFields() + .toArray(String[]::new); + final var values = Arrays.stream(value.split(COMMA)) + .map(String::trim) + .toArray(String[]::new); + final var multipleFields = hasMultipleFields(searchFields); + + Arrays.stream(searchFields).forEach(searchField -> { + final var termsQuery = QueryBuilders.termsQuery(searchField, values).boost(key.fieldBoost()); + switch (key.searchOperator()) { + case MUST -> { + if (multipleFields) { + bq.should(termsQuery); + } else { + bq.must(termsQuery); + } + } + case MUST_NOT -> bq.mustNot(termsQuery); + case SHOULD -> bq.should(termsQuery); + default -> throw new IllegalArgumentException(OPERATOR_NOT_SUPPORTED); + } + }); + } + + public static QueryBuilder buildQuery(ParameterKey key, String value) { + final var values = value.replace(COMMA, " "); + final var searchFields = + key.searchFields().stream() + .map(String::trim) + .map(trimmed -> !key.fieldType().equals(ParameterKey.ParamKind.KEYWORD) + ? trimmed.replace(".keyword", "") + : trimmed) + .toArray(String[]::new); + if (hasMultipleFields(searchFields)) { + return QueryBuilders + .multiMatchQuery(values, searchFields) + .type(Type.BEST_FIELDS) + .operator(operatorByKey(key)); + } + var searchField = searchFields[0]; + return QueryBuilders + .matchQuery(searchField, values) + .boost(key.fieldBoost()) + .operator(operatorByKey(key)); + } + + public static RangeQueryBuilder rangeQuery(ParameterKey key, String value) { + final var searchField = key.searchFields().toArray()[0].toString(); + + return switch (key.searchOperator()) { + case MUST, MUST_NOT, SHOULD -> throw new IllegalArgumentException(OPERATOR_NOT_SUPPORTED); + case GREATER_THAN_OR_EQUAL_TO -> QueryBuilders.rangeQuery(searchField).gte(value); + case LESS_THAN -> QueryBuilders.rangeQuery(searchField).lt(value); + }; + } + + public static Operator operatorByKey(ParameterKey key) { + return switch (key.searchOperator()) { + case MUST -> Operator.AND; + case SHOULD, MUST_NOT -> Operator.OR; + case GREATER_THAN_OR_EQUAL_TO, LESS_THAN -> throw new IllegalArgumentException(OPERATOR_NOT_SUPPORTED); + }; + } + + public static boolean hasMultipleFields(String... swsKeys) { + return swsKeys.length > SINGLE_FIELD; + } + +} diff --git a/search-commons/src/main/java/no/unit/nva/search2/common/QueryContentWrapper.java b/search-commons/src/main/java/no/unit/nva/search2/common/QueryContentWrapper.java new file mode 100644 index 000000000..4772c0954 --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/common/QueryContentWrapper.java @@ -0,0 +1,8 @@ +package no.unit.nva.search2.common; + +import java.net.URI; +import org.opensearch.search.builder.SearchSourceBuilder; + +public record QueryContentWrapper(SearchSourceBuilder source, URI requestUri) { + +} diff --git a/search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchSwsResponse.java b/search-commons/src/main/java/no/unit/nva/search2/common/SwsResponse.java similarity index 78% rename from search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchSwsResponse.java rename to search-commons/src/main/java/no/unit/nva/search2/common/SwsResponse.java index 94c3fe455..cce01a8dc 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchSwsResponse.java +++ b/search-commons/src/main/java/no/unit/nva/search2/common/SwsResponse.java @@ -1,26 +1,25 @@ -package no.unit.nva.search2.model; +package no.unit.nva.search2.common; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.JsonNode; -import no.unit.nva.search2.model.OpenSearchSwsResponse.HitsInfo.Hit; +import no.unit.nva.search2.common.SwsResponse.HitsInfo.Hit; +import nva.commons.core.JacocoGenerated; +import org.jetbrains.annotations.NotNull; import java.beans.Transient; import java.util.List; import java.util.Optional; -import nva.commons.core.JacocoGenerated; -import org.jetbrains.annotations.NotNull; - import static java.util.Objects.nonNull; -import static no.unit.nva.search.models.SearchResponseDto.formatAggregations; -public record OpenSearchSwsResponse( +public record SwsResponse( int took, boolean timed_out, ShardsInfo _shards, HitsInfo hits, JsonNode aggregations) { + public record ShardsInfo( Long total, Long successful, @@ -33,6 +32,7 @@ public record HitsInfo( TotalInfo total, double max_score, List hits) { + public record TotalInfo( Integer value, String relation) { @@ -46,7 +46,7 @@ public record Hit( String _id, double _score, JsonNode _source, - List sort) { + List sort) { } } @@ -56,8 +56,8 @@ public record Hit( @Transient public Integer getTotalSize() { return nonNull(hits) - ? hits.total.value - : 0; + ? hits.total.value + : 0; } @JacocoGenerated @@ -72,19 +72,19 @@ public List getSearchHits() { @NotNull @Transient - public List getSort() { + public List getSort() { return nonNull(hits) && nonNull(hits.hits) && !hits.hits.isEmpty() ? Optional.ofNullable(hits.hits.get(hits.hits.size() - 1).sort()) - .orElse(List.of()) + .orElse(List.of()) : List.of(); } - @Transient public JsonNode getAggregationsStructured() { return nonNull(aggregations) - ? formatAggregations(aggregations) - : null; + ? AggregationFormat.apply(aggregations) + : null; } + } diff --git a/search-commons/src/main/java/no/unit/nva/search2/constant/ApplicationConstants.java b/search-commons/src/main/java/no/unit/nva/search2/constant/ApplicationConstants.java deleted file mode 100644 index 970fbb532..000000000 --- a/search-commons/src/main/java/no/unit/nva/search2/constant/ApplicationConstants.java +++ /dev/null @@ -1,44 +0,0 @@ -package no.unit.nva.search2.constant; - -import com.fasterxml.jackson.databind.ObjectMapper; -import no.unit.nva.commons.json.JsonUtils; -import nva.commons.core.Environment; -import nva.commons.core.JacocoGenerated; - -@JacocoGenerated -public final class ApplicationConstants { - - public static final String AMPERSAND = "&"; - public static final String ASTERISK = "*"; - public static final String ALL = "all"; - public static final String COLON = ":"; - public static final String COMMA = ","; - public static final String EQUAL = "="; - public static final String PIPE = "|"; - public static final String PLUS = "+"; - public static final String PREFIX = "("; - public static final String QUOTE = "'"; - public static final String RESOURCES = "resources"; - public static final String SEARCH = "_search"; - public static final String SPACE = " "; - public static final String SUFFIX = ")"; - public static final String UNDERSCORE = "_"; - public static final String ZERO = "0"; - public static final String SEARCH_INFRASTRUCTURE_CREDENTIALS = "SearchInfrastructureCredentials"; - - - public static final ObjectMapper objectMapperWithEmpty = JsonUtils.dtoObjectMapper; - public static final Environment ENVIRONMENT = new Environment(); - - public static String readSearchInfrastructureAuthUri() { - return ENVIRONMENT.readEnv("SEARCH_INFRASTRUCTURE_AUTH_URI"); - } - - public static String readSearchInfrastructureApiUri() { - return ENVIRONMENT.readEnv("SEARCH_INFRASTRUCTURE_API_URI"); - } - - public static String readApiHost() { - return ENVIRONMENT.readEnv("API_HOST"); - } -} diff --git a/search-commons/src/main/java/no/unit/nva/search2/constant/Defaults.java b/search-commons/src/main/java/no/unit/nva/search2/constant/Defaults.java index e35db796d..0f0b03f5a 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/constant/Defaults.java +++ b/search-commons/src/main/java/no/unit/nva/search2/constant/Defaults.java @@ -1,31 +1,31 @@ package no.unit.nva.search2.constant; import com.fasterxml.jackson.databind.ObjectMapper; - +import com.google.common.net.MediaType; +import java.net.URI; import java.util.List; import java.util.Locale; - -import com.google.common.net.MediaType; import no.unit.nva.commons.json.JsonUtils; -import no.unit.nva.search2.model.ResourceSortKeys; - -import java.net.URI; - +import no.unit.nva.search2.enums.ImportCandidateSort; +import no.unit.nva.search2.enums.ResourceSort; import nva.commons.apigateway.MediaTypes; import nva.commons.core.JacocoGenerated; @JacocoGenerated public final class Defaults { + public static final ObjectMapper objectMapperWithEmpty = JsonUtils.dtoObjectMapper; public static final String DEFAULT_OFFSET = "0"; public static final String DEFAULT_VALUE_PER_PAGE = "15"; - public static final String DEFAULT_VALUE_SORT = ResourceSortKeys.PUBLISHED_DATE - .name().toLowerCase(Locale.getDefault()); - public static final String DEFAULT_VALUE_SORT_ORDER = "desc"; - public static final URI PAGINATED_SEARCH_RESULT_CONTEXT - = URI.create("https://bibsysdev.github.io/src/search/paginated-search-result.json"); + public static final String DEFAULT_RESOURCE_SORT = + ResourceSort.PUBLISHED_DATE.name().toLowerCase(Locale.getDefault()); + public static final String DEFAULT_IMPORT_CANDIDATE_SORT = + ImportCandidateSort.CREATED_DATE.name().toLowerCase(Locale.getDefault()); + public static final String DEFAULT_SORT_ORDER = "desc"; + public static final int DEFAULT_AGGREGATION_SIZE = 100; + public static final URI PAGINATED_SEARCH_RESULT_CONTEXT = + URI.create("https://bibsysdev.github.io/src/search/paginated-search-result.json"); public static final List DEFAULT_RESPONSE_MEDIA_TYPES = - List.of(MediaType.JSON_UTF_8, MediaTypes.APPLICATION_JSON_LD, - MediaType.CSV_UTF_8); + List.of(MediaType.JSON_UTF_8, MediaTypes.APPLICATION_JSON_LD, MediaType.CSV_UTF_8); } diff --git a/search-commons/src/main/java/no/unit/nva/search2/constant/ErrorMessages.java b/search-commons/src/main/java/no/unit/nva/search2/constant/ErrorMessages.java index 88209715c..e2772077f 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/constant/ErrorMessages.java +++ b/search-commons/src/main/java/no/unit/nva/search2/constant/ErrorMessages.java @@ -1,15 +1,14 @@ package no.unit.nva.search2.constant; +import static no.unit.nva.search2.constant.Words.PREFIX; +import static no.unit.nva.search2.constant.Words.QUOTE; +import static no.unit.nva.search2.constant.Words.SUFFIX; +import static nva.commons.core.StringUtils.EMPTY_STRING; import java.util.Collection; import java.util.Set; import java.util.stream.Collectors; import nva.commons.core.JacocoGenerated; -import static no.unit.nva.search2.constant.ApplicationConstants.QUOTE; -import static no.unit.nva.search2.constant.ApplicationConstants.SUFFIX; -import static no.unit.nva.search2.constant.ApplicationConstants.PREFIX; -import static nva.commons.core.StringUtils.EMPTY_STRING; - @JacocoGenerated public class ErrorMessages { public static final String INVALID_VALUE = "Parameter [%s] has invalid value [%s]"; @@ -17,15 +16,14 @@ public class ErrorMessages { "Sort has invalid field value [%s]. Valid values are: %s"; public static final String INVALID_NUMBER = "Parameter '%s' has invalid value. Must be a number."; public static final String INVALID_DATE = "Parameter '%s' has invalid value. Must be a date."; - + public static final String MISSING_PARAMETER = "Parameter(s) -> [%s] -> is/are required."; public static final String OPERATOR_NOT_SUPPORTED = "Operator not supported"; public static final String TEMPLATE_INVALID_QUERY_PARAMETERS = - """ - Invalid query parameter supplied %s.\s - Valid parameters: %s - Also pass through to OpenSearch:[page & per_page | offset & results, sort (& sortOrder), fields, search_after] - """; - public static final String MISSING_PARAMETER = "Parameter(s) -> [%s] -> is/are required."; + "Invalid query parameter supplied %s. " + + " Valid parameters: %s" + + " Also pass through to OpenSearch:[page & per_page | offset & results, sort (& sortOrder), fields, " + + "search_after]"; + public static final String UNEXPECTED_VALUE = "Unexpected value: "; /** * Formats and emits a message with valid parameter names. diff --git a/search-commons/src/main/java/no/unit/nva/search2/constant/Functions.java b/search-commons/src/main/java/no/unit/nva/search2/constant/Functions.java new file mode 100644 index 000000000..4d1021944 --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/constant/Functions.java @@ -0,0 +1,81 @@ +package no.unit.nva.search2.constant; + +import static no.unit.nva.search2.constant.Words.ADMINSTRATIVE_AGREEMENT; +import static no.unit.nva.search2.constant.Words.ASSOCIATED_ARTIFACTS; +import static no.unit.nva.search2.constant.Words.BOKMAAL_CODE; +import static no.unit.nva.search2.constant.Words.DOT; +import static no.unit.nva.search2.constant.Words.ENGLISH_CODE; +import static no.unit.nva.search2.constant.Words.ID; +import static no.unit.nva.search2.constant.Words.KEYWORD; +import static no.unit.nva.search2.constant.Words.LABELS; +import static no.unit.nva.search2.constant.Words.NYNORSK_CODE; +import static no.unit.nva.search2.constant.Words.PUBLISHED_FILE; +import static no.unit.nva.search2.constant.Words.SAMI_CODE; +import static no.unit.nva.search2.constant.Words.TYPE; +import java.util.stream.Stream; +import nva.commons.core.Environment; +import org.opensearch.search.aggregations.AggregationBuilders; +import org.opensearch.search.aggregations.bucket.nested.NestedAggregationBuilder; +import org.opensearch.search.aggregations.bucket.terms.IncludeExclude; +import org.opensearch.search.aggregations.bucket.terms.TermsAggregationBuilder; + +public final class Functions { + + static final Environment ENVIRONMENT = new Environment(); + + public static String jsonPath(String... args) { + return String.join(DOT, args); + } + + public static String readSearchInfrastructureAuthUri() { + return ENVIRONMENT.readEnv("SEARCH_INFRASTRUCTURE_AUTH_URI"); + } + + public static String readSearchInfrastructureApiUri() { + return ENVIRONMENT.readEnv("SEARCH_INFRASTRUCTURE_API_URI"); + } + + public static String readApiHost() { + return ENVIRONMENT.readEnv("API_HOST"); + } + + static TermsAggregationBuilder generateSimpleAggregation(String term, String field) { + return AggregationBuilders + .terms(term) + .field(field) + .size(Defaults.DEFAULT_AGGREGATION_SIZE); + } + + static NestedAggregationBuilder generateObjectLabelsAggregation(String name, String path) { + return new NestedAggregationBuilder(name, path) + .subAggregation(generateIdAggregation(path)); + } + + static TermsAggregationBuilder generateIdAggregation(String object) { + return new TermsAggregationBuilder(ID) + .field(jsonPath(object, ID)) + .size(Defaults.DEFAULT_AGGREGATION_SIZE) + .subAggregation(generateLabelsAggregation(object)); + } + + static NestedAggregationBuilder generateLabelsAggregation(String jsonPath) { + var nestedAggregation = new NestedAggregationBuilder(LABELS, jsonPath(jsonPath, LABELS)); + Stream.of(BOKMAAL_CODE, ENGLISH_CODE, NYNORSK_CODE, SAMI_CODE) + .map(code -> generateSimpleAggregation(code, jsonPath(jsonPath, LABELS, code, KEYWORD))) + .forEach(nestedAggregation::subAggregation); + return nestedAggregation; + } + + static TermsAggregationBuilder generateHasFileAggregation() { + var include = new IncludeExclude(PUBLISHED_FILE, ""); + return AggregationBuilders + .terms(ASSOCIATED_ARTIFACTS) + .field(jsonPath(ASSOCIATED_ARTIFACTS, TYPE, KEYWORD)) + .includeExclude(include) + .size(Defaults.DEFAULT_AGGREGATION_SIZE) + .subAggregation( + generateSimpleAggregation("public", jsonPath(ASSOCIATED_ARTIFACTS, ADMINSTRATIVE_AGREEMENT)) + + ); + } +} diff --git a/search-commons/src/main/java/no/unit/nva/search2/constant/ImportCandidate.java b/search-commons/src/main/java/no/unit/nva/search2/constant/ImportCandidate.java new file mode 100644 index 000000000..b116c7364 --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/constant/ImportCandidate.java @@ -0,0 +1,48 @@ +package no.unit.nva.search2.constant; + +import static no.unit.nva.search2.constant.Functions.generateHasFileAggregation; +import static no.unit.nva.search2.constant.Functions.generateObjectLabelsAggregation; +import static no.unit.nva.search2.constant.Functions.generateSimpleAggregation; +import static no.unit.nva.search2.constant.Words.DOI; +import static no.unit.nva.search2.constant.Words.DOT; +import static no.unit.nva.search2.constant.Words.KEYWORD; +import static no.unit.nva.search2.constant.Words.PIPE; +import java.util.List; +import org.opensearch.search.aggregations.AbstractAggregationBuilder; + +public final class ImportCandidate { + + public static final String ADDITIONAL_IDENTIFIERS_KEYWORD = "additionalIdentifiers.value.keyword"; + public static final String CANDIDATE_STATUS = "candidateStatus"; + public static final String COLLABORATION_TYPE = "collaborationType"; + public static final String COLLABORATION_TYPE_KEYWORD = COLLABORATION_TYPE + DOT + KEYWORD; + public static final String CONTRIBUTORS_IDENTITY_ID = "contributors.identity.id"; + public static final String CONTRIBUTORS_IDENTITY_NAME = "contributors.identity.name"; + public static final String CONTRIBUTOR_IDENTITY_KEYWORDS = + CONTRIBUTORS_IDENTITY_ID + DOT + KEYWORD + PIPE + CONTRIBUTORS_IDENTITY_NAME + DOT + KEYWORD; + public static final String DOI_KEYWORD = DOI + DOT + KEYWORD; + public static final String IDENTIFIER = "id.keyword"; + public static final String IMPORTED_BY_USER = "importedByUser"; + public static final String IMPORT_CANDIDATES_INDEX_NAME = "import-candidates"; + public static final String IMPORT_STATUS_SET_BY_KEYWORD = "importStatus.setBy.keyword"; + public static final String INSTANCE_TYPE = "instanceType"; + public static final String INSTANCE_TYPE_KEYWORD = "publicationInstance.type"; + public static final String MAIN_TITLE_KEYWORD = "mainTitle.keyword"; + public static final String PUBLICATION_INSTANCE_TYPE = "publicationInstance.type"; + public static final String PUBLICATION_YEAR = "publicationYear"; + public static final String PUBLICATION_YEAR_KEYWORD = PUBLICATION_YEAR + DOT + KEYWORD; + public static final String PUBLISHER_ID_KEYWORD = "publisher.id.keyword"; + public static final String STATUS_TYPE_KEYWORD = "importStatus.candidateStatus.keyword"; + public static final String TYPE_KEYWORD = "type.keyword"; + + public static final List>> + IMPORT_CANDIDATES_AGGREGATIONS = List.of( + generateSimpleAggregation(CANDIDATE_STATUS, STATUS_TYPE_KEYWORD), + generateSimpleAggregation(PUBLICATION_YEAR, PUBLICATION_YEAR_KEYWORD), + generateSimpleAggregation(INSTANCE_TYPE, PUBLICATION_INSTANCE_TYPE), + generateSimpleAggregation(COLLABORATION_TYPE, COLLABORATION_TYPE_KEYWORD), + generateSimpleAggregation(IMPORTED_BY_USER, IMPORT_STATUS_SET_BY_KEYWORD), + generateObjectLabelsAggregation("organization", "organizations"), + generateHasFileAggregation() + ); +} \ No newline at end of file diff --git a/search-commons/src/main/java/no/unit/nva/search2/constant/Patterns.java b/search-commons/src/main/java/no/unit/nva/search2/constant/Patterns.java index 5796f6cb1..6489cd547 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/constant/Patterns.java +++ b/search-commons/src/main/java/no/unit/nva/search2/constant/Patterns.java @@ -4,21 +4,38 @@ @JacocoGenerated public class Patterns { - - public static final String PATTERN_IS_BOOLEAN = "true|false|1|0"; + + public static final String PATTERN_IS_IGNORE_CASE = "(?i)"; + public static final String PATTERN_IS_BOOLEAN = PATTERN_IS_IGNORE_CASE + "(true|false|1|0)"; + + public static final String PATTERN_IS_ADD_SLASH = "\\\\$1"; + public static final String PATTERN_IS_ASC_DESC_VALUE = "(?i)asc|desc"; + public static final String PATTERN_IS_ASC_OR_DESC_GROUP = "(?i) (asc|desc)"; + public static final String PATTERN_IS_CATEGORY_KEYS = "(?i)instance.?type|category"; + public static final String PATTERN_IS_CATEGORY_NOT_KEYS = "(?i)instance.?type.?not|category.?not"; + public static final String PATTERN_IS_CATEGORY_SHOULD_KEYS = "(?i)instance.?type.?should|category.?should"; /** - * Pattern for matching a date string. - * yyyy | yyyy-MM-dd | yyyy-MM-ddTHH:mm:ssZ | yyyy-MM-ddTHH:mm:ss.SSSZ + * Pattern for matching a date string. yyyy | yyyy-MM-dd | yyyy-MM-ddTHH:mm:ssZ | yyyy-MM-ddTHH:mm:ss.SSSZ */ public static final String PATTERN_IS_DATE = "\\d{4}(-\\d{2}(-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?Z?)?)?)?"; - - public static final String PATTERN_IS_URI = "https?://[^\\s/$.?#].[^\\s]*"; - public static final String PATTERN_IS_ADD_SLASH = "\\\\$1"; - public static final String PATTERN_IS_IGNORE_CASE = "(?i)"; + public static final String PATTERN_IS_DOC_COUNT_ERROR_UPPER_BOUND = "(?i)doc.?count.?error.?upper.?bound"; + public static final String PATTERN_IS_FROM_KEY = "(?i)offset|from"; public static final String PATTERN_IS_NONE_OR_ONE = ".?"; public static final String PATTERN_IS_NON_EMPTY = ".+"; public static final String PATTERN_IS_NUMBER = "[0-9]\\d*"; + public static final String PATTERN_IS_PUBLICATION_YEAR_KEYS = "(?i)year.?reported|publication.?year"; + public static final String PATTERN_IS_PUBLICATION_YEAR_SHOULD_KEYS = "(?i)year.?reported.?should|publication" + + ".?year.?should"; + public static final String PATTERN_IS_SEARCH_ALL_KEY = "(?i)search.?all|query"; + public static final String PATTERN_IS_SELECTED_GROUP = ":$1"; + public static final String PATTERN_IS_SIZE_KEY = "(?i)per.?page|results|limit|size"; + public static final String PATTERN_IS_SORT_KEY = "(?i)order.?by|sort"; + public static final String PATTERN_IS_SORT_ORDER_KEY = "(?i)sort.?order|order"; + public static final String PATTERN_IS_SUM_OTHER_DOC_COUNT = PATTERN_IS_IGNORE_CASE + "sum.?other.?doc.?count"; + public static final String PATTERN_IS_URI = "https?://[^\\s/$.?#].[^\\s]*"; + public static final String PATTERN_IS_URL_PARAM_INDICATOR = "\\?"; + /** * Pattern for matching a funding string. diff --git a/search-commons/src/main/java/no/unit/nva/search2/constant/Resource.java b/search-commons/src/main/java/no/unit/nva/search2/constant/Resource.java new file mode 100644 index 000000000..4910ca7e0 --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/constant/Resource.java @@ -0,0 +1,127 @@ +package no.unit.nva.search2.constant; + +import static no.unit.nva.search2.constant.Functions.generateHasFileAggregation; +import static no.unit.nva.search2.constant.Functions.generateLabelsAggregation; +import static no.unit.nva.search2.constant.Functions.generateObjectLabelsAggregation; +import static no.unit.nva.search2.constant.Functions.generateSimpleAggregation; +import static no.unit.nva.search2.constant.Functions.jsonPath; +import static no.unit.nva.search2.constant.Words.AFFILIATIONS; +import static no.unit.nva.search2.constant.Words.BOKMAAL_CODE; +import static no.unit.nva.search2.constant.Words.CONTEXT_TYPE; +import static no.unit.nva.search2.constant.Words.CONTRIBUTORS; +import static no.unit.nva.search2.constant.Words.DOI; +import static no.unit.nva.search2.constant.Words.DOT; +import static no.unit.nva.search2.constant.Words.ENGLISH_CODE; +import static no.unit.nva.search2.constant.Words.ENTITY_DESCRIPTION; +import static no.unit.nva.search2.constant.Words.FUNDINGS; +import static no.unit.nva.search2.constant.Words.FUNDING_SOURCE; +import static no.unit.nva.search2.constant.Words.ID; +import static no.unit.nva.search2.constant.Words.IDENTIFIER; +import static no.unit.nva.search2.constant.Words.IDENTITY; +import static no.unit.nva.search2.constant.Words.INSTANCE_TYPE; +import static no.unit.nva.search2.constant.Words.KEYWORD; +import static no.unit.nva.search2.constant.Words.LABELS; +import static no.unit.nva.search2.constant.Words.NAME; +import static no.unit.nva.search2.constant.Words.NYNORSK_CODE; +import static no.unit.nva.search2.constant.Words.ORC_ID; +import static no.unit.nva.search2.constant.Words.OWNER; +import static no.unit.nva.search2.constant.Words.OWNER_AFFILIATION; +import static no.unit.nva.search2.constant.Words.PIPE; +import static no.unit.nva.search2.constant.Words.PUBLICATION_CONTEXT; +import static no.unit.nva.search2.constant.Words.PUBLICATION_DATE; +import static no.unit.nva.search2.constant.Words.PUBLICATION_INSTANCE; +import static no.unit.nva.search2.constant.Words.REFERENCE; +import static no.unit.nva.search2.constant.Words.RESOURCE_OWNER; +import static no.unit.nva.search2.constant.Words.SAMI_CODE; +import static no.unit.nva.search2.constant.Words.SOURCE; +import static no.unit.nva.search2.constant.Words.TOP_LEVEL_ORGANIZATION; +import static no.unit.nva.search2.constant.Words.TOP_LEVEL_ORGANIZATIONS; +import static no.unit.nva.search2.constant.Words.TYPE; +import static no.unit.nva.search2.constant.Words.USER; +import static no.unit.nva.search2.constant.Words.USER_AFFILIATION; +import static no.unit.nva.search2.constant.Words.YEAR; +import java.util.List; +import org.opensearch.search.aggregations.AbstractAggregationBuilder; + +public class Resource { + + public static final String IDENTIFIER_KEYWORD = IDENTIFIER + DOT + KEYWORD; + public static final String CONTRIBUTORS_AFFILIATION_ID_KEYWORD = + jsonPath(ENTITY_DESCRIPTION, CONTRIBUTORS, AFFILIATIONS, ID, KEYWORD); + public static final String CONTRIBUTORS_AFFILIATION_LABELS = + jsonPath(ENTITY_DESCRIPTION, CONTRIBUTORS, AFFILIATIONS, LABELS); + public static final String CONTRIBUTORS_IDENTITY_ID = + jsonPath(ENTITY_DESCRIPTION, CONTRIBUTORS, IDENTITY, ID); + public static final String CONTRIBUTORS_IDENTITY_NAME_KEYWORD = + jsonPath(ENTITY_DESCRIPTION, CONTRIBUTORS, IDENTITY, NAME, KEYWORD); + public static final String CONTRIBUTORS_IDENTITY_ORC_ID_KEYWORD = + jsonPath(ENTITY_DESCRIPTION, CONTRIBUTORS, IDENTITY, ORC_ID, KEYWORD); + public static final String ENTITY_DESCRIPTION_PUBLICATION_DATE_YEAR = + jsonPath(ENTITY_DESCRIPTION, PUBLICATION_DATE, YEAR); + public static final String REFERENCE_DOI_KEYWORD = + jsonPath(ENTITY_DESCRIPTION, REFERENCE, DOI, KEYWORD); + public static final String PUBLICATION_CONTEXT_ISBN_LIST = + jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, "isbnList"); + public static final String PUBLICATION_CONTEXT_ONLINE_ISSN_KEYWORD = + jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, "onlineIssn", KEYWORD); + public static final String PUBLICATION_CONTEXT_PRINT_ISSN_KEYWORD = + jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, "printIssn", KEYWORD); + public static final String PUBLICATION_CONTEXT_TYPE_KEYWORD = + jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, TYPE, KEYWORD); + public static final String PUBLICATION_INSTANCE_TYPE = + jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_INSTANCE, TYPE); + public static final String ENTITY_DESCRIPTION_MAIN_TITLE = ENTITY_DESCRIPTION + DOT + Words.MAIN_TITLE; + public static final String ENTITY_DESCRIPTION_MAIN_TITLE_KEYWORD = ENTITY_DESCRIPTION_MAIN_TITLE + DOT + KEYWORD; + public static final String FUNDINGS_SOURCE_LABELS = jsonPath(FUNDINGS, SOURCE, LABELS); + public static final String RESOURCE_OWNER_OWNER_AFFILIATION_KEYWORD = + jsonPath(RESOURCE_OWNER, OWNER_AFFILIATION, KEYWORD); + public static final String RESOURCE_OWNER_OWNER_KEYWORD = jsonPath(RESOURCE_OWNER, OWNER, KEYWORD); + + + public static final String ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_LABELS_KEYWORD = + jsonPath(CONTRIBUTORS_AFFILIATION_LABELS, ENGLISH_CODE, KEYWORD) + + PIPE + jsonPath(CONTRIBUTORS_AFFILIATION_LABELS, NYNORSK_CODE, KEYWORD) + + PIPE + jsonPath(CONTRIBUTORS_AFFILIATION_LABELS, BOKMAAL_CODE, KEYWORD) + + PIPE + jsonPath(CONTRIBUTORS_AFFILIATION_LABELS, SAMI_CODE, KEYWORD); + + public static final String ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION = + CONTRIBUTORS_AFFILIATION_ID_KEYWORD + + PIPE + ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_LABELS_KEYWORD; + + public static final String ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY = + CONTRIBUTORS_IDENTITY_ID + + PIPE + CONTRIBUTORS_IDENTITY_NAME_KEYWORD; + + public static final String ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ISSN = + PUBLICATION_CONTEXT_ONLINE_ISSN_KEYWORD + + PIPE + PUBLICATION_CONTEXT_PRINT_ISSN_KEYWORD; + + public static final String FUNDINGS_IDENTIFIER_FUNDINGS_SOURCE_IDENTIFIER = + jsonPath(FUNDINGS, IDENTIFIER_KEYWORD + PIPE + FUNDINGS, SOURCE, IDENTIFIER); + + public static final String FUNDINGS_SOURCE_IDENTIFIER_FUNDINGS_SOURCE_LABELS = + FUNDINGS_IDENTIFIER_FUNDINGS_SOURCE_IDENTIFIER + + PIPE + jsonPath(FUNDINGS_SOURCE_LABELS, ENGLISH_CODE, KEYWORD) + + PIPE + jsonPath(FUNDINGS_SOURCE_LABELS, NYNORSK_CODE, KEYWORD) + + PIPE + jsonPath(FUNDINGS_SOURCE_LABELS, BOKMAAL_CODE, KEYWORD) + + PIPE + jsonPath(FUNDINGS_SOURCE_LABELS, SAMI_CODE, KEYWORD); + + public static final String PARENT_PUBLICATION_ID = + jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_INSTANCE, "corrigendumFor", KEYWORD) + + PIPE + jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_INSTANCE, "manifestations", ID, KEYWORD) + + PIPE + jsonPath(ENTITY_DESCRIPTION, REFERENCE, PUBLICATION_CONTEXT, ID, KEYWORD); + + public static final List>> + RESOURCES_AGGREGATIONS = List.of( + generateSimpleAggregation(USER, RESOURCE_OWNER_OWNER_KEYWORD), + generateSimpleAggregation(USER_AFFILIATION, RESOURCE_OWNER_OWNER_AFFILIATION_KEYWORD), + generateSimpleAggregation(INSTANCE_TYPE, PUBLICATION_INSTANCE_TYPE), + generateSimpleAggregation(CONTEXT_TYPE, PUBLICATION_CONTEXT_TYPE_KEYWORD), + generateSimpleAggregation(FUNDING_SOURCE, jsonPath(FUNDINGS, SOURCE, IDENTIFIER)) + .subAggregation(generateLabelsAggregation(jsonPath(FUNDINGS, SOURCE))), + generateObjectLabelsAggregation(TOP_LEVEL_ORGANIZATION, TOP_LEVEL_ORGANIZATIONS), + generateSimpleAggregation(TOP_LEVEL_ORGANIZATION +"1", jsonPath(TOP_LEVEL_ORGANIZATIONS,ID)) + .subAggregation(generateLabelsAggregation(jsonPath(TOP_LEVEL_ORGANIZATIONS, ID))), + generateHasFileAggregation() + ); +} diff --git a/search-commons/src/main/java/no/unit/nva/search2/constant/Words.java b/search-commons/src/main/java/no/unit/nva/search2/constant/Words.java new file mode 100644 index 000000000..eab95a300 --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/constant/Words.java @@ -0,0 +1,76 @@ +package no.unit.nva.search2.constant; + +import nva.commons.core.JacocoGenerated; + +@JacocoGenerated +public final class Words { + + public static final String ADMINSTRATIVE_AGREEMENT = "administrativeAgreement"; + public static final String AFFILIATIONS = "affiliations"; + public static final String ALL = "all"; + public static final String AMPERSAND = "&"; + public static final String ASSOCIATED_ARTIFACTS = "associatedArtifacts"; + public static final String ASTERISK = "*"; + public static final String BOKMAAL_CODE = "nb"; + public static final String COLON = ":"; + public static final String COMMA = ","; + public static final String CONTEXT_TYPE = "contextType"; + public static final String CONTRIBUTORS = "contributors"; + public static final String COUNT = "count"; + public static final String CREATED_DATE = "createdDate"; + public static final String DOI = "doi"; + public static final String DOT = "."; + public static final String ENGLISH_CODE = "en"; + public static final String ENTITY_DESCRIPTION = "entityDescription"; + public static final String EQUAL = "="; + public static final String FROM = "FROM"; + public static final String FUNDINGS = "fundings"; + public static final String FUNDING_SOURCE = "fundingSource"; + public static final String ID = "id"; + public static final String IDENTIFIER = "identifier"; + public static final String IDENTITY = "identity"; + public static final String INSTANCE_TYPE = "instanceType"; + public static final String JANUARY_FIRST = "-01-01"; + public static final String KEYWORD = "keyword"; + public static final String LABELS = "labels"; + public static final String MAIN_TITLE = "mainTitle"; + public static final String MODIFIED_DATE = "modifiedDate"; + public static final String NAME = "name"; + public static final String NYNORSK_CODE = "nn"; + public static final String ORC_ID = "orcId"; + public static final String OWNER = "owner"; + public static final String OWNER_AFFILIATION = "ownerAffiliation"; + public static final String PIPE = "|"; + public static final String PLUS = "+"; + public static final String PREFIX = "("; + public static final String PROJECTS_ID = "projects.id"; + public static final String PUBLICATION_CONTEXT = "publicationContext"; + public static final String PUBLICATION_DATE = "publicationDate"; + public static final String PUBLICATION_INSTANCE = "publicationInstance"; + public static final String PUBLISHED_DATE = "publishedDate"; + public static final String PUBLISHED_FILE = "PublishedFile"; + public static final String Q = "q"; + public static final String QUOTE = "'"; + public static final String REFERENCE = "reference"; + public static final String RESOURCES = "resources"; + public static final String RESOURCE_OWNER = "resourceOwner"; + public static final String SAMI_CODE = "sme"; + public static final String SEARCH = "_search"; + public static final String SEARCH_AFTER = "SEARCH_AFTER"; + public static final String SEARCH_ALL = "SEARCH_ALL"; + public static final String SEARCH_INFRASTRUCTURE_CREDENTIALS = "SearchInfrastructureCredentials"; + public static final String SOURCE = "source"; + public static final String SORT = "SORT"; + public static final String SPACE = " "; + public static final String SUFFIX = ")"; + public static final String TEXT_CSV = "text/csv"; + public static final String TOP_LEVEL_ORGANIZATION = "topLevelOrganization"; + public static final String TOP_LEVEL_ORGANIZATIONS = "topLevelOrganizations"; + public static final String TYPE = "type"; + public static final String UNDERSCORE = "_"; + public static final String USER = "user"; + public static final String USER_AFFILIATION = "userAffiliation"; + public static final String YEAR = "year"; + public static final String ZERO = "0"; + +} diff --git a/search-commons/src/main/java/no/unit/nva/search2/dto/Facet.java b/search-commons/src/main/java/no/unit/nva/search2/dto/Facet.java new file mode 100644 index 000000000..1cb954789 --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/dto/Facet.java @@ -0,0 +1,15 @@ +package no.unit.nva.search2.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.net.URI; +import java.util.Map; +import java.util.Objects; +import no.unit.nva.commons.json.JsonSerializable; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record Facet(URI id, String key, Integer count, Map labels) implements JsonSerializable { + + public Facet { + Objects.requireNonNull(count); + } +} diff --git a/search-commons/src/main/java/no/unit/nva/search2/dto/FacetsBuilder.java b/search-commons/src/main/java/no/unit/nva/search2/dto/FacetsBuilder.java new file mode 100644 index 000000000..80b18520b --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/dto/FacetsBuilder.java @@ -0,0 +1,45 @@ +package no.unit.nva.search2.dto; + +import static nva.commons.core.attempt.Try.attempt; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import java.net.URI; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import no.unit.nva.commons.json.JsonUtils; +import nva.commons.core.paths.UriWrapper; +import org.jetbrains.annotations.NotNull; + +public final class FacetsBuilder { + + public static Map> build(JsonNode aggregations, URI id) { + return jsonNodeToMapOfFacets(aggregations) + .entrySet().stream() + .map((entry) -> addIdToFacets(entry, id)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); +} + + private static Map> jsonNodeToMapOfFacets(JsonNode aggregations) { + final var typeReference = new TypeReference>>() { }; + return attempt(() -> JsonUtils.dtoObjectMapper.readValue(aggregations.toPrettyString(), typeReference)) + .orElseThrow(); + } + + @NotNull + private static Map.Entry> addIdToFacets(Map.Entry> entry, URI id) { + final var uriwrap = UriWrapper.fromUri(id); + var facets = entry.getValue().stream() + .map(facet -> new Facet( + createUriFilterByKey(entry.getKey(), facet.key(), uriwrap), + facet.key(), + facet.count(), + facet.labels()) + ).toList(); + return Map.entry(entry.getKey(), facets); + } + + private static URI createUriFilterByKey(String keyName, String keyValue, UriWrapper uriwrap) { + return uriwrap.addQueryParameter(keyName, keyValue).getUri(); + } +} diff --git a/search-commons/src/main/java/no/unit/nva/search2/dto/PagedSearch.java b/search-commons/src/main/java/no/unit/nva/search2/dto/PagedSearch.java new file mode 100644 index 000000000..436796a46 --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/dto/PagedSearch.java @@ -0,0 +1,30 @@ +package no.unit.nva.search2.dto; + +import static java.util.Objects.nonNull; +import static no.unit.nva.search2.constant.Defaults.PAGINATED_SEARCH_RESULT_CONTEXT; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import java.net.URI; +import java.util.List; +import java.util.Map; +import no.unit.nva.commons.json.JsonSerializable; + +public record PagedSearch( + URI id, + int totalHits, + List hits, + URI nextResults, + URI nextSearchAfterResults, + URI previousResults, + Map> aggregations) implements JsonSerializable { + + @JsonProperty("@context") + public URI context() { + return PAGINATED_SEARCH_RESULT_CONTEXT; + } + + @Override + public List hits() { + return nonNull(hits) ? hits : List.of(); + } +} diff --git a/search-commons/src/main/java/no/unit/nva/search2/dto/PagedSearchBuilder.java b/search-commons/src/main/java/no/unit/nva/search2/dto/PagedSearchBuilder.java new file mode 100644 index 000000000..43c7918e9 --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/dto/PagedSearchBuilder.java @@ -0,0 +1,87 @@ +package no.unit.nva.search2.dto; + +import static java.util.Objects.isNull; +import com.fasterxml.jackson.databind.JsonNode; +import java.net.URI; +import java.util.List; +import java.util.Map; +import nva.commons.core.paths.UriWrapper; +import org.jetbrains.annotations.Nullable; + +public class PagedSearchBuilder { + + private URI id; + private int totalHits; + private List hits; + private URI nextResults; + private URI nextSearchAfterResults; + private URI previousResults; + private Map> aggregations; + + @SuppressWarnings("PMD.NullAssignment") + public PagedSearch build() { + if (isNull(this.nextResults)) { + this.nextSearchAfterResults = null; // null values are not serialized + } + return new PagedSearch( + id, + totalHits, + hits, + nextResults, + nextSearchAfterResults, + previousResults, + aggregations + ); + } + + public PagedSearchBuilder withIds(URI gatewayUri, Map requestParameter, Integer offset, + Integer size) { + this.id = createUriOffsetRef(requestParameter, offset, gatewayUri); + this.previousResults = createUriOffsetRef(requestParameter, offset - size, gatewayUri); + this.nextResults = createNextResults(requestParameter, offset + size, totalHits, gatewayUri); + return this; + } + + public PagedSearchBuilder withNextResultsBySortKey(URI nextSearchAfterResults) { + this.nextSearchAfterResults = nextSearchAfterResults; + return this; + } + + public PagedSearchBuilder withTotalHits(int totalHits) { + this.totalHits = totalHits; + return this; + } + + public PagedSearchBuilder withHits(List hits) { + this.hits = hits; + return this; + } + + public PagedSearchBuilder withAggregations(JsonNode aggregations) { + + if (isNull(aggregations)) { + return this; + } + this.aggregations = FacetsBuilder.build(aggregations, this.id); + return this; + } + + @Nullable + private URI createNextResults(Map requestParameter, Integer offset, Integer totalSize, + URI gatewayUri) { + return offset < totalSize + ? createUriOffsetRef(requestParameter, offset, gatewayUri) + : null; + } + + private URI createUriOffsetRef(Map params, Integer offset, URI gatewayUri) { + if (offset < 0) { + return null; + } + + params.put("FROM", String.valueOf(offset)); + return UriWrapper.fromUri(gatewayUri) + .addQueryParameters(params) + .getUri(); + } +} \ No newline at end of file diff --git a/search-commons/src/main/java/no/unit/nva/search2/model/UserSettings.java b/search-commons/src/main/java/no/unit/nva/search2/dto/UserSettings.java similarity index 81% rename from search-commons/src/main/java/no/unit/nva/search2/model/UserSettings.java rename to search-commons/src/main/java/no/unit/nva/search2/dto/UserSettings.java index 924936238..ea5cd0823 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/model/UserSettings.java +++ b/search-commons/src/main/java/no/unit/nva/search2/dto/UserSettings.java @@ -1,8 +1,6 @@ -package no.unit.nva.search2.model; - +package no.unit.nva.search2.dto; import com.fasterxml.jackson.annotation.JsonInclude; - import java.util.List; diff --git a/search-commons/src/main/java/no/unit/nva/search2/enums/ImportCandidateParameter.java b/search-commons/src/main/java/no/unit/nva/search2/enums/ImportCandidateParameter.java new file mode 100644 index 000000000..6bc8ab2e5 --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/enums/ImportCandidateParameter.java @@ -0,0 +1,220 @@ +package no.unit.nva.search2.enums; + +import static java.util.Objects.nonNull; +import static no.unit.nva.search2.constant.ImportCandidate.ADDITIONAL_IDENTIFIERS_KEYWORD; +import static no.unit.nva.search2.constant.ImportCandidate.COLLABORATION_TYPE_KEYWORD; +import static no.unit.nva.search2.constant.ImportCandidate.INSTANCE_TYPE_KEYWORD; +import static no.unit.nva.search2.constant.ImportCandidate.PUBLICATION_INSTANCE_TYPE; +import static no.unit.nva.search2.constant.ImportCandidate.PUBLICATION_YEAR_KEYWORD; +import static no.unit.nva.search2.constant.ImportCandidate.PUBLISHER_ID_KEYWORD; +import static no.unit.nva.search2.constant.ImportCandidate.STATUS_TYPE_KEYWORD; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_ASC_DESC_VALUE; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_FROM_KEY; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_IGNORE_CASE; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_NONE_OR_ONE; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_SEARCH_ALL_KEY; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_SIZE_KEY; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_SORT_KEY; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_SORT_ORDER_KEY; +import static no.unit.nva.search2.constant.Words.COLON; +import static no.unit.nva.search2.constant.Words.Q; +import static no.unit.nva.search2.constant.Words.UNDERSCORE; +import static no.unit.nva.search2.enums.ParameterKey.FieldOperator.MUST; +import static no.unit.nva.search2.enums.ParameterKey.FieldOperator.MUST_NOT; +import static no.unit.nva.search2.enums.ParameterKey.FieldOperator.SHOULD; +import static no.unit.nva.search2.enums.ParameterKey.ParamKind.KEYWORD; +import static no.unit.nva.search2.enums.ParameterKey.ParamKind.NUMBER; +import static no.unit.nva.search2.enums.ParameterKey.ParamKind.SORT_KEY; +import static no.unit.nva.search2.enums.ParameterKey.ParamKind.TEXT; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Locale; +import java.util.Set; +import java.util.StringJoiner; +import java.util.stream.Collectors; +import no.unit.nva.search2.constant.ImportCandidate; +import no.unit.nva.search2.constant.Words; +import nva.commons.core.JacocoGenerated; + +/** + * Enum for all the parameters that can be used to query the search index. This enum needs to implement these + * parameters + * cristin API + */ + +public enum ImportCandidateParameter implements ParameterKey { + INVALID(TEXT), + // Parameters converted to Lucene query + ADDITIONAL_IDENTIFIERS(KEYWORD, MUST, ADDITIONAL_IDENTIFIERS_KEYWORD), + ADDITIONAL_IDENTIFIERS_NOT(KEYWORD, MUST_NOT, ADDITIONAL_IDENTIFIERS_KEYWORD), + ADDITIONAL_IDENTIFIERS_SHOULD(TEXT, SHOULD, ADDITIONAL_IDENTIFIERS_KEYWORD), + CATEGORY(KEYWORD, PUBLICATION_INSTANCE_TYPE), + CATEGORY_NOT(KEYWORD, MUST_NOT, PUBLICATION_INSTANCE_TYPE), + CATEGORY_SHOULD(TEXT, SHOULD, PUBLICATION_INSTANCE_TYPE), + CREATED_DATE(ParamKind.DATE, Words.CREATED_DATE), + CONTRIBUTOR(KEYWORD, ImportCandidate.CONTRIBUTOR_IDENTITY_KEYWORDS), + CONTRIBUTOR_NOT(KEYWORD, MUST_NOT, ImportCandidate.CONTRIBUTOR_IDENTITY_KEYWORDS), + CONTRIBUTOR_SHOULD(TEXT, SHOULD, ImportCandidate.CONTRIBUTOR_IDENTITY_KEYWORDS), + COLLABORATION_TYPE(KEYWORD, MUST, COLLABORATION_TYPE_KEYWORD), + COLLABORATION_TYPE_NOT(KEYWORD, MUST_NOT, COLLABORATION_TYPE_KEYWORD), + COLLABORATION_TYPE_SHOULD(TEXT, SHOULD, COLLABORATION_TYPE_KEYWORD), + DOI(KEYWORD, ImportCandidate.DOI_KEYWORD), + DOI_NOT(TEXT, MUST_NOT, ImportCandidate.DOI_KEYWORD), + DOI_SHOULD(TEXT, SHOULD, ImportCandidate.DOI_KEYWORD), + ID(KEYWORD, ImportCandidate.IDENTIFIER), + ID_NOT(KEYWORD, MUST_NOT, ImportCandidate.IDENTIFIER), + ID_SHOULD(TEXT, SHOULD, ImportCandidate.IDENTIFIER), + IMPORT_STATUS(KEYWORD, STATUS_TYPE_KEYWORD), + IMPORT_STATUS_NOT(KEYWORD, MUST_NOT, STATUS_TYPE_KEYWORD), + IMPORT_STATUS_SHOULD(TEXT, SHOULD, STATUS_TYPE_KEYWORD), + INSTANCE_TYPE(KEYWORD, MUST, INSTANCE_TYPE_KEYWORD), + INSTANCE_TYPE_NOT(KEYWORD, MUST_NOT, INSTANCE_TYPE_KEYWORD), + INSTANCE_TYPE_SHOULD(TEXT, SHOULD, INSTANCE_TYPE_KEYWORD), + PUBLICATION_YEAR(KEYWORD, MUST, PUBLICATION_YEAR_KEYWORD), + PUBLICATION_YEAR_BEFORE(NUMBER, FieldOperator.LESS_THAN, PUBLICATION_YEAR_KEYWORD), + PUBLICATION_YEAR_SINCE(NUMBER, FieldOperator.GREATER_THAN_OR_EQUAL_TO, PUBLICATION_YEAR_KEYWORD), + PUBLISHER(KEYWORD, MUST, PUBLISHER_ID_KEYWORD), + PUBLISHER_NOT(KEYWORD, MUST_NOT, PUBLISHER_ID_KEYWORD), + PUBLISHER_SHOULD(TEXT, SHOULD, PUBLISHER_ID_KEYWORD), + TITLE(TEXT, ImportCandidate.MAIN_TITLE_KEYWORD, 2F), + TITLE_NOT(TEXT, MUST_NOT, ImportCandidate.MAIN_TITLE_KEYWORD), + TITLE_SHOULD(TEXT, SHOULD, ImportCandidate.MAIN_TITLE_KEYWORD), + TYPE(KEYWORD, ImportCandidate.TYPE_KEYWORD), + // Query parameters passed to SWS/Opensearch + SEARCH_ALL(TEXT, MUST, Q, PATTERN_IS_SEARCH_ALL_KEY, null, null), + FIELDS(ParamKind.CUSTOM), + // Pagination parameters + PAGE(NUMBER), + FROM(NUMBER, null, null, PATTERN_IS_FROM_KEY, null, null), + SIZE(NUMBER, null, null, PATTERN_IS_SIZE_KEY, null, null), + SORT(SORT_KEY, null, null, PATTERN_IS_SORT_KEY, null, null), + SORT_ORDER(ParamKind.CUSTOM, MUST, null, PATTERN_IS_SORT_ORDER_KEY, PATTERN_IS_ASC_DESC_VALUE, null), + SEARCH_AFTER(ParamKind.CUSTOM); + + public static final int IGNORE_PARAMETER_INDEX = 0; + + public static final Set VALID_LUCENE_PARAMETER_KEYS = + Arrays.stream(ImportCandidateParameter.values()) + .filter(ImportCandidateParameter::isSearchField) + .sorted(ParameterKey::compareAscending) + .collect(Collectors.toCollection(LinkedHashSet::new)); + + private final String key; + private final ValueEncoding encoding; + private final String keyPattern; + private final String validValuePattern; + private final String[] fieldsToSearch; + private final FieldOperator fieldOperator; + private final String errorMsg; + private final ParamKind paramkind; + private final Float boost; + + ImportCandidateParameter(ParamKind kind) { + this(kind, MUST, null, null, null, null); + } + + ImportCandidateParameter(ParamKind kind, String fieldsToSearch) { + this(kind, MUST, fieldsToSearch, null, null, null); + } + + ImportCandidateParameter(ParamKind kind, String fieldsToSearch, Float boost) { + this(kind, MUST, fieldsToSearch, null, null, boost); + } + + ImportCandidateParameter(ParamKind kind, FieldOperator operator, String fieldsToSearch) { + this(kind, operator, fieldsToSearch, null, null, null); + } + + ImportCandidateParameter( + ParamKind kind, FieldOperator operator, String fieldsToSearch, String keyPattern, String valuePattern, + Float boost) { + + this.key = this.name().toLowerCase(Locale.getDefault()); + this.fieldOperator = operator; + this.boost = nonNull(boost) ? boost : 1F; + this.fieldsToSearch = nonNull(fieldsToSearch) + ? fieldsToSearch.split("\\|") + : new String[]{key}; + this.validValuePattern = ParameterKey.getValuePattern(kind, valuePattern); + this.errorMsg = ParameterKey.getErrorMessage(kind); + this.encoding = ParameterKey.getEncoding(kind); + this.keyPattern = nonNull(keyPattern) + ? keyPattern + : PATTERN_IS_IGNORE_CASE + key.replace(UNDERSCORE, PATTERN_IS_NONE_OR_ONE); + this.paramkind = kind; + } + + @Override + public String fieldName() { + return key; + } + + @Override + public Float fieldBoost() { + return boost; + } + + @Override + public ParamKind fieldType() { + return paramkind; + } + + @Override + public String fieldPattern() { + return keyPattern; + } + + @Override + public String valuePattern() { + return validValuePattern; + } + + @Override + public ValueEncoding valueEncoding() { + return encoding; + } + + @Override + public Collection searchFields() { + return Arrays.stream(fieldsToSearch).toList(); + } + + @Override + public FieldOperator searchOperator() { + return fieldOperator; + } + + @Override + public String errorMessage() { + return errorMsg; + } + + @Override + @JacocoGenerated + public String toString() { + return + new StringJoiner(COLON, "Key[", "]") + .add(String.valueOf(ordinal())) + .add(name().toLowerCase(Locale.ROOT)) + .toString(); + } + + public static ImportCandidateParameter keyFromString(String paramName) { + var result = Arrays.stream(ImportCandidateParameter.values()) + .filter(ImportCandidateParameter::ignoreInvalidKey) + .filter(ParameterKey.equalTo(paramName)) + .collect(Collectors.toSet()); + return result.size() == 1 + ? result.stream().findFirst().get() + : INVALID; + } + + private static boolean ignoreInvalidKey(ImportCandidateParameter f) { + return f.ordinal() > IGNORE_PARAMETER_INDEX; + } + + private static boolean isSearchField(ImportCandidateParameter f) { + return f.ordinal() > IGNORE_PARAMETER_INDEX && f.ordinal() < SEARCH_ALL.ordinal(); + } +} \ No newline at end of file diff --git a/search-commons/src/main/java/no/unit/nva/search2/model/ResourceSortKeys.java b/search-commons/src/main/java/no/unit/nva/search2/enums/ImportCandidateSort.java similarity index 57% rename from search-commons/src/main/java/no/unit/nva/search2/model/ResourceSortKeys.java rename to search-commons/src/main/java/no/unit/nva/search2/enums/ImportCandidateSort.java index c561eae0b..e7457d19a 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/model/ResourceSortKeys.java +++ b/search-commons/src/main/java/no/unit/nva/search2/enums/ImportCandidateSort.java @@ -1,8 +1,8 @@ -package no.unit.nva.search2.model; +package no.unit.nva.search2.enums; -import static no.unit.nva.search2.constant.ApplicationConstants.UNDERSCORE; import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_IGNORE_CASE; import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_NONE_OR_ONE; +import static no.unit.nva.search2.constant.Words.UNDERSCORE; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; @@ -10,32 +10,29 @@ import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; +import no.unit.nva.search2.constant.ImportCandidate; +import no.unit.nva.search2.constant.Words; -public enum ResourceSortKeys { +public enum ImportCandidateSort { INVALID(""), - CATEGORY("entityDescription.reference.publicationInstance.type"), - CREATED_DATE("createdDate"), - MODIFIED_DATE("modifiedDate"), - PUBLISHED_DATE("publishedDate"), - TITLE("entityDescription.mainTitle"), - UNIT_ID("entityDescription.contributors.affiliation.id"), - USER("(?i)(user)|(owner)", "resourceOwner.owner"); + COLLABORATION_TYPE(ImportCandidate.COLLABORATION_TYPE_KEYWORD), + CREATED_DATE(Words.CREATED_DATE), + INSTANCE_TYPE(ImportCandidate.INSTANCE_TYPE_KEYWORD), + PUBLICATION_YEAR(ImportCandidate.PUBLICATION_YEAR_KEYWORD), + TITLE(ImportCandidate.MAIN_TITLE_KEYWORD), + TYPE(ImportCandidate.TYPE_KEYWORD); - public static final Set VALID_SORT_PARAMETER_KEYS = - Arrays.stream(ResourceSortKeys.values()) - .sorted(ResourceSortKeys::compareAscending) + public static final Set VALID_SORT_PARAMETER_KEYS = + Arrays.stream(ImportCandidateSort.values()) + .sorted(ImportCandidateSort::compareAscending) .skip(1) // skip INVALID .collect(Collectors.toCollection(LinkedHashSet::new)); private final String keyValidationRegEx; private final String fieldName; - ResourceSortKeys(String pattern, String fieldName) { - this.keyValidationRegEx = pattern; - this.fieldName = fieldName; - } - ResourceSortKeys(String fieldName) { + ImportCandidateSort(String fieldName) { this.keyValidationRegEx = getIgnoreCaseAndUnderscoreKeyExpression(this.name()); this.fieldName = fieldName; } @@ -48,27 +45,27 @@ public String getFieldName() { return fieldName; } - public static ResourceSortKeys fromSortKey(String keyName) { - var result = Arrays.stream(ResourceSortKeys.values()) - .filter(ResourceSortKeys.equalTo(keyName)) + public static ImportCandidateSort fromSortKey(String keyName) { + var result = Arrays.stream(ImportCandidateSort.values()) + .filter(ImportCandidateSort.equalTo(keyName)) .collect(Collectors.toSet()); return result.size() == 1 ? result.stream().findFirst().get() : INVALID; } - public static Predicate equalTo(String name) { + public static Predicate equalTo(String name) { return key -> name.matches(key.getKeyPattern()); } public static Collection validSortKeys() { return VALID_SORT_PARAMETER_KEYS.stream() - .map(ResourceSortKeys::name) + .map(ImportCandidateSort::name) .map(String::toLowerCase) .toList(); } - private static int compareAscending(ResourceSortKeys key1, ResourceSortKeys key2) { + private static int compareAscending(ImportCandidateSort key1, ImportCandidateSort key2) { return key1.ordinal() - key2.ordinal(); } diff --git a/search-commons/src/main/java/no/unit/nva/search2/model/ParameterKey.java b/search-commons/src/main/java/no/unit/nva/search2/enums/ParameterKey.java similarity index 72% rename from search-commons/src/main/java/no/unit/nva/search2/model/ParameterKey.java rename to search-commons/src/main/java/no/unit/nva/search2/enums/ParameterKey.java index a4d25b29d..ce3680aa1 100644 --- a/search-commons/src/main/java/no/unit/nva/search2/model/ParameterKey.java +++ b/search-commons/src/main/java/no/unit/nva/search2/enums/ParameterKey.java @@ -1,56 +1,54 @@ -package no.unit.nva.search2.model; +package no.unit.nva.search2.enums; import static java.util.Objects.nonNull; import static no.unit.nva.search2.constant.ErrorMessages.INVALID_DATE; import static no.unit.nva.search2.constant.ErrorMessages.INVALID_NUMBER; import static no.unit.nva.search2.constant.ErrorMessages.INVALID_VALUE; import static no.unit.nva.search2.constant.ErrorMessages.INVALID_VALUE_WITH_SORT; -import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_ADD_SLASH; import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_BOOLEAN; import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_DATE; import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_IGNORE_CASE; import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_NONE_OR_ONE; import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_NON_EMPTY; import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_NUMBER; -import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_SPECIAL_CHARACTERS; import java.util.Collection; import java.util.function.Predicate; import nva.commons.core.JacocoGenerated; import org.jetbrains.annotations.NotNull; public interface ParameterKey { - + String fieldName(); - + Float fieldBoost(); - + ParamKind fieldType(); - + String fieldPattern(); - + String valuePattern(); - + ValueEncoding valueEncoding(); - + Collection searchFields(); - + FieldOperator searchOperator(); - + String errorMessage(); - + static Predicate equalTo(String name) { return key -> name.matches(key.fieldPattern()); } - + @NotNull @JacocoGenerated static ValueEncoding getEncoding(ParamKind kind) { return switch (kind) { - case BOOLEAN, NUMBER, CUSTOM -> ValueEncoding.NONE; + case INVALID, NUMBER, BOOLEAN, CUSTOM -> ValueEncoding.NONE; case DATE, KEYWORD, TEXT, SORT_KEY -> ValueEncoding.DECODE; }; } - + @JacocoGenerated static String getErrorMessage(ParamKind kind) { return switch (kind) { @@ -60,51 +58,48 @@ static String getErrorMessage(ParamKind kind) { // case RANGE -> ERROR_MESSAGE_INVALID_VALUE_WITH_RANGE; case SORT_KEY -> INVALID_VALUE_WITH_SORT; case KEYWORD, TEXT, CUSTOM -> INVALID_VALUE; + case INVALID -> "Status INVALID should not raise an exception, Exception"; }; } - + @JacocoGenerated static String getValuePattern(ParamKind kind, String pattern) { - return - nonNull(pattern) ? pattern - : switch (kind) { - case BOOLEAN -> PATTERN_IS_BOOLEAN; - case DATE -> PATTERN_IS_DATE; - case NUMBER -> PATTERN_IS_NUMBER; - // case RANGE -> PATTERN_IS_RANGE; - case KEYWORD, CUSTOM, TEXT, SORT_KEY -> PATTERN_IS_NON_EMPTY; - }; + return nonNull(pattern) ? pattern : switch (kind) { + case BOOLEAN -> PATTERN_IS_BOOLEAN; + case DATE -> PATTERN_IS_DATE; + case NUMBER -> PATTERN_IS_NUMBER; + // case RANGE -> PATTERN_IS_RANGE; + case KEYWORD, CUSTOM, TEXT, SORT_KEY -> PATTERN_IS_NON_EMPTY; + case INVALID -> PATTERN_IS_NONE_OR_ONE; + }; } - + static int compareAscending(Enum key1, Enum key2) { return key1.ordinal() - key2.ordinal(); } - - static String escapeSearchString(String value) { - return value.replaceAll(PATTERN_IS_SPECIAL_CHARACTERS, PATTERN_IS_ADD_SLASH); - } - + + enum ValueEncoding { NONE, DECODE } - + enum ParamKind { - BOOLEAN, DATE, NUMBER, KEYWORD, TEXT, SORT_KEY, CUSTOM + BOOLEAN, DATE, NUMBER, KEYWORD, TEXT, SORT_KEY, CUSTOM, INVALID } - + enum FieldOperator { - MUST(""), + MUST("KEYWORD"), MUST_NOT("NOT"), SHOULD("SHOULD"), GREATER_THAN_OR_EQUAL_TO("SINCE"), LESS_THAN("BEFORE"); - + private final String keyPattern; - + FieldOperator(String pattern) { this.keyPattern = PATTERN_IS_IGNORE_CASE + PATTERN_IS_NONE_OR_ONE + pattern; } - + public String pattern() { return keyPattern; } diff --git a/search-commons/src/main/java/no/unit/nva/search2/enums/ResourceParameter.java b/search-commons/src/main/java/no/unit/nva/search2/enums/ResourceParameter.java new file mode 100644 index 000000000..0e518355d --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/enums/ResourceParameter.java @@ -0,0 +1,279 @@ +package no.unit.nva.search2.enums; + +import static java.util.Objects.nonNull; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_ASC_DESC_VALUE; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_CATEGORY_KEYS; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_CATEGORY_NOT_KEYS; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_CATEGORY_SHOULD_KEYS; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_FROM_KEY; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_FUNDING; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_IGNORE_CASE; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_NONE_OR_ONE; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_PUBLICATION_YEAR_KEYS; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_PUBLICATION_YEAR_SHOULD_KEYS; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_SEARCH_ALL_KEY; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_SIZE_KEY; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_SORT_KEY; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_SORT_ORDER_KEY; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_URI; +import static no.unit.nva.search2.constant.Resource.CONTRIBUTORS_AFFILIATION_ID_KEYWORD; +import static no.unit.nva.search2.constant.Resource.CONTRIBUTORS_IDENTITY_ID; +import static no.unit.nva.search2.constant.Resource.CONTRIBUTORS_IDENTITY_ORC_ID_KEYWORD; +import static no.unit.nva.search2.constant.Resource.ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION; +import static no.unit.nva.search2.constant.Resource.ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY; +import static no.unit.nva.search2.constant.Resource.ENTITY_DESCRIPTION_MAIN_TITLE; +import static no.unit.nva.search2.constant.Resource.ENTITY_DESCRIPTION_PUBLICATION_DATE_YEAR; +import static no.unit.nva.search2.constant.Resource.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ISSN; +import static no.unit.nva.search2.constant.Resource.FUNDINGS_IDENTIFIER_FUNDINGS_SOURCE_IDENTIFIER; +import static no.unit.nva.search2.constant.Resource.FUNDINGS_SOURCE_IDENTIFIER_FUNDINGS_SOURCE_LABELS; +import static no.unit.nva.search2.constant.Resource.IDENTIFIER_KEYWORD; +import static no.unit.nva.search2.constant.Resource.PARENT_PUBLICATION_ID; +import static no.unit.nva.search2.constant.Resource.PUBLICATION_CONTEXT_ISBN_LIST; +import static no.unit.nva.search2.constant.Resource.PUBLICATION_CONTEXT_TYPE_KEYWORD; +import static no.unit.nva.search2.constant.Resource.PUBLICATION_INSTANCE_TYPE; +import static no.unit.nva.search2.constant.Resource.REFERENCE_DOI_KEYWORD; +import static no.unit.nva.search2.constant.Resource.RESOURCE_OWNER_OWNER_AFFILIATION_KEYWORD; +import static no.unit.nva.search2.constant.Resource.RESOURCE_OWNER_OWNER_KEYWORD; +import static no.unit.nva.search2.constant.Words.ASTERISK; +import static no.unit.nva.search2.constant.Words.COLON; +import static no.unit.nva.search2.constant.Words.CREATED_DATE; +import static no.unit.nva.search2.constant.Words.DOT; +import static no.unit.nva.search2.constant.Words.MODIFIED_DATE; +import static no.unit.nva.search2.constant.Words.PROJECTS_ID; +import static no.unit.nva.search2.constant.Words.PUBLISHED_DATE; +import static no.unit.nva.search2.constant.Words.Q; +import static no.unit.nva.search2.constant.Words.TOP_LEVEL_ORGANIZATIONS; +import static no.unit.nva.search2.constant.Words.UNDERSCORE; +import static no.unit.nva.search2.enums.ParameterKey.FieldOperator.MUST; +import static no.unit.nva.search2.enums.ParameterKey.FieldOperator.MUST_NOT; +import static no.unit.nva.search2.enums.ParameterKey.FieldOperator.SHOULD; +import static no.unit.nva.search2.enums.ParameterKey.ParamKind.KEYWORD; +import static no.unit.nva.search2.enums.ParameterKey.ParamKind.NUMBER; +import static no.unit.nva.search2.enums.ParameterKey.ParamKind.TEXT; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Locale; +import java.util.Set; +import java.util.StringJoiner; +import java.util.stream.Collectors; +import no.unit.nva.search2.constant.Words; +import nva.commons.core.JacocoGenerated; + +/** + * Enum for all the parameters that can be used to query the search index. + * This enum needs to implement these parameters + * cristin API + * + */ + +public enum ResourceParameter implements ParameterKey { + INVALID(ParamKind.INVALID), + // Parameters converted to Lucene query + CONTEXT_TYPE(KEYWORD, MUST, PUBLICATION_CONTEXT_TYPE_KEYWORD), + CONTEXT_TYPE_NOT(KEYWORD, MUST_NOT, PUBLICATION_CONTEXT_TYPE_KEYWORD), + CONTEXT_TYPE_SHOULD(KEYWORD, SHOULD, PUBLICATION_CONTEXT_TYPE_KEYWORD), + CONTRIBUTOR_ID(KEYWORD, MUST, CONTRIBUTORS_IDENTITY_ID, null, + PATTERN_IS_URI, null), + CONTRIBUTOR(KEYWORD, ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY), + CONTRIBUTOR_NOT(KEYWORD, MUST_NOT, ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY), + // CONTRIBUTOR_SHOULD(TEXT, SHOULD, ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY), + // TODO fix definition -> CONTRIBUTOR_SHOULD needs text AND keyword. + CREATED_BEFORE(ParamKind.DATE, FieldOperator.LESS_THAN, CREATED_DATE), + CREATED_SINCE(ParamKind.DATE, FieldOperator.GREATER_THAN_OR_EQUAL_TO, CREATED_DATE), + DOI(KEYWORD, REFERENCE_DOI_KEYWORD), + DOI_NOT(TEXT, MUST_NOT, REFERENCE_DOI_KEYWORD), + DOI_SHOULD(TEXT, SHOULD, REFERENCE_DOI_KEYWORD), + FUNDING(KEYWORD, MUST, FUNDINGS_IDENTIFIER_FUNDINGS_SOURCE_IDENTIFIER, null, + PATTERN_IS_FUNDING, null), + FUNDING_SOURCE(KEYWORD, FUNDINGS_SOURCE_IDENTIFIER_FUNDINGS_SOURCE_LABELS), + FUNDING_SOURCE_NOT(KEYWORD, MUST_NOT, FUNDINGS_SOURCE_IDENTIFIER_FUNDINGS_SOURCE_LABELS), + FUNDING_SOURCE_SHOULD(TEXT, SHOULD, FUNDINGS_SOURCE_IDENTIFIER_FUNDINGS_SOURCE_LABELS), + ID(KEYWORD, IDENTIFIER_KEYWORD), + ID_NOT(KEYWORD, MUST_NOT, IDENTIFIER_KEYWORD), + ID_SHOULD(TEXT, SHOULD, IDENTIFIER_KEYWORD), + INSTANCE_TYPE(KEYWORD, MUST, PUBLICATION_INSTANCE_TYPE, + PATTERN_IS_CATEGORY_KEYS, null, null), + INSTANCE_TYPE_NOT(KEYWORD, MUST_NOT, PUBLICATION_INSTANCE_TYPE, + PATTERN_IS_CATEGORY_NOT_KEYS, null, null), + INSTANCE_TYPE_SHOULD(KEYWORD, SHOULD, + PUBLICATION_INSTANCE_TYPE, + PATTERN_IS_CATEGORY_SHOULD_KEYS, null, null), + INSTITUTION(KEYWORD, ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION), + INSTITUTION_NOT(KEYWORD, MUST_NOT, ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION), + INSTITUTION_SHOULD(TEXT, SHOULD, ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION), + ISBN(KEYWORD, PUBLICATION_CONTEXT_ISBN_LIST), + ISBN_NOT(KEYWORD, MUST_NOT, PUBLICATION_CONTEXT_ISBN_LIST), + ISBN_SHOULD(KEYWORD, SHOULD, PUBLICATION_CONTEXT_ISBN_LIST), + ISSN(KEYWORD, ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ISSN), + ISSN_NOT(KEYWORD, MUST_NOT, ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ISSN), + ISSN_SHOULD(KEYWORD, SHOULD, ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ISSN), + ORCID(KEYWORD, CONTRIBUTORS_IDENTITY_ORC_ID_KEYWORD), + ORCID_NOT(KEYWORD, MUST_NOT, CONTRIBUTORS_IDENTITY_ORC_ID_KEYWORD), + ORCID_SHOULD(TEXT, SHOULD, CONTRIBUTORS_IDENTITY_ORC_ID_KEYWORD), + MODIFIED_BEFORE(ParamKind.DATE, FieldOperator.LESS_THAN, MODIFIED_DATE), + MODIFIED_SINCE(ParamKind.DATE, FieldOperator.GREATER_THAN_OR_EQUAL_TO, MODIFIED_DATE), + PARENT_PUBLICATION(KEYWORD, MUST, PARENT_PUBLICATION_ID), + PARENT_PUBLICATION_SHOULD(TEXT, SHOULD, PARENT_PUBLICATION_ID), + PROJECT(KEYWORD, PROJECTS_ID), + PROJECT_NOT(KEYWORD, MUST_NOT, PROJECTS_ID), + PROJECT_SHOULD(TEXT, SHOULD, PROJECTS_ID), + PUBLISHED_BEFORE(ParamKind.DATE, FieldOperator.LESS_THAN, PUBLISHED_DATE), + PUBLISHED_SINCE(ParamKind.DATE, FieldOperator.GREATER_THAN_OR_EQUAL_TO, PUBLISHED_DATE), + TITLE(TEXT, ENTITY_DESCRIPTION_MAIN_TITLE, 2F), + TITLE_NOT(TEXT, MUST_NOT, ENTITY_DESCRIPTION_MAIN_TITLE), + TITLE_SHOULD(TEXT, SHOULD, ENTITY_DESCRIPTION_MAIN_TITLE), + TOP_LEVEL_ORGANIZATION(KEYWORD, MUST, TOP_LEVEL_ORGANIZATIONS + DOT + Words.ID), + UNIT(KEYWORD, CONTRIBUTORS_AFFILIATION_ID_KEYWORD), + UNIT_NOT(KEYWORD, MUST_NOT, CONTRIBUTORS_AFFILIATION_ID_KEYWORD), + UNIT_SHOULD(TEXT, SHOULD, CONTRIBUTORS_AFFILIATION_ID_KEYWORD), + USER(KEYWORD, RESOURCE_OWNER_OWNER_KEYWORD), + USER_NOT(KEYWORD, MUST_NOT, RESOURCE_OWNER_OWNER_KEYWORD), + USER_SHOULD(TEXT, SHOULD, RESOURCE_OWNER_OWNER_KEYWORD), + USER_AFFILIATION(KEYWORD, RESOURCE_OWNER_OWNER_AFFILIATION_KEYWORD), + USER_AFFILIATION_NOT(KEYWORD, RESOURCE_OWNER_OWNER_AFFILIATION_KEYWORD), + USER_AFFILIATION_SHOULD(TEXT, RESOURCE_OWNER_OWNER_AFFILIATION_KEYWORD), + PUBLICATION_YEAR(NUMBER, MUST, ENTITY_DESCRIPTION_PUBLICATION_DATE_YEAR, + PATTERN_IS_PUBLICATION_YEAR_KEYS, null, null), + PUBLICATION_YEAR_SHOULD(NUMBER, SHOULD, ENTITY_DESCRIPTION_PUBLICATION_DATE_YEAR, + PATTERN_IS_PUBLICATION_YEAR_SHOULD_KEYS, null, null), + // Query parameters passed to SWS/Opensearch + SEARCH_ALL(TEXT, MUST, Q, PATTERN_IS_SEARCH_ALL_KEY, null, null), + FIELDS(ParamKind.CUSTOM), + // Pagination parameters + PAGE(NUMBER), + FROM(NUMBER, null, null, PATTERN_IS_FROM_KEY, null, null), + SIZE(NUMBER, null, null, PATTERN_IS_SIZE_KEY, null, null), + SORT(ParamKind.SORT_KEY, null, null, PATTERN_IS_SORT_KEY, null, null), + SORT_ORDER(ParamKind.CUSTOM, MUST, null, PATTERN_IS_SORT_ORDER_KEY, PATTERN_IS_ASC_DESC_VALUE, null), + SEARCH_AFTER(ParamKind.CUSTOM), + // ignored parameter + LANG(ParamKind.CUSTOM); + + public static final int IGNORE_PARAMETER_INDEX = 0; + + public static final Set VALID_SEARCH_PARAMETER_KEYS = + Arrays.stream(ResourceParameter.values()) + .filter(ResourceParameter::isSearchField) + .sorted(ParameterKey::compareAscending) + .collect(Collectors.toCollection(LinkedHashSet::new)); + + private final String key; + private final ValueEncoding encoding; + private final String keyPattern; + private final String validValuePattern; + private final String[] fieldsToSearch; + private final FieldOperator fieldOperator; + private final String errorMsg; + private final ParamKind paramkind; + private final Float boost; + + ResourceParameter(ParamKind kind) { + this(kind, MUST, null, null, null, null); + } + + ResourceParameter(ParamKind kind, String fieldsToSearch) { + this(kind, MUST, fieldsToSearch, null, null, null); + } + + ResourceParameter(ParamKind kind, String fieldsToSearch, Float boost) { + this(kind, MUST, fieldsToSearch, null, null, boost); + } + + ResourceParameter(ParamKind kind, FieldOperator operator, String fieldsToSearch) { + this(kind, operator, fieldsToSearch, null, null, null); + } + + ResourceParameter( + ParamKind kind, FieldOperator operator, String fieldsToSearch, String keyPattern, String valuePattern, + Float boost) { + + this.key = this.name().toLowerCase(Locale.getDefault()); + this.fieldOperator = operator; + this.boost = nonNull(boost) ? boost : 1F; + this.fieldsToSearch = nonNull(fieldsToSearch) + ? fieldsToSearch.split("\\|") + : new String[]{key}; + this.validValuePattern = ParameterKey.getValuePattern(kind, valuePattern); + this.errorMsg = ParameterKey.getErrorMessage(kind); + this.encoding = ParameterKey.getEncoding(kind); + this.keyPattern = nonNull(keyPattern) + ? keyPattern + : PATTERN_IS_IGNORE_CASE + key.replace(UNDERSCORE, PATTERN_IS_NONE_OR_ONE) + ASTERISK; + this.paramkind = kind; + } + + @Override + public String fieldName() { + return key; + } + + @Override + public Float fieldBoost() { + return boost; + } + + @Override + public ParamKind fieldType() { + return paramkind; + } + + @Override + public String fieldPattern() { + return keyPattern; + } + + @Override + public String valuePattern() { + return validValuePattern; + } + + @Override + public ValueEncoding valueEncoding() { + return encoding; + } + + @Override + public Collection searchFields() { + return Arrays.stream(fieldsToSearch).toList(); + } + + @Override + public FieldOperator searchOperator() { + return fieldOperator; + } + + @Override + public String errorMessage() { + return errorMsg; + } + + @Override + @JacocoGenerated + public String toString() { + return + new StringJoiner(COLON, "Key[", "]") + .add(String.valueOf(ordinal())) + .add(name().toLowerCase(Locale.ROOT)) + .toString(); + } + + public static ResourceParameter keyFromString(String paramName) { + var result = Arrays.stream(ResourceParameter.values()) + .filter(ResourceParameter::ignoreInvalidKey) + .filter(ParameterKey.equalTo(paramName)) + .collect(Collectors.toSet()); + return result.size() == 1 + ? result.stream().findFirst().get() + : INVALID; + } + + private static boolean ignoreInvalidKey(ResourceParameter f) { + return f.ordinal() > IGNORE_PARAMETER_INDEX; + } + + private static boolean isSearchField(ResourceParameter f) { + return f.ordinal() > IGNORE_PARAMETER_INDEX && f.ordinal() < SEARCH_ALL.ordinal(); + } + +} \ No newline at end of file diff --git a/search-commons/src/main/java/no/unit/nva/search2/enums/ResourceSort.java b/search-commons/src/main/java/no/unit/nva/search2/enums/ResourceSort.java new file mode 100644 index 000000000..dd678747a --- /dev/null +++ b/search-commons/src/main/java/no/unit/nva/search2/enums/ResourceSort.java @@ -0,0 +1,85 @@ +package no.unit.nva.search2.enums; + +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_IGNORE_CASE; +import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_NONE_OR_ONE; +import static no.unit.nva.search2.constant.Words.UNDERSCORE; +import static nva.commons.core.StringUtils.EMPTY_STRING; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Locale; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import no.unit.nva.search2.constant.Resource; +import no.unit.nva.search2.constant.Words; + +public enum ResourceSort { + INVALID(EMPTY_STRING), + CATEGORY(Resource.PUBLICATION_INSTANCE_TYPE), + INSTANCE_TYPE(Resource.PUBLICATION_INSTANCE_TYPE), + CREATED_DATE(Words.CREATED_DATE), + MODIFIED_DATE(Words.MODIFIED_DATE), + PUBLISHED_DATE(Words.PUBLISHED_DATE), + TITLE(Resource.ENTITY_DESCRIPTION_MAIN_TITLE_KEYWORD), + UNIT_ID(Resource.CONTRIBUTORS_AFFILIATION_ID_KEYWORD), + USER("(?i)(user)|(owner)", Resource.RESOURCE_OWNER_OWNER_KEYWORD); + + public static final Set VALID_SORT_PARAMETER_KEYS = + Arrays.stream(ResourceSort.values()) + .sorted(ResourceSort::compareAscending) + .skip(1) // skip INVALID + .collect(Collectors.toCollection(LinkedHashSet::new)); + + private final String keyValidationRegEx; + private final String fieldName; + + ResourceSort(String pattern, String fieldName) { + this.keyValidationRegEx = pattern; + this.fieldName = fieldName; + } + + ResourceSort(String fieldName) { + this.keyValidationRegEx = getIgnoreCaseAndUnderscoreKeyExpression(this.name()); + this.fieldName = fieldName; + } + + public String getKeyPattern() { + return keyValidationRegEx; + } + + public String getFieldName() { + return fieldName; + } + + public static ResourceSort fromSortKey(String keyName) { + var result = Arrays.stream(ResourceSort.values()) + .filter(ResourceSort.equalTo(keyName)) + .collect(Collectors.toSet()); + return result.size() == 1 + ? result.stream().findFirst().get() + : INVALID; + } + + public static Predicate equalTo(String name) { + return key -> name.matches(key.getKeyPattern()); + } + + public static Collection validSortKeys() { + return VALID_SORT_PARAMETER_KEYS.stream() + .map(ResourceSort::name) + .map(String::toLowerCase) + .toList(); + } + + private static int compareAscending(ResourceSort key1, ResourceSort key2) { + return key1.ordinal() - key2.ordinal(); + } + + private static String getIgnoreCaseAndUnderscoreKeyExpression(String keyName) { + var keyNameIgnoreUnderscoreExpression = + keyName.toLowerCase(Locale.getDefault()) + .replace(UNDERSCORE, PATTERN_IS_NONE_OR_ONE); + return "%s%s".formatted(PATTERN_IS_IGNORE_CASE, keyNameIgnoreUnderscoreExpression); + } +} diff --git a/search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchQuery.java b/search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchQuery.java deleted file mode 100644 index 21c086e87..000000000 --- a/search-commons/src/main/java/no/unit/nva/search2/model/OpenSearchQuery.java +++ /dev/null @@ -1,265 +0,0 @@ -package no.unit.nva.search2.model; - -import static java.util.Objects.isNull; -import static java.util.Objects.nonNull; -import static no.unit.nva.search2.constant.ApplicationConstants.AMPERSAND; -import static no.unit.nva.search2.constant.ApplicationConstants.COLON; -import static no.unit.nva.search2.constant.ApplicationConstants.COMMA; -import static no.unit.nva.search2.constant.ApplicationConstants.EQUAL; -import static no.unit.nva.search2.constant.ApplicationConstants.PLUS; -import static no.unit.nva.search2.constant.ApplicationConstants.RESOURCES; -import static no.unit.nva.search2.constant.ApplicationConstants.SEARCH; -import static no.unit.nva.search2.constant.ApplicationConstants.readSearchInfrastructureApiUri; -import static nva.commons.core.StringUtils.EMPTY_STRING; -import static nva.commons.core.StringUtils.SPACE; -import static nva.commons.core.attempt.Try.attempt; -import static nva.commons.core.paths.UriWrapper.fromUri; -import com.google.common.net.MediaType; -import java.net.URI; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Stream; -import no.unit.nva.search2.model.ParameterKey.ValueEncoding; -import nva.commons.core.JacocoGenerated; -import org.jetbrains.annotations.NotNull; -import org.joda.time.DateTime; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class OpenSearchQuery & ParameterKey> { - - protected static final Logger logger = LoggerFactory.getLogger(OpenSearchQuery.class); - protected final transient Map queryParameters; - protected final transient Map luceneParameters; - protected final transient Set otherRequiredKeys; - protected transient URI openSearchUri = URI.create(readSearchInfrastructureApiUri()); - private transient MediaType mediaType; - private transient URI gatewayUri = URI.create("https://unset/resource/search"); - - protected OpenSearchQuery() { - luceneParameters = new ConcurrentHashMap<>(); - queryParameters = new ConcurrentHashMap<>(); - otherRequiredKeys = new HashSet<>(); - mediaType = MediaType.JSON_UTF_8; - } - - /** - * Builds URI to query SWS based on post body. - * - * @return an URI to Sws search without parameters. - */ - public URI getOpenSearchUri() { - return - fromUri(openSearchUri) - .addChild(RESOURCES, SEARCH) - .getUri(); - } - - public Map getOpenSearchParameters() { - return luceneParameters; - } - - - /** - * Query Parameters with string Keys. - * - * @return Map of String and String - */ - public Map toNvaSearchApiRequestParameter() { - var results = new LinkedHashMap(); - Stream.of(luceneParameters.entrySet(), queryParameters.entrySet()) - .flatMap(Set::stream) - .sorted(Comparator.comparingInt(o -> o.getKey().ordinal())) - .forEach(entry -> results.put(toNvaSearchApiKey(entry), entry.getValue().replace(SPACE, PLUS))); - return results; - } - - - /** - * Get value from Query Parameter Map with key. - * - * @param key to look up. - * @return String content raw - */ - public AsType getValue(K key) { - return new AsType( - luceneParameters.containsKey(key) - ? luceneParameters.get(key) - : queryParameters.get(key), - key - ); - } - - public Optional getOptional(K key) { - return Optional.ofNullable(luceneParameters.containsKey(key) - ? luceneParameters.get(key) - : queryParameters.get(key)); - } - - public String removeKey(K key) { - return luceneParameters.containsKey(key) - ? luceneParameters.remove(key) - : queryParameters.remove(key); - } - - public boolean isPresent(K key) { - return luceneParameters.containsKey(key) || queryParameters.containsKey(key); - } - - - @JacocoGenerated - public boolean hasNoSearchValue() { - return luceneParameters.isEmpty(); - } - - /** - * Add a key value pair to searchable Parameters. - * - * @param key to add to. - * @param value to assign - */ - public void setSearchFieldValue(K key, String value) { - if (nonNull(value)) { - var decodedValue = key.valueEncoding() != ValueEncoding.NONE ? decodeUTF(value) : value; - luceneParameters.put(key, decodedValue); - } - } - - /** - * Add a key value pair to non-searchable Parameters. - * - * @param key to add to. - * @param value to assign - */ - public void setQueryValue(K key, String value) { - if (nonNull(value)) { - queryParameters.put(key, key.valueEncoding() != ValueEncoding.NONE ? decodeUTF(value) : value); - } - } - - public MediaType getMediaType() { - return mediaType; - } - - public void setMediaType(String mediaType) { - if (nonNull(mediaType) && mediaType.contains("text/csv")) { - this.mediaType = MediaType.CSV_UTF_8; - } else { - this.mediaType = MediaType.JSON_UTF_8; - } - } - - public URI getNvaSearchApiUri() { - return gatewayUri; - } - - public void setNvaSearchApiUri(URI gatewayUri) { - this.gatewayUri = gatewayUri; - } - - public void setOpenSearchUri(URI openSearchUri) { - this.openSearchUri = openSearchUri; - } - - - protected String toNvaSearchApiKey(Entry entry) { - return entry.getKey().fieldName().toLowerCase(Locale.getDefault()); - } - - protected static String mergeParameters(String oldValue, String newValue) { - if (nonNull(oldValue)) { - var delimiter = newValue.matches("asc|desc") ? COLON : COMMA; - return String.join(delimiter, oldValue, newValue); - } else { - return newValue; - } - } - - protected static String decodeUTF(String encoded) { - return URLDecoder.decode(encoded, StandardCharsets.UTF_8); - } - - public static Collection> queryToMapEntries(URI uri) { - return queryToMapEntries(uri.getQuery()); - } - - public static Collection> queryToMapEntries(String query) { - return - nonNull(query) - ? Arrays.stream(query.split(AMPERSAND)) - .map(s -> s.split(EQUAL)) - .map(OpenSearchQuery::stringsToEntry) - .toList() - : Collections.emptyList(); - } - - @NotNull - private static Entry stringsToEntry(String... strings) { - return new Entry<>() { - @Override - public String getKey() { - return strings[0]; - } - - @Override - public String getValue() { - return attempt(() -> strings[1]).orElse((f) -> EMPTY_STRING); - } - - @Override - @JacocoGenerated - public String setValue(String value) { - return null; - } - }; - } - - @SuppressWarnings({"PMD.ShortMethodName"}) - public static class AsType { - - private final String value; - private final ParameterKey key; - - public AsType(String value, ParameterKey key) { - this.value = value; - this.key = key; - } - - public T as() { - if (isNull(value)) { - return null; - } - return (T) switch (key.fieldType()) { - case DATE -> castDateTime(); - case NUMBER -> castNumber(); - default -> value; - }; - } - - @Override - public String toString() { - return value; - } - - private T castDateTime() { - return ((Class) DateTime.class).cast(DateTime.parse(value)); - } - - @NotNull - private T castNumber() { - return (T) attempt(() -> Integer.parseInt(value)).orElseThrow(); - } - } -} diff --git a/search-commons/src/main/java/no/unit/nva/search2/model/PagedSearchDto.java b/search-commons/src/main/java/no/unit/nva/search2/model/PagedSearchDto.java deleted file mode 100644 index 47bca75d2..000000000 --- a/search-commons/src/main/java/no/unit/nva/search2/model/PagedSearchDto.java +++ /dev/null @@ -1,123 +0,0 @@ -package no.unit.nva.search2.model; - -import static java.util.Objects.isNull; -import static no.unit.nva.search2.constant.ApplicationConstants.objectMapperWithEmpty; -import static no.unit.nva.search2.constant.Defaults.PAGINATED_SEARCH_RESULT_CONTEXT; -import static no.unit.nva.search2.model.ParameterKeyResource.FROM; -import static nva.commons.core.attempt.Try.attempt; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.JsonNode; -import java.net.URI; -import java.util.List; -import java.util.Map; -import nva.commons.core.paths.UriWrapper; -import org.jetbrains.annotations.Nullable; - -public record PagedSearchDto( - URI id, - int totalHits, - List hits, - URI nextResults, - URI nextSearchAfterResults, - URI previousResults, - JsonNode aggregations) { - - private PagedSearchDto(Builder builder) { - this(builder.id, - builder.totalHits, - builder.hits, - builder.nextResults, - builder.nextResultsBySortKey, - builder.previousResults, - builder.aggregations - ); - } - - @JsonProperty("@context") - public URI context() { - return PAGINATED_SEARCH_RESULT_CONTEXT; - } - - public String toJsonString() { - return attempt(() -> objectMapperWithEmpty.writeValueAsString(this)) - .orElseThrow(); - } - - @SuppressWarnings({"PMD.UnusedPrivateField", "PMD.SingularField"}) - public static final class Builder { - - private URI id; - private URI nextResults; - private URI previousResults; - private URI nextResultsBySortKey; - private int totalHits; - private List hits; - private JsonNode aggregations; - - private Builder() { - } - - public static Builder builder() { - return new Builder(); - } - - public Builder withIds(URI gatewayUri, Map requestParameter, Integer offset, Integer size) { - this.id = - createUriOffsetRef(requestParameter, offset, gatewayUri); - this.previousResults = - createUriOffsetRef(requestParameter, offset - size, gatewayUri); - - this.nextResults = - createNextResults(requestParameter, offset + size, totalHits, gatewayUri); - return this; - } - - public Builder withNextResultsBySortKey(URI nextResultsBySortKey) { - this.nextResultsBySortKey = nextResultsBySortKey; - return this; - } - - public Builder withTotalHits(int totalHits) { - this.totalHits = totalHits; - return this; - } - - public Builder withHits(List hits) { - this.hits = hits; - return this; - } - - public Builder withAggregations(JsonNode aggregations) { - this.aggregations = aggregations; - return this; - } - - @Nullable - private URI createNextResults(Map requestParameter, Integer offset, Integer totalSize, - URI gatewayUri) { - return offset < totalSize - ? createUriOffsetRef(requestParameter, offset, gatewayUri) - : null; - } - - private URI createUriOffsetRef(Map params, Integer offset, URI gatewayUri) { - if (offset < 0) { - return null; - } - - params.put(FROM.fieldName(), String.valueOf(offset)); - return UriWrapper.fromUri(gatewayUri) - .addQueryParameters(params) - .getUri(); - } - - @SuppressWarnings("PMD.NullAssignment") - public PagedSearchDto build() { - if (isNull(this.nextResults)) { - this.nextResultsBySortKey = null; // null values are not serialized - } - - return new PagedSearchDto(this); - } - } -} diff --git a/search-commons/src/main/java/no/unit/nva/search2/model/ParameterKeyImportCandidate.java b/search-commons/src/main/java/no/unit/nva/search2/model/ParameterKeyImportCandidate.java deleted file mode 100644 index 43fb999f2..000000000 --- a/search-commons/src/main/java/no/unit/nva/search2/model/ParameterKeyImportCandidate.java +++ /dev/null @@ -1,210 +0,0 @@ -package no.unit.nva.search2.model; - -import static java.util.Objects.nonNull; -import static no.unit.nva.search2.constant.ApplicationConstants.COLON; -import static no.unit.nva.search2.constant.ApplicationConstants.UNDERSCORE; -import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_IGNORE_CASE; -import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_NONE_OR_ONE; -import static no.unit.nva.search2.model.ParameterKey.FieldOperator.GREATER_THAN_OR_EQUAL_TO; -import static no.unit.nva.search2.model.ParameterKey.FieldOperator.LESS_THAN; -import static no.unit.nva.search2.model.ParameterKey.FieldOperator.MUST; -import static no.unit.nva.search2.model.ParameterKey.FieldOperator.MUST_NOT; -import static no.unit.nva.search2.model.ParameterKey.FieldOperator.SHOULD; -import static no.unit.nva.search2.model.ParameterKey.ParamKind.CUSTOM; -import static no.unit.nva.search2.model.ParameterKey.ParamKind.KEYWORD; -import static no.unit.nva.search2.model.ParameterKey.ParamKind.NUMBER; -import static no.unit.nva.search2.model.ParameterKey.ParamKind.SORT_KEY; -import static no.unit.nva.search2.model.ParameterKey.ParamKind.TEXT; -import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.Locale; -import java.util.Set; -import java.util.StringJoiner; -import java.util.stream.Collectors; -import nva.commons.core.JacocoGenerated; - -/** - * Enum for all the parameters that can be used to query the search index. This enum needs to implement these - * parameters - * cristin API - */ - -public enum ParameterKeyImportCandidate implements ParameterKey { - INVALID(TEXT), - // Parameters converted to Lucene query - ADDITIONAL_IDENTIFIERS(KEYWORD, MUST, Constants.ADDITIONAL_IDENTIFIERS_VALUE_KEYWORD), - ADDITIONAL_IDENTIFIERS_NOT(KEYWORD, MUST_NOT, Constants.ADDITIONAL_IDENTIFIERS_VALUE_KEYWORD), - ADDITIONAL_IDENTIFIERS_SHOULD(TEXT, SHOULD, Constants.ADDITIONAL_IDENTIFIERS_VALUE_KEYWORD), - CATEGORY(KEYWORD, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_INSTANCE_TYPE), - CATEGORY_NOT(KEYWORD, MUST_NOT, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_INSTANCE_TYPE), - CATEGORY_SHOULD(TEXT, SHOULD, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_INSTANCE_TYPE), - COLLABORATION_TYPE(KEYWORD, MUST, ""), - DOI(KEYWORD, Constants.DOI), - DOI_NOT(TEXT, MUST_NOT, Constants.DOI), - DOI_SHOULD(TEXT, SHOULD, Constants.DOI), - ID(KEYWORD, Constants.IDENTIFIER), - ID_NOT(KEYWORD, MUST_NOT, Constants.IDENTIFIER), - ID_SHOULD(TEXT, SHOULD, Constants.IDENTIFIER), - OWNER(KEYWORD, MUST, Constants.RESOURCE_OWNER), - OWNER_NOT(KEYWORD, MUST_NOT, Constants.RESOURCE_OWNER), - OWNER_SHOULD(TEXT, SHOULD, Constants.RESOURCE_OWNER), - PUBLISHED_BEFORE(NUMBER, LESS_THAN, Constants.PUBLISHED_DATE), - PUBLISHED_SINCE(NUMBER, GREATER_THAN_OR_EQUAL_TO, Constants.PUBLISHED_DATE), - PUBLISHER(KEYWORD, MUST, Constants.PUBLISHER), - PUBLISHER_NOT(KEYWORD, MUST_NOT, Constants.PUBLISHER), - PUBLISHER_SHOULD(TEXT, SHOULD, Constants.PUBLISHER), - TITLE(TEXT, Constants.MAIN_TITLE, 2F), - TITLE_NOT(TEXT, MUST_NOT, Constants.MAIN_TITLE), - TITLE_SHOULD(TEXT, SHOULD, Constants.MAIN_TITLE), - // Query parameters passed to SWS/Opensearch - SEARCH_ALL(TEXT, MUST, "q", "(?i)search.?all|query", null, null), - FIELDS(CUSTOM), - // Pagination parameters - PAGE(NUMBER), - FROM(NUMBER, null, null, "(?i)offset|from", null, null), - SIZE(NUMBER, null, null, "(?i)per.?page|results|limit|size", null, null), - SORT(SORT_KEY, null, null, "(?i)order.?by|sort", null, null), - SORT_ORDER(CUSTOM, MUST, null, "(?i)sort.?order|order", "(?i)asc|desc", null), - SEARCH_AFTER(CUSTOM); - - public static final int IGNORE_PARAMETER_INDEX = 0; - - public static final Set VALID_LUCENE_PARAMETER_KEYS = - Arrays.stream(ParameterKeyImportCandidate.values()) - .filter(ParameterKeyImportCandidate::isSearchField) - .sorted(ParameterKey::compareAscending) - .collect(Collectors.toCollection(LinkedHashSet::new)); - - private final String key; - private final ValueEncoding encoding; - private final String keyPattern; - private final String validValuePattern; - private final String[] fieldsToSearch; - private final FieldOperator fieldOperator; - private final String errorMsg; - private final ParamKind paramkind; - private final Float boost; - - ParameterKeyImportCandidate(ParamKind kind) { - this(kind, MUST, null, null, null, null); - } - - ParameterKeyImportCandidate(ParamKind kind, String fieldsToSearch) { - this(kind, MUST, fieldsToSearch, null, null, null); - } - - ParameterKeyImportCandidate(ParamKind kind, String fieldsToSearch, Float boost) { - this(kind, MUST, fieldsToSearch, null, null, boost); - } - - ParameterKeyImportCandidate(ParamKind kind, FieldOperator operator, String fieldsToSearch) { - this(kind, operator, fieldsToSearch, null, null, null); - } - - ParameterKeyImportCandidate( - ParamKind kind, FieldOperator operator, String fieldsToSearch, String keyPattern, String valuePattern, - Float boost) { - - this.key = this.name().toLowerCase(Locale.getDefault()); - this.fieldOperator = operator; - this.boost = nonNull(boost) ? boost : 1F; - this.fieldsToSearch = nonNull(fieldsToSearch) - ? fieldsToSearch.split("\\|") - : new String[]{key}; - this.validValuePattern = ParameterKey.getValuePattern(kind, valuePattern); - this.errorMsg = ParameterKey.getErrorMessage(kind); - this.encoding = ParameterKey.getEncoding(kind); - this.keyPattern = nonNull(keyPattern) - ? keyPattern - : PATTERN_IS_IGNORE_CASE + key.replace(UNDERSCORE, PATTERN_IS_NONE_OR_ONE) + "*"; - this.paramkind = kind; - } - - @Override - public String fieldName() { - return key; - } - - @Override - public Float fieldBoost() { - return boost; - } - - @Override - public ParamKind fieldType() { - return paramkind; - } - - @Override - public String fieldPattern() { - return keyPattern; - } - - @Override - public String valuePattern() { - return validValuePattern; - } - - @Override - public ValueEncoding valueEncoding() { - return encoding; - } - - @Override - public Collection searchFields() { - return Arrays.stream(fieldsToSearch).toList(); - } - - @Override - public FieldOperator searchOperator() { - return fieldOperator; - } - - @Override - public String errorMessage() { - return errorMsg; - } - - @Override - @JacocoGenerated - public String toString() { - return - new StringJoiner(COLON, "Key[", "]") - .add(String.valueOf(ordinal())) - .add(name().toLowerCase(Locale.ROOT)) - .toString(); - } - - public static ParameterKeyImportCandidate keyFromString(String paramName) { - var result = Arrays.stream(ParameterKeyImportCandidate.values()) - .filter(ParameterKeyImportCandidate::ignoreInvalidKey) - .filter(ParameterKey.equalTo(paramName)) - .collect(Collectors.toSet()); - return result.size() == 1 - ? result.stream().findFirst().get() - : INVALID; - } - - private static boolean ignoreInvalidKey(ParameterKeyImportCandidate f) { - return f.ordinal() > IGNORE_PARAMETER_INDEX; - } - - private static boolean isSearchField(ParameterKeyImportCandidate f) { - return f.ordinal() > IGNORE_PARAMETER_INDEX && f.ordinal() < SEARCH_ALL.ordinal(); - } - - private static class Constants { - - public static final String DOI = "doi"; - public static final String ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_INSTANCE_TYPE = - "entityDescription.reference.publicationInstance.type.keyword"; - public static final String IDENTIFIER = "identifier.keyword"; - public static final String MAIN_TITLE = "title.keyword"; - public static final String PUBLISHED_DATE = "publishedDate.year"; - public static final String PUBLISHER = "publisher.id.keyword"; - public static final String RESOURCE_OWNER = "owner.keyword"; - public static final String ADDITIONAL_IDENTIFIERS_VALUE_KEYWORD = "additionalIdentifiers.value.keyword"; - - } -} \ No newline at end of file diff --git a/search-commons/src/main/java/no/unit/nva/search2/model/ParameterKeyResource.java b/search-commons/src/main/java/no/unit/nva/search2/model/ParameterKeyResource.java deleted file mode 100644 index 195267385..000000000 --- a/search-commons/src/main/java/no/unit/nva/search2/model/ParameterKeyResource.java +++ /dev/null @@ -1,280 +0,0 @@ -package no.unit.nva.search2.model; - -import static java.util.Objects.nonNull; -import static no.unit.nva.search2.constant.ApplicationConstants.COLON; -import static no.unit.nva.search2.constant.ApplicationConstants.PIPE; -import static no.unit.nva.search2.constant.ApplicationConstants.UNDERSCORE; -import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_FUNDING; -import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_IGNORE_CASE; -import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_NONE_OR_ONE; -import static no.unit.nva.search2.constant.Patterns.PATTERN_IS_URI; -import static no.unit.nva.search2.model.ParameterKey.FieldOperator.GREATER_THAN_OR_EQUAL_TO; -import static no.unit.nva.search2.model.ParameterKey.FieldOperator.LESS_THAN; -import static no.unit.nva.search2.model.ParameterKey.FieldOperator.MUST; -import static no.unit.nva.search2.model.ParameterKey.FieldOperator.MUST_NOT; -import static no.unit.nva.search2.model.ParameterKey.FieldOperator.SHOULD; -import static no.unit.nva.search2.model.ParameterKey.ParamKind.CUSTOM; -import static no.unit.nva.search2.model.ParameterKey.ParamKind.DATE; -import static no.unit.nva.search2.model.ParameterKey.ParamKind.KEYWORD; -import static no.unit.nva.search2.model.ParameterKey.ParamKind.NUMBER; -import static no.unit.nva.search2.model.ParameterKey.ParamKind.SORT_KEY; -import static no.unit.nva.search2.model.ParameterKey.ParamKind.TEXT; -import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.Locale; -import java.util.Set; -import java.util.StringJoiner; -import java.util.stream.Collectors; -import nva.commons.core.JacocoGenerated; - -/** - * Enum for all the parameters that can be used to query the search index. - * This enum needs to implement these parameters - * cristin API - * - */ - -public enum ParameterKeyResource implements ParameterKey { - INVALID(TEXT), - // Parameters converted to Lucene query - CATEGORY(KEYWORD, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_INSTANCE_TYPE), - CATEGORY_NOT(KEYWORD, MUST_NOT, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_INSTANCE_TYPE), - CATEGORY_SHOULD(KEYWORD, SHOULD, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_INSTANCE_TYPE), - CONTRIBUTOR_ID(KEYWORD, MUST, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_ID,null, PATTERN_IS_URI, null), - CONTRIBUTOR(KEYWORD, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_ID - + PIPE + Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_NAME), - CONTRIBUTOR_NOT(KEYWORD, MUST_NOT, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_ID - + PIPE + Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_NAME), - CONTRIBUTOR_SHOULD(TEXT, SHOULD, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_ID - + PIPE + Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_NAME), - CREATED_BEFORE(DATE, LESS_THAN, Constants.CREATED_DATE), - CREATED_SINCE(DATE, GREATER_THAN_OR_EQUAL_TO, Constants.CREATED_DATE), - DOI(KEYWORD, Constants.ENTITY_DESCRIPTION_REFERENCE_DOI), - DOI_NOT(TEXT, MUST_NOT, Constants.ENTITY_DESCRIPTION_REFERENCE_DOI), - DOI_SHOULD(TEXT, SHOULD, Constants.ENTITY_DESCRIPTION_REFERENCE_DOI), - FUNDING(KEYWORD, MUST, Constants.FUNDINGS_IDENTIFIER_FUNDINGS_SOURCE_IDENTIFIER, - null, PATTERN_IS_FUNDING, null), - FUNDING_SOURCE(KEYWORD, Constants.FUNDINGS_SOURCE_IDENTIFIER_FUNDINGS_SOURCE_LABELS), - FUNDING_SOURCE_NOT(KEYWORD, MUST_NOT, Constants.FUNDINGS_SOURCE_IDENTIFIER_FUNDINGS_SOURCE_LABELS), - FUNDING_SOURCE_SHOULD(TEXT, SHOULD, Constants.FUNDINGS_SOURCE_IDENTIFIER_FUNDINGS_SOURCE_LABELS), - ID(KEYWORD, Constants.IDENTIFIER), - ID_NOT(KEYWORD, MUST_NOT, Constants.IDENTIFIER), - ID_SHOULD(TEXT, SHOULD, Constants.IDENTIFIER), - INSTITUTION(KEYWORD, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_ID + PIPE - + Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_NAME), - INSTITUTION_NOT(KEYWORD, MUST_NOT, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_ID + PIPE - + Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_NAME), - INSTITUTION_SHOULD(TEXT, SHOULD, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_ID + PIPE - + Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_NAME), - ISBN(KEYWORD, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ISBN_LIST), - ISBN_NOT(KEYWORD, MUST_NOT, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ISBN_LIST), - ISBN_SHOULD(TEXT, SHOULD, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ISBN_LIST), - ISSN(KEYWORD, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ONLINE_ISSN - + PIPE + Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_PRINT_ISSN), - ISSN_NOT(KEYWORD, MUST_NOT, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ONLINE_ISSN - + PIPE + Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_PRINT_ISSN), - ISSN_SHOULD(TEXT, SHOULD, Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ONLINE_ISSN - + PIPE + Constants.ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_PRINT_ISSN), - ORCID(KEYWORD, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_ORC_ID), - ORCID_NOT(KEYWORD, MUST_NOT, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_ORC_ID), - ORCID_SHOULD(TEXT, SHOULD, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_ORC_ID), - MODIFIED_BEFORE(DATE, LESS_THAN, Constants.MODIFIED_DATE), - MODIFIED_SINCE(DATE, GREATER_THAN_OR_EQUAL_TO, Constants.MODIFIED_DATE), - PROJECT(KEYWORD, Constants.PROJECTS_ID), - PROJECT_NOT(KEYWORD, MUST_NOT, Constants.PROJECTS_ID), - PROJECT_SHOULD(TEXT, SHOULD, Constants.PROJECTS_ID), - PUBLISHED_BEFORE(DATE, LESS_THAN, Constants.PUBLISHED_DATE), - PUBLISHED_SINCE(DATE, GREATER_THAN_OR_EQUAL_TO, Constants.PUBLISHED_DATE), - TITLE(TEXT, Constants.MAIN_TITLE, 2F), - TITLE_NOT(TEXT, MUST_NOT, Constants.MAIN_TITLE), - TITLE_SHOULD(TEXT, SHOULD, Constants.MAIN_TITLE), - UNIT(KEYWORD, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_ID), - UNIT_NOT(KEYWORD, MUST_NOT, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_ID), - UNIT_SHOULD(TEXT, SHOULD, Constants.ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_ID), - USER(KEYWORD, Constants.RESOURCE_OWNER), - USER_NOT(KEYWORD, MUST_NOT, Constants.RESOURCE_OWNER), - USER_SHOULD(TEXT, SHOULD, Constants.RESOURCE_OWNER), - PUBLICATION_YEAR(NUMBER, MUST, Constants.ENTITY_DESCRIPTION_PUBLICATION_DATE_YEAR, - "(?i)year.?reported|publication.?year", null, null), - PUBLICATION_YEAR_SHOULD(NUMBER, SHOULD, Constants.ENTITY_DESCRIPTION_PUBLICATION_DATE_YEAR, - "(?i)year.?reported.?should|publication.?year.?should", null, null), - // Query parameters passed to SWS/Opensearch - SEARCH_ALL(TEXT, MUST, "q", "(?i)search.?all|query", null, null), - FIELDS(CUSTOM), - // Pagination parameters - PAGE(NUMBER), - FROM(NUMBER, null, null, "(?i)offset|from", null, null), - SIZE(NUMBER, null, null, "(?i)per.?page|results|limit|size", null, null), - SORT(SORT_KEY, null, null, "(?i)order.?by|sort", null, null), - SORT_ORDER(CUSTOM, MUST, null, "(?i)sort.?order|order", "(?i)asc|desc", null), - SEARCH_AFTER(CUSTOM), - // ignored parameter - LANG(TEXT); - - public static final int IGNORE_PARAMETER_INDEX = 0; - - public static final Set VALID_LUCENE_PARAMETER_KEYS = - Arrays.stream(ParameterKeyResource.values()) - .filter(ParameterKeyResource::isSearchField) - .sorted(ParameterKey::compareAscending) - .collect(Collectors.toCollection(LinkedHashSet::new)); - - private final String key; - private final ValueEncoding encoding; - private final String keyPattern; - private final String validValuePattern; - private final String[] fieldsToSearch; - private final FieldOperator fieldOperator; - private final String errorMsg; - private final ParamKind paramkind; - private final Float boost; - - ParameterKeyResource(ParamKind kind) { - this(kind, MUST, null, null, null, null); - } - - ParameterKeyResource(ParamKind kind, String fieldsToSearch) { - this(kind, MUST, fieldsToSearch, null, null, null); - } - - ParameterKeyResource(ParamKind kind, String fieldsToSearch, Float boost) { - this(kind, MUST, fieldsToSearch, null, null, boost); - } - - ParameterKeyResource(ParamKind kind, FieldOperator operator, String fieldsToSearch) { - this(kind, operator, fieldsToSearch, null, null, null); - } - - ParameterKeyResource( - ParamKind kind, FieldOperator operator, String fieldsToSearch, String keyPattern, String valuePattern, - Float boost) { - - this.key = this.name().toLowerCase(Locale.getDefault()); - this.fieldOperator = operator; - this.boost = nonNull(boost) ? boost : 1F; - this.fieldsToSearch = nonNull(fieldsToSearch) - ? fieldsToSearch.split("\\|") - : new String[]{key}; - this.validValuePattern = ParameterKey.getValuePattern(kind, valuePattern); - this.errorMsg = ParameterKey.getErrorMessage(kind); - this.encoding = ParameterKey.getEncoding(kind); - this.keyPattern = nonNull(keyPattern) - ? keyPattern - : PATTERN_IS_IGNORE_CASE + key.replace(UNDERSCORE, PATTERN_IS_NONE_OR_ONE) + "*"; - this.paramkind = kind; - } - - @Override - public String fieldName() { - return key; - } - - @Override - public Float fieldBoost() { - return boost; - } - - @Override - public ParamKind fieldType() { - return paramkind; - } - - @Override - public String fieldPattern() { - return keyPattern; - } - - @Override - public String valuePattern() { - return validValuePattern; - } - - @Override - public ValueEncoding valueEncoding() { - return encoding; - } - - @Override - public Collection searchFields() { - return Arrays.stream(fieldsToSearch).toList(); - } - - @Override - public FieldOperator searchOperator() { - return fieldOperator; - } - - @Override - public String errorMessage() { - return errorMsg; - } - - @Override - @JacocoGenerated - public String toString() { - return - new StringJoiner(COLON, "Key[", "]") - .add(String.valueOf(ordinal())) - .add(name().toLowerCase(Locale.ROOT)) - .toString(); - } - - public static ParameterKeyResource keyFromString(String paramName) { - var result = Arrays.stream(ParameterKeyResource.values()) - .filter(ParameterKeyResource::ignoreInvalidKey) - .filter(ParameterKey.equalTo(paramName)) - .collect(Collectors.toSet()); - return result.size() == 1 - ? result.stream().findFirst().get() - : INVALID; - } - - private static boolean ignoreInvalidKey(ParameterKeyResource f) { - return f.ordinal() > IGNORE_PARAMETER_INDEX; - } - - private static boolean isSearchField(ParameterKeyResource f) { - return f.ordinal() > IGNORE_PARAMETER_INDEX && f.ordinal() < SEARCH_ALL.ordinal(); - } - - - private static class Constants { - - public static final String CREATED_DATE = "createdDate"; - public static final String ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_ID = - "entityDescription.contributors.affiliations.id.keyword"; - public static final String ENTITY_DESCRIPTION_CONTRIBUTORS_AFFILIATION_NAME = - "entityDescription.contributors.affiliations.labels.nb.keyword" - + "|entityDescription.contributors.affiliations.labels.n n.keyword" - + "|entityDescription.contributors.affiliations.labels.en.keyword"; - public static final String ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_ID = - "entityDescription.contributors.identity.id"; - public static final String ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_NAME = - "entityDescription.contributors.identity.name.keyword"; - public static final String ENTITY_DESCRIPTION_CONTRIBUTORS_IDENTITY_ORC_ID = - "entityDescription.contributors.identity.orcId"; - public static final String ENTITY_DESCRIPTION_PUBLICATION_DATE_YEAR = - "entityDescription.publicationDate.year"; - public static final String ENTITY_DESCRIPTION_REFERENCE_DOI = - "entityDescription.reference.doi"; - public static final String ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ISBN_LIST = - "entityDescription.reference.publicationContext.isbnList"; - public static final String ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_ONLINE_ISSN = - "entityDescription.reference.publicationContext.onlineIssn"; - public static final String ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_CONTEXT_PRINT_ISSN = - "entityDescription.reference.publicationContext.printIssn"; - public static final String ENTITY_DESCRIPTION_REFERENCE_PUBLICATION_INSTANCE_TYPE = - "entityDescription.reference.publicationInstance.type"; - public static final String FUNDINGS_IDENTIFIER_FUNDINGS_SOURCE_IDENTIFIER = - "fundings.identifier|fundings.source.identifier"; - public static final String FUNDINGS_SOURCE_IDENTIFIER_FUNDINGS_SOURCE_LABELS = - "fundings.source.labels.nb.keyword|fundings.source.labels.en.keyword"; - public static final String IDENTIFIER = "identifier"; - public static final String MAIN_TITLE = "entityDescription.mainTitle"; - public static final String MODIFIED_DATE = "modifiedDate"; - public static final String PROJECTS_ID = "projects.id"; - public static final String PUBLISHED_DATE = "publishedDate"; - public static final String RESOURCE_OWNER = "resourceOwner.owner"; - } -} \ No newline at end of file diff --git a/search-commons/src/main/java/no/unit/nva/search2/model/QueryBuilderSourceWrapper.java b/search-commons/src/main/java/no/unit/nva/search2/model/QueryBuilderSourceWrapper.java deleted file mode 100644 index b4961e277..000000000 --- a/search-commons/src/main/java/no/unit/nva/search2/model/QueryBuilderSourceWrapper.java +++ /dev/null @@ -1,8 +0,0 @@ -package no.unit.nva.search2.model; - -import java.net.URI; -import org.opensearch.search.builder.SearchSourceBuilder; - -public record QueryBuilderSourceWrapper(SearchSourceBuilder source, URI requestUri) { - -} diff --git a/search-commons/src/test/java/no/unit/nva/search/OpensearchTest.java b/search-commons/src/test/java/no/unit/nva/search/OpensearchTest.java index b6c8f7625..eebbc507d 100644 --- a/search-commons/src/test/java/no/unit/nva/search/OpensearchTest.java +++ b/search-commons/src/test/java/no/unit/nva/search/OpensearchTest.java @@ -65,15 +65,12 @@ public class OpensearchTest { public static final URI INCLUDED_ORGANIZATION_ID = randomUri(); - public static final URI EXCLUDED_ORGANIZATION_ID = randomUri(); public static final long ZERO_HITS_BECAUSE_VIEWING_SCOPE_IS_EMPTY = 0; public static final long TWO_HITS_BECAUSE_MATCH_ON_BOTH_INCLUDED_UNITS = 2; - public static final long ONE_HIT_BECAUSE_ONE_UNIT_WAS_EXCLUDED = 1; public static final String STATUS_TO_INCLUDE_IN_RESULT = "Pending"; public static final long NON_ZERO_HITS_BECAUSE_APPROVED_WAS_INCLUDED = 1; public static final long DELAY_AFTER_INDEXING = 1000L; public static final String TEST_RESOURCES_MAPPINGS = "test_resources_mappings.json"; - public static final String TEST_TICKETS_MAPPINGS = "test_tickets_mappings.json"; public static final String TEST_IMPORT_CANDIDATES_MAPPINGS = "test_import_candidates_mappings.json"; public static final String OPEN_SEARCH_IMAGE = "opensearchproject/opensearch:2.0.0"; private static final int SAMPLE_NUMBER_OF_RESULTS = 7; @@ -174,8 +171,8 @@ private IndexDocument crateSampleIndexDocument(String indexName, String jsonFile indexName, SortableIdentifier.next() ); - var jsonNode = objectMapperWithEmpty.readValue(inputStreamFromResources(jsonFile), - JsonNode.class); + var jsonNode = objectMapperWithEmpty + .readValue(inputStreamFromResources(jsonFile), JsonNode.class); return new IndexDocument(eventConsumptionAttributes, jsonNode); } @@ -251,7 +248,7 @@ void shouldReturnInstanceTypeAggregationWithDocCountTwo() var query = queryWithTermAndAggregation(SEARCH_ALL, IMPORT_CANDIDATES_AGGREGATIONS); var response = searchClient.searchWithSearchDocumentQuery(query, indexName); - var docCount = response.getAggregations().get("type").get("buckets").get(0).get("docCount").asInt(); + var docCount = response.getAggregations().get("instanceType").get("buckets").get(0).get("docCount").asInt(); assertThat(docCount, is(equalTo(1))); } @@ -261,8 +258,8 @@ void shouldFilterDocumentsWithFiles() addDocumentsToIndex("imported_candidate_from_index.json", "not_imported_candidate_from_index.json"); var query = queryWithTermAndAggregation( - "(associatedArtifacts.type:\"PublishedFile\")AND(associatedArtifacts.administrativeAgreement:\"false\")", - IMPORT_CANDIDATES_AGGREGATIONS); + "(associatedArtifacts.type:\"PublishedFile\")AND(associatedArtifacts" + + ".administrativeAgreement:\"false\")", IMPORT_CANDIDATES_AGGREGATIONS); var response = searchClient.searchWithSearchDocumentQuery(query, indexName); @@ -444,7 +441,7 @@ void shouldQueryingFundingSuccessfully() throws InterruptedException, ApiGateway "sample_publication_with_several_of_the_same_affiliation.json"); var query = queryWithTermAndAggregation( - "fundings.source.identifier.keyword:\"NFR\"", + "fundings.source.identifier:\"NFR\"", ApplicationConstants.RESOURCES_AGGREGATIONS); var response = searchClient.searchWithSearchDocumentQuery(query, indexName); diff --git a/search-commons/src/test/java/no/unit/nva/search2/FacetsTest.java b/search-commons/src/test/java/no/unit/nva/search2/FacetsTest.java new file mode 100644 index 000000000..ca93a1dba --- /dev/null +++ b/search-commons/src/test/java/no/unit/nva/search2/FacetsTest.java @@ -0,0 +1,33 @@ +package no.unit.nva.search2; + +import static no.unit.nva.search.constants.ApplicationConstants.objectMapperWithEmpty; +import static nva.commons.core.attempt.Try.attempt; +import static nva.commons.core.ioutils.IoUtils.inputStreamFromResources; +import static nva.commons.core.ioutils.IoUtils.streamToString; +import com.fasterxml.jackson.databind.JsonNode; +import no.unit.nva.search2.common.AggregationFormat; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FacetsTest { + protected static final Logger logger = LoggerFactory.getLogger(FacetsTest.class); + + @Test + void shoulCheckMapping() { + var jsonString = fileToString("sample_aggregations.json"); + var jsonNode = stringToJsonNode(jsonString); + + assert jsonNode != null; + logger.info(AggregationFormat.apply(jsonNode).toPrettyString()); + } + + + private String fileToString(String fileName) { + return streamToString(inputStreamFromResources(fileName)); + } + + private static JsonNode stringToJsonNode(String aggregation) { + return attempt(() -> objectMapperWithEmpty.readTree(aggregation)).orElseThrow(); + } +} diff --git a/search-commons/src/test/java/no/unit/nva/search2/ImportCandidateClientTest.java b/search-commons/src/test/java/no/unit/nva/search2/ImportCandidateClientTest.java index 73ed6ddb7..96c0ebb05 100644 --- a/search-commons/src/test/java/no/unit/nva/search2/ImportCandidateClientTest.java +++ b/search-commons/src/test/java/no/unit/nva/search2/ImportCandidateClientTest.java @@ -1,187 +1,211 @@ package no.unit.nva.search2; import static no.unit.nva.indexing.testutils.MockedJwtProvider.setupMockedCachedJwtProvider; -import static no.unit.nva.search2.model.OpenSearchQuery.queryToMapEntries; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.CATEGORY; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.FROM; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.SIZE; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.SORT; +import static no.unit.nva.search.constants.ApplicationConstants.IMPORT_CANDIDATES_INDEX; +import static no.unit.nva.search2.common.Query.queryToMapEntries; +import static no.unit.nva.search2.enums.ImportCandidateParameter.FROM; +import static no.unit.nva.search2.enums.ImportCandidateParameter.SIZE; +import static no.unit.nva.search2.enums.ImportCandidateParameter.SORT; +import static nva.commons.core.attempt.Try.attempt; import static nva.commons.core.ioutils.IoUtils.stringFromResources; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import com.fasterxml.jackson.core.type.TypeReference; import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; -import java.net.http.HttpHeaders; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; import java.nio.file.Path; -import java.util.Collections; import java.util.Map; -import java.util.Optional; import java.util.stream.Stream; -import javax.net.ssl.SSLSession; +import no.unit.nva.commons.json.JsonUtils; +import no.unit.nva.identifiers.SortableIdentifier; +import no.unit.nva.search.IndexingClient; +import no.unit.nva.search.RestHighLevelClientWrapper; +import no.unit.nva.search.models.EventConsumptionAttributes; +import no.unit.nva.search.models.IndexDocument; +import no.unit.nva.search2.enums.ImportCandidateParameter; import nva.commons.apigateway.exceptions.ApiGatewayException; import nva.commons.apigateway.exceptions.BadRequestException; -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.BeforeEach; +import org.apache.http.HttpHost; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import org.opensearch.client.RestClient; +import org.opensearch.testcontainers.OpensearchContainer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; class ImportCandidateClientTest { - private ImportCandidateClient resourceAwsClient; + protected static final Logger logger = LoggerFactory.getLogger(ImportCandidateClientTest.class); + public static final String SAMPLE_IMPORT_CANDIDATES = "sample_import_candidate_search.json"; + public static final String OPEN_SEARCH_IMAGE = "opensearchproject/opensearch:2.0.0"; + public static final long DELAY_AFTER_INDEXING = 1000L; + private static final OpensearchContainer container = new OpensearchContainer(OPEN_SEARCH_IMAGE); + private static IndexingClient indexingClient; + private static ImportCandidateClient importCandidateClient; - public static final String SAMPLE_OPENSEARCH_RESPONSE_RESPONSE_EXPORT - = "sample_opensearch_response.json"; + @BeforeAll + public static void setUp() throws IOException, InterruptedException { + container.start(); - @BeforeEach - public void setUp() throws IOException, InterruptedException { - var httpClient = mock(HttpClient.class); + var restClientBuilder = RestClient.builder(HttpHost.create(container.getHttpHostAddress())); + var restHighLevelClientWrapper = new RestHighLevelClientWrapper(restClientBuilder); var cachedJwtProvider = setupMockedCachedJwtProvider(); - resourceAwsClient = new ImportCandidateClient(cachedJwtProvider, httpClient); - when(httpClient.send(any(), any())) - .thenReturn(mockedHttpResponse(SAMPLE_OPENSEARCH_RESPONSE_RESPONSE_EXPORT)); - } - - @ParameterizedTest - @MethodSource("uriProvider") - void searchWithUriReturnsOpenSearchAwsResponse(URI uri) throws ApiGatewayException { - var pagedSearchResourceDto = - ImportCandidateQuery.builder() - .fromQueryParameters(queryToMapEntries(uri)) - .withRequiredParameters(FROM, SIZE, SORT) - .build() - .doSearch(resourceAwsClient); - - assertNotNull(pagedSearchResourceDto); - } + indexingClient = new IndexingClient(restHighLevelClientWrapper, cachedJwtProvider); + importCandidateClient = new ImportCandidateClient(cachedJwtProvider, HttpClient.newHttpClient()); - @ParameterizedTest - @MethodSource("uriProvider") - void searchWithUriReturnsCSVResponse(URI uri) throws ApiGatewayException { - - var csvResult = ImportCandidateQuery.builder() - .fromQueryParameters(queryToMapEntries(uri)) - .withRequiredParameters(FROM, SIZE, SORT) - .withMediaType("text/csv") - .build() - .doSearch(resourceAwsClient); - assertNotNull(csvResult); + createIndex(); + populateIndex(); + logger.info("Waiting {} ms for indexing to complete", DELAY_AFTER_INDEXING); + Thread.sleep(DELAY_AFTER_INDEXING); } - @ParameterizedTest - @MethodSource("uriSortingProvider") - void searchUriWithSortingReturnsOpenSearchAwsResponse(URI uri) throws ApiGatewayException { - var query = - ImportCandidateQuery.builder() - .fromQueryParameters(queryToMapEntries(uri)) - .withRequiredParameters(FROM, SIZE, SORT, CATEGORY) - .build(); - - var response = resourceAwsClient.doSearch(query); - var pagedSearchResourceDto = query.toPagedResponse(response); - assertNotNull(pagedSearchResourceDto.id()); - assertNotNull(pagedSearchResourceDto.context()); - assertTrue(pagedSearchResourceDto.id().getScheme().contains("https")); + @AfterAll + static void afterAll() throws IOException, InterruptedException { + logger.info("Stopping container"); + indexingClient.deleteIndex(IMPORT_CANDIDATES_INDEX); + Thread.sleep(DELAY_AFTER_INDEXING); + container.stop(); } - @ParameterizedTest - @MethodSource("uriInvalidProvider") - void failToSearchUri(URI uri) { - assertThrows(BadRequestException.class, - () -> ImportCandidateQuery.builder() - .fromQueryParameters(queryToMapEntries(uri)) - .withRequiredParameters(FROM, SIZE) - .build() - .doSearch(resourceAwsClient)); - } + @Nested + class ImportCandidateTest { - static Stream uriSortingProvider() { - return Stream.of( - URI.create("https://example.com/?category=PhdThesis&sort=title&sortOrder=asc&sort=category&order" - + "=desc"), - URI.create("https://example.com/?category=PhdThesis&sort=title&sortOrder=asc&sort=category"), - URI.create("https://example.com/?category=PhdThesis&sort=title&sortOrder=asc&sort=category"), - URI.create("https://example.com/?category=PhdThesis&size=10&from=0&sort=category"), - URI.create("https://example.com/?category=PhdThesis&orderBy=UNIT_ID:asc,title:desc"), - URI.create("https://example.com/?category=PhdThesis&orderBy=title:asc," - + "modifiedDate:desc&searchAfter=1241234,23412"), - URI.create("https://example.com/?category=PhdThesis&sort=unitId+asc&sort=category+desc")); - } + @ParameterizedTest + @MethodSource("uriProvider") + void searchWithUriReturnsOpenSearchAwsResponse(URI uri) throws ApiGatewayException { + var query = + ImportCandidateQuery.builder() + .fromQueryParameters(queryToMapEntries(uri)) + .withOpensearchUri(URI.create(container.getHttpHostAddress())) + .withRequiredParameters(FROM, SIZE, SORT) + .build(); - static Stream uriProvider() { - return Stream.of( - URI.create("https://example.com/?query=hello+world&fields=category,title"), - URI.create("https://example.com/?query=hello+world&fields=category,title,werstfg&ID_NOT=123"), - URI.create("https://example.com/?title=http://hello+world&published_before=2019"), - URI.create("https://example.com/?owner_should=" - + "https://api.dev.nva.aws.unit.no/cristin/person/1136254+" - + "https://api.dev.nva.aws.unit.no/cristin/person/1135555"), - URI.create("https://example.com/?owner_not=hello+world&PUBLISHED_SINCE=2019"), - URI.create("https://example.com/?owner_should=hello+world&size=1&from=0"), - URI.create("https://example.com/?PUBLISHED_BEFORE=1872&PUBLISHED_SINCE=9460"), - URI.create("https://example.com/"), - URI.create("https://example.com/?query=hello+world&fields=all")); - } + var swsResponse = importCandidateClient.doSearch(query); + var pagedResponse = query.toPagedResponse(swsResponse); - static Stream uriInvalidProvider() { - return Stream.of( - URI.create("https://example.com/?categories=hello+world"), - URI.create("https://example.com/?tittles=hello+world&modified_before=2019-01"), - URI.create("https://example.com/?conttributors=hello+world&published_before=2020-01-01"), - URI.create("https://example.com/?category=PhdThesis&sort=beunited+asc"), - URI.create("https://example.com/?funding=NFR,296896"), - URI.create("https://example.com/?useers=hello+world")); - } + logger.info("returned: " + pagedResponse.hits().size()); + logger.info("totalHits: " + pagedResponse.totalHits()); - @NotNull - public static HttpResponse mockedHttpResponse(String filename) { - return new HttpResponse<>() { - @Override - public int statusCode() { - return 200; - } + assertNotNull(pagedResponse); + assertThat(pagedResponse.hits().size(), is(equalTo(query.getValue(ImportCandidateParameter.SIZE).as()))); + assertThat(pagedResponse.totalHits(), is(equalTo(query.getValue(ImportCandidateParameter.SIZE).as()))); + } - @Override - public HttpRequest request() { - return null; - } + @ParameterizedTest + @MethodSource("uriProvider") + void searchWithUriReturnsCSVResponse(URI uri) throws ApiGatewayException { - @Override - public Optional> previousResponse() { - return Optional.empty(); - } - - @Override - public HttpHeaders headers() { - return HttpHeaders.of(Map.of("Content-Type", Collections.singletonList("application/json")), - (s, s2) -> true); - } - - @Override - public String body() { - return stringFromResources(Path.of(filename)); - } - - @Override - public Optional sslSession() { - return Optional.empty(); - } + var csvResult = ImportCandidateQuery.builder() + .fromQueryParameters(queryToMapEntries(uri)) + .withOpensearchUri(URI.create(container.getHttpHostAddress())) + .withRequiredParameters(FROM, SIZE, SORT) + .withMediaType("text/csv") + .build() + .doSearch(importCandidateClient); + assertNotNull(csvResult); + } + + @ParameterizedTest + @MethodSource("uriSortingProvider") + void searchUriWithSortingReturnsOpenSearchAwsResponse(URI uri) throws ApiGatewayException { + var query = + ImportCandidateQuery.builder() + .fromQueryParameters(queryToMapEntries(uri)) + .withOpensearchUri(URI.create(container.getHttpHostAddress())) + .withRequiredParameters(FROM, SIZE, SORT) + .build(); + + var response = importCandidateClient.doSearch(query); + var pagedResponse = query.toPagedResponse(response); + assertNotNull(pagedResponse.id()); + assertNotNull(pagedResponse.context()); + assertTrue(pagedResponse.id().getScheme().contains("https")); + } + + @ParameterizedTest + @MethodSource("uriInvalidProvider") + void failToSearchUri(URI uri) { + assertThrows(BadRequestException.class, + () -> ImportCandidateQuery.builder() + .fromQueryParameters(queryToMapEntries(uri)) + .withOpensearchUri(URI.create(container.getHttpHostAddress())) + .withRequiredParameters(FROM, SIZE) + .build() + .doSearch(importCandidateClient)); + } + + static Stream uriSortingProvider() { + return Stream.of( + URI.create( + "https://example.com/?category=AcademicArticle&sort=title&sortOrder=asc&sort=created_date&order" + + "=desc"), + URI.create("https://example.com/?category=AcademicArticle&sort=title&sortOrder=asc&sort=created_date"), + URI.create("https://example.com/?category=AcademicArticle&sort=title&sortOrder=asc&sort=created_date"), + URI.create("https://example.com/?category=AcademicArticle&size=10&from=0&sort=created_date"), + URI.create( + "https://example.com/?category=AcademicArticle&orderBy=INSTANCE_TYPE:asc,PUBLICATION_YEAR:desc"), + URI.create("https://example.com/?category=AcademicArticle&orderBy=title:asc," + + "CREATED_DATE:desc&searchAfter=1241234,23412"), + URI.create("https://example.com/?category=AcademicArticle&sort=TYPE+asc&sort=INSTANCE_TYPE+desc")); + } + + static Stream uriProvider() { + return Stream.of( + URI.create("https://example.com/?size=8"), + URI.create("https://example.com/?category=AcademicArticle&size=5"), + URI.create("https://example.com/?CONTRIBUTOR=Andrew+Morrison&size=1"), + URI.create("https://example.com/?CONTRIBUTOR_SHOULD=Andrew+Morrison,George+Rigos&size=2"), + URI.create("https://example.com/?CONTRIBUTOR_NOT=George+Rigos&size=7"), + URI.create("https://example.com/?PUBLICATION_YEAR_BEFORE=2023&size=5"), + URI.create("https://example.com/?publication_year=2022&size=1"), + URI.create("https://example.com/?PublicationYearBefore=2024&publication_year_since=2023&size=3"), + URI.create("https://example.com/?title=In+reply:+Why+big+data&size=1"), + URI.create("https://example.com/?title=chronic+diseases&size=1"), + URI.create("https://example.com/?title_should=antibacterial+Fishing&size=2"), + URI.create("https://example.com/?query=antibacterial&fields=category,title&size=1"), + URI.create("https://example.com/?query=antibacterial&fields=category,title,werstfg&ID_NOT=123&size=1"), + URI.create("https://example.com/?query=European&fields=all&size=3")); + } + + static Stream uriInvalidProvider() { + return Stream.of( + URI.create("https://example.com/?categories=hello+world"), + URI.create("https://example.com/?tittles=hello+world&modified_before=2019-01"), + URI.create("https://example.com/?conttributors=hello+world&PUBLICATION_YEAR_BEFORE=2020-01-01"), + URI.create("https://example.com/?category=PhdThesis&sort=beunited+asc"), + URI.create("https://example.com/?funding=NFR,296896"), + URI.create("https://example.com/?useers=hello+world")); + } + } - @Override - public URI uri() { - return null; + protected static void populateIndex() { + var jsonFile = stringFromResources(Path.of(SAMPLE_IMPORT_CANDIDATES)); + var jsonNodes = + attempt(() -> JsonUtils.dtoObjectMapper.readTree(jsonFile)).orElseThrow(); + + jsonNodes.forEach(node -> { + try { + var attributes = new EventConsumptionAttributes(IMPORT_CANDIDATES_INDEX, SortableIdentifier.next()); + indexingClient.addDocumentToIndex(new IndexDocument(attributes, node)); + } catch (IOException e) { + throw new RuntimeException(e); } + }); + } - @Override - public HttpClient.Version version() { - return null; - } + protected static void createIndex() throws IOException { + var mappingsJson = stringFromResources(Path.of("test_import_candidates_mappings.json")); + var type = new TypeReference>() { }; + var mappings = attempt(() -> JsonUtils.dtoObjectMapper.readValue(mappingsJson, type)).orElseThrow(); + indexingClient.createIndex(IMPORT_CANDIDATES_INDEX, mappings); } } \ No newline at end of file diff --git a/search-commons/src/test/java/no/unit/nva/search2/ResourceClientNoHitsTest.java b/search-commons/src/test/java/no/unit/nva/search2/ResourceClientNoHitsTest.java index 1cbb0d18a..0611c7ea0 100644 --- a/search-commons/src/test/java/no/unit/nva/search2/ResourceClientNoHitsTest.java +++ b/search-commons/src/test/java/no/unit/nva/search2/ResourceClientNoHitsTest.java @@ -1,11 +1,11 @@ package no.unit.nva.search2; import static no.unit.nva.indexing.testutils.MockedJwtProvider.setupMockedCachedJwtProvider; -import static no.unit.nva.search2.ResourceClientTest.mockedHttpResponse; -import static no.unit.nva.search2.model.ParameterKeyResource.CATEGORY; -import static no.unit.nva.search2.model.ParameterKeyResource.FROM; -import static no.unit.nva.search2.model.ParameterKeyResource.SIZE; -import static no.unit.nva.search2.model.ParameterKeyResource.SORT; +import static no.unit.nva.search2.common.MockedHttpResponse.mockedHttpResponse; +import static no.unit.nva.search2.enums.ResourceParameter.FROM; +import static no.unit.nva.search2.enums.ResourceParameter.INSTANCE_TYPE; +import static no.unit.nva.search2.enums.ResourceParameter.SIZE; +import static no.unit.nva.search2.enums.ResourceParameter.SORT; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -16,7 +16,7 @@ import java.net.URI; import java.net.http.HttpClient; import java.util.stream.Stream; -import no.unit.nva.search2.model.OpenSearchQuery; +import no.unit.nva.search2.common.Query; import nva.commons.apigateway.exceptions.ApiGatewayException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -39,14 +39,13 @@ public void setUp() throws IOException, InterruptedException { .thenReturn(response); } - @ParameterizedTest @MethodSource("uriProvider") void searchSingleTermReturnsOpenSearchSwsResponse(URI uri) throws ApiGatewayException { var pagedSearchResourceDto = ResourceQuery.builder() - .fromQueryParameters(OpenSearchQuery.queryToMapEntries(uri)) + .fromQueryParameters(Query.queryToMapEntries(uri)) .withRequiredParameters(FROM, SIZE, SORT) .build() .doSearch(resourceClient); @@ -54,18 +53,17 @@ void searchSingleTermReturnsOpenSearchSwsResponse(URI uri) throws ApiGatewayExce assertNotNull(pagedSearchResourceDto); } - @ParameterizedTest @MethodSource("uriSortingProvider") void uriParamsToResourceParams(URI uri) throws ApiGatewayException { var query = ResourceQuery.builder() - .fromQueryParameters(OpenSearchQuery.queryToMapEntries(uri)) + .fromQueryParameters(Query.queryToMapEntries(uri)) .withRequiredParameters(FROM, SIZE, SORT) .build(); - assertNotNull(query.getValue(CATEGORY).as()); - assertNotNull(query.removeKey(CATEGORY)); - assertNull(query.removeKey(CATEGORY)); + assertNotNull(query.getValue(INSTANCE_TYPE).as()); + assertNotNull(query.removeKey(INSTANCE_TYPE)); + assertNull(query.removeKey(INSTANCE_TYPE)); var response = resourceClient.doSearch(query); var pagedSearchResourceDto = query.toPagedResponse(response); @@ -75,19 +73,18 @@ void uriParamsToResourceParams(URI uri) throws ApiGatewayException { assertEquals(0, pagedSearchResourceDto.hits().size()); } - static Stream uriSortingProvider() { return Stream.of( - URI.create("https://example.com/?category=PhdThesis&sort=category&sortOrder=asc&sort=created_date&order" + URI.create("https://example.com/?INSTANCE_TYPE=PhdThesis&sort=INSTANCE_TYPE&sortOrder=asc&sort=created_date&order" + "=desc"), - URI.create("https://example.com/?category=PhdThesis"), - URI.create("https://example.com/?category=PhdThesis&orderBy=category:asc,created_date:desc"), - URI.create("https://example.com/?category=PhdThesis&sort=category+asc&sort=created_date+desc")); + URI.create("https://example.com/?INSTANCE_TYPE=PhdThesis"), + URI.create("https://example.com/?INSTANCE_TYPE=PhdThesis&orderBy=INSTANCE_TYPE:asc,created_date:desc"), + URI.create("https://example.com/?INSTANCE_TYPE=PhdThesis&sort=INSTANCE_TYPE+asc&sort=created_date+desc")); } static Stream uriProvider() { return Stream.of( - URI.create("https://example.com/testsearch?category=hello+world&lang=en"), + URI.create("https://example.com/testsearch?INSTANCE_TYPE=hello+world&lang=en"), URI.create("https://example.com/testsearch?title=hello+world&modified_before=2019-01-01"), URI.create("https://example.com/testsearch?contributor=hello+world&published_before=2020-01-01"), URI.create("https://example.com/testsearch?user=hello+world&lang=en")); diff --git a/search-commons/src/test/java/no/unit/nva/search2/ResourceClientTest.java b/search-commons/src/test/java/no/unit/nva/search2/ResourceClientTest.java index 01299d8cf..71e7ace1c 100644 --- a/search-commons/src/test/java/no/unit/nva/search2/ResourceClientTest.java +++ b/search-commons/src/test/java/no/unit/nva/search2/ResourceClientTest.java @@ -1,206 +1,347 @@ package no.unit.nva.search2; import static no.unit.nva.indexing.testutils.MockedJwtProvider.setupMockedCachedJwtProvider; -import static no.unit.nva.search2.model.OpenSearchQuery.queryToMapEntries; -import static no.unit.nva.search2.model.ParameterKeyResource.CATEGORY; -import static no.unit.nva.search2.model.ParameterKeyResource.FROM; -import static no.unit.nva.search2.model.ParameterKeyResource.SIZE; -import static no.unit.nva.search2.model.ParameterKeyResource.SORT; +import static no.unit.nva.search2.common.Query.queryToMapEntries; +import static no.unit.nva.search2.enums.ResourceParameter.FROM; +import static no.unit.nva.search2.enums.ResourceParameter.INSTANCE_TYPE; +import static no.unit.nva.search2.enums.ResourceParameter.SIZE; +import static no.unit.nva.search2.enums.ResourceParameter.SORT; +import static nva.commons.core.attempt.Try.attempt; import static nva.commons.core.ioutils.IoUtils.stringFromResources; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import com.fasterxml.jackson.core.type.TypeReference; import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; -import java.net.http.HttpHeaders; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; import java.nio.file.Path; -import java.util.Collections; import java.util.Map; -import java.util.Optional; import java.util.stream.Stream; -import javax.net.ssl.SSLSession; +import no.unit.nva.commons.json.JsonUtils; +import no.unit.nva.identifiers.SortableIdentifier; +import no.unit.nva.search.IndexingClient; +import no.unit.nva.search.RestHighLevelClientWrapper; +import no.unit.nva.search.models.EventConsumptionAttributes; +import no.unit.nva.search.models.IndexDocument; import nva.commons.apigateway.exceptions.ApiGatewayException; import nva.commons.apigateway.exceptions.BadRequestException; -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.BeforeEach; +import org.apache.http.HttpHost; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import org.opensearch.client.RestClient; +import org.opensearch.testcontainers.OpensearchContainer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.junit.jupiter.Testcontainers; +@Testcontainers class ResourceClientTest { - private ResourceClient resourceClient; + protected static final Logger logger = LoggerFactory.getLogger(ResourceClientTest.class); + public static final String TEST_RESOURCES_MAPPINGS = "test_resources_mappings.json"; + public static final String OPEN_SEARCH_IMAGE = "opensearchproject/opensearch:2.0.0"; + public static final long DELAY_AFTER_INDEXING = 1000L; + private static final OpensearchContainer container = new OpensearchContainer(OPEN_SEARCH_IMAGE); + private static ResourceClient searchClient; + private static IndexingClient indexingClient; + private static String indexName; - public static final String SAMPLE_OPENSEARCH_RESPONSE_RESPONSE_EXPORT - = "sample_opensearch_response.json"; + @BeforeAll + static void setUp() throws IOException, InterruptedException { + container.start(); - @BeforeEach - public void setUp() throws IOException, InterruptedException { - var httpClient = mock(HttpClient.class); + var restClientBuilder = RestClient.builder(HttpHost.create(container.getHttpHostAddress())); + var restHighLevelClientWrapper = new RestHighLevelClientWrapper(restClientBuilder); var cachedJwtProvider = setupMockedCachedJwtProvider(); - resourceClient = new ResourceClient(cachedJwtProvider, httpClient); - when(httpClient.send(any(), any())) - .thenReturn(mockedHttpResponse(SAMPLE_OPENSEARCH_RESPONSE_RESPONSE_EXPORT)); - } - - @ParameterizedTest - @MethodSource("uriProvider") - void searchWithUriReturnsOpenSearchAwsResponse(URI uri) throws ApiGatewayException { - var pagedSearchResourceDto = - ResourceQuery.builder() - .fromQueryParameters(queryToMapEntries(uri)) - .withRequiredParameters(FROM, SIZE, SORT) - .build() - .doSearch(resourceClient); + indexingClient = new IndexingClient(restHighLevelClientWrapper, cachedJwtProvider); + searchClient = new ResourceClient(cachedJwtProvider, HttpClient.newHttpClient()); + indexName = generateIndexName(); - assertNotNull(pagedSearchResourceDto); + createIndex(); + populateIndex(); + logger.info("Waiting {} ms for indexing to complete", DELAY_AFTER_INDEXING); + Thread.sleep(DELAY_AFTER_INDEXING); } - @ParameterizedTest - @MethodSource("uriProvider") - void searchWithUriReturnsCSVResponse(URI uri) throws ApiGatewayException { - - var csvResult = ResourceQuery.builder() - .fromQueryParameters(queryToMapEntries(uri)) - .withRequiredParameters(FROM, SIZE, SORT) - .withMediaType("text/csv") - .build() - .doSearch(resourceClient); - assertNotNull(csvResult); + @AfterAll + static void afterAll() throws IOException, InterruptedException { + logger.info("Stopping container"); + indexingClient.deleteIndex(indexName); + Thread.sleep(DELAY_AFTER_INDEXING); + container.stop(); } + @Nested + class ResourceQueries { + + @Test + void shoulCheckMapping() { + + var mapping = indexingClient.getMapping(indexName); + assertThat(mapping, is(notNullValue())); + var topLevelOrgType = mapping.path("properties") + .path("topLevelOrganizations") + .path("type").textValue(); + assertThat(topLevelOrgType, is(equalTo("nested"))); + + logger.info(mapping.toString()); + } - @ParameterizedTest - @MethodSource("uriSortingProvider") - void searchUriWithSortingReturnsOpenSearchAwsResponse(URI uri) throws ApiGatewayException { - var query = - ResourceQuery.builder() + @Test + void shoulCheckFacets() throws BadRequestException { + var uri = URI.create("https://x.org/?size=20"); + var query = ResourceQuery.builder() .fromQueryParameters(queryToMapEntries(uri)) - .withRequiredParameters(FROM, SIZE, SORT, CATEGORY) + .withRequiredParameters(FROM, SIZE, SORT) + .withOpensearchUri(URI.create(container.getHttpHostAddress())) .build(); + var response = searchClient.doSearch(query); + var aggregations = query.toPagedResponse(response).aggregations(); - var response = resourceClient.doSearch(query); - var pagedSearchResourceDto = query.toPagedResponse(response); - assertNotNull(pagedSearchResourceDto.id()); - assertNotNull(pagedSearchResourceDto.context()); - assertTrue(pagedSearchResourceDto.id().getScheme().contains("https")); - } + assertFalse(aggregations.isEmpty()); + assertThat(aggregations.get("userAffiliation").size(), is(3)); + assertThat(aggregations.get("contextType").size(), is(3)); + assertThat(aggregations.get("instanceType").size(), is(3)); + assertThat(aggregations.get("associatedArtifacts").size(), is(1)); + assertThat(aggregations.get("associatedArtifacts").get(0).count(), is(20)); + assertThat(aggregations.get("fundingSource").size(), is(2)); + assertThat(aggregations.get("user").size(), is(3)); + assertThat(aggregations.get("topLevelOrganization").size(), is(4)); + assertThat(aggregations.get("topLevelOrganization").get(1).labels().get("nb"), + is(equalTo("Sikt – Kunnskapssektorens tjenesteleverandør"))); + } - @ParameterizedTest - @MethodSource("uriInvalidProvider") - void failToSearchUri(URI uri) { - assertThrows(BadRequestException.class, - () -> ResourceQuery.builder() - .fromQueryParameters(queryToMapEntries(uri)) - .withRequiredParameters(FROM, SIZE) - .build() - .doSearch(resourceClient)); - } - static Stream uriSortingProvider() { - return Stream.of( - URI.create("https://example.com/?category=PhdThesis&sort=title&sortOrder=asc&sort=category&order" - + "=desc"), - URI.create("https://example.com/?category=PhdThesis&sort=title&sortOrder=asc&sort=category"), - URI.create("https://example.com/?category=PhdThesis&sort=title&sortOrder=asc&sort=category"), - URI.create("https://example.com/?category=PhdThesis&size=10&from=0&sort=category"), - URI.create("https://example.com/?category=PhdThesis&orderBy=UNIT_ID:asc,title:desc"), - URI.create("https://example.com/?category=PhdThesis&orderBy=title:asc," - + "modifiedDate:desc&searchAfter=1241234,23412"), - URI.create("https://example.com/?category=PhdThesis&sort=unitId+asc&sort=category+desc")); - } + @ParameterizedTest + @MethodSource("uriProvider") + void searchWithUriReturnsOpenSearchAwsResponse(URI uri) throws ApiGatewayException { - static Stream uriProvider() { - return Stream.of( - URI.create("https://example.com/?title=http://hello+world&INSTITUTION=UiO"), - URI.create("https://example.com/?title_not=http://hello+world&INSTITUTION=UiO"), - URI.create("https://example.com/?title_should=http://hello+world&INSTITUTION=UiO"), - URI.create("https://example.com/?query=hello+world&lang=en&fields=category,title"), - URI.create("https://example.com/?query=Muhammad+Yahya&fields=CONTRIBUTOR"), - URI.create("https://example.com/?query=hello+world&lang=en&fields=category,title,werstfg&ID_NOT=123"), - URI.create("https://example.com/?title=http://hello+world&modified_before=2019"), - URI.create("https://example.com/?CONTRIBUTOR_SHOULD=" - + "https://api.dev.nva.aws.unit.no/cristin/person/1136254+" - + "https://api.dev.nva.aws.unit.no/cristin/person/1135555"), - URI.create("https://example.com/?CONTRIBUTOR=https://api.dev.nva.aws.unit.no/cristin/person/1136254"), - URI.create("https://example.com/?CONTRIBUTOR_ID=https://api.dev.nva.aws.unit.no/cristin/person/1136254"), - URI.create("https://example.com/?CONTRIBUTOR_SHOULD=" - + "https://api.dev.nva.aws.unit.no/cristin/person/1136254+" - + "https://api.dev.nva.aws.unit.no/cristin/person/1135555"), - URI.create("https://example.com/?CONTRIBUTOR_NOT=" - + "https://api.dev.nva.aws.unit.no/cristin/person/1136254+" - + "https://api.dev.nva.aws.unit.no/cristin/person/1135555"), - URI.create("https://example.com/?contributor_should=hello+:+world&published_before=2020"), - URI.create("https://example.com/?user=hello+world&lang=en&PUBLISHED_SINCE=2019"), - URI.create("https://example.com/?user=hello+world&size=1&from=0"), - URI.create("https://example.com/?isbn=1872-9460"), - URI.create("https://example.com/?issn=1872-9460"), - URI.create("https://example.com/?funding=NFR:296896"), - URI.create("https://example.com/?funding_source=NFR+296896"), - URI.create("https://example.com/?MODIFIED_BEFORE=1872-01-01&MODIFIED_SINCE=9460-01-01"), - URI.create("https://example.com/?ORCID=1872-9460"), - URI.create("https://example.com/"), - URI.create("https://example.com/?query=hello+world&fields=all")); - } + var query = + ResourceQuery.builder() + .fromQueryParameters(queryToMapEntries(uri)) + .withRequiredParameters(FROM, SIZE) + .withOpensearchUri(URI.create(container.getHttpHostAddress())) + .build(); - static Stream uriInvalidProvider() { - return Stream.of( - URI.create("https://example.com/?categories=hello+world&lang=en"), - URI.create("https://example.com/?tittles=hello+world&modified_before=2019-01-01"), - URI.create("https://example.com/?conttributors=hello+world&published_before=2020-01-01"), - URI.create("https://example.com/?category=PhdThesis&sort=beunited+asc"), - URI.create("https://example.com/?funding=NFR,296896"), - URI.create("https://example.com/?useers=hello+world&lang=en")); - } + var response = searchClient.doSearch(query); + var pagedSearchResourceDto = query.toPagedResponse(response); - @NotNull - public static HttpResponse mockedHttpResponse(String filename) { - return new HttpResponse<>() { - @Override - public int statusCode() { - return 200; - } + assertNotNull(pagedSearchResourceDto); + assertThat(pagedSearchResourceDto.hits().size(), is(equalTo(query.getValue(SIZE).as()))); + assertThat(pagedSearchResourceDto.totalHits(), is(equalTo(query.getValue(SIZE).as()))); + } - @Override - public HttpRequest request() { - return null; - } - @Override - public Optional> previousResponse() { - return Optional.empty(); - } + @ParameterizedTest + @MethodSource("uriProvider") + void searchWithUriReturnsCSVResponse(URI uri) throws ApiGatewayException { + var csvResult = + ResourceQuery.builder() + .fromQueryParameters(queryToMapEntries(uri)) + .withRequiredParameters(FROM, SIZE, SORT) + .withOpensearchUri(URI.create(container.getHttpHostAddress())) + .withMediaType("text/csv") + .build() + .doSearch(searchClient); + assertNotNull(csvResult); + } - @Override - public HttpHeaders headers() { - return HttpHeaders.of(Map.of("Content-Type", Collections.singletonList("application/json")), - (s, s2) -> true); - } + @ParameterizedTest + @MethodSource("uriSortingProvider") + void searchUriWithSortingReturnsOpenSearchAwsResponse(URI uri) throws ApiGatewayException { + var query = + ResourceQuery.builder() + .fromQueryParameters(queryToMapEntries(uri)) + .withRequiredParameters(FROM, SIZE, SORT, INSTANCE_TYPE) + .withOpensearchUri(URI.create(container.getHttpHostAddress())) + .build(); - @Override - public String body() { - return stringFromResources(Path.of(filename)); - } + logger.info(query.getValue(SORT).toString()); + var response = searchClient.doSearch(query); + var pagedSearchResourceDto = query.toPagedResponse(response); + logger.info(pagedSearchResourceDto.id().toString()); + assertNotNull(pagedSearchResourceDto.id()); + assertNotNull(pagedSearchResourceDto.context()); + assertTrue(pagedSearchResourceDto.totalHits() >= 0); + } - @Override - public Optional sslSession() { - return Optional.empty(); - } + @ParameterizedTest + @MethodSource("uriInvalidProvider") + void failToSearchUri(URI uri) { + assertThrows( + BadRequestException.class, + () -> ResourceQuery.builder() + .fromQueryParameters(queryToMapEntries(uri)) + .withRequiredParameters(FROM, SIZE) + .withOpensearchUri(URI.create(container.getHttpHostAddress())) + .build() + .doSearch(searchClient)); + } - @Override - public URI uri() { - return null; - } + static Stream uriSortingProvider() { + return Stream.of( + URI.create("https://x.org/?category=AcademicChapter&sort=created_date&sortOrder=asc" + + "&sort=category&order=desc"), + URI.create("https://x.org/?category=AcademicChapter&sort=modified_date&sortOrder=asc&sort=category"), + URI.create("https://x.org/?category=AcademicChapter&sort=published_date&sortOrder=asc&sort=category"), + URI.create("https://x.org/?category=AcademicChapter&size=10&from=0&sort=modified_date"), + URI.create("https://x.org/?category=AcademicChapter&orderBy=UNIT_ID:asc,title:desc"), + URI.create("https://x.org/?category=AcademicChapter&orderBy=created_date:asc," + + "modifiedDate:desc&searchAfter=1241234,23412"), + URI.create("https://x.org/?category=AcademicChapter&sort=published_date+asc&sort=category+desc")); + } + + static Stream uriInvalidProvider() { + return Stream.of( + URI.create("https://x.org/?categories=hello+world&lang=en"), + URI.create("https://x.org/?tittles=hello+world&modified_before=2019-01-01"), + URI.create("https://x.org/?conttributors=hello+world&published_before=2020-01-01"), + URI.create("https://x.org/?category=PhdThesis&sort=beunited+asc"), + URI.create("https://x.org/?funding=NFR,296896"), + URI.create("https://x.org/?useers=hello+world&lang=en")); + } - @Override - public HttpClient.Version version() { - return null; + static Stream uriProvider() { + return Stream.of( + URI.create("https://x.org/?size=20"), + URI.create("https://x.org/?category=ReportResearch&page=0&size=10"), + URI.create("https://x.org/?category=ReportResearch,AcademicArticle&page=0&size=19"), + URI.create("https://x.org/?CONTEXT_TYPE=Anthology&size=1"), + URI.create("https://x.org/?CONTEXT_TYPE=Report&size=10"), + URI.create("https://x.org/?CONTEXT_TYPE_NOT=Report&size=10"), + URI.create("https://x.org/?CONTEXT_TYPE_SHOULD=Report&size=10"), + URI.create("https://x.org/?CONTRIBUTOR=Kate+Robinson,Henrik+Langeland&size=3"), + URI.create("https://x.org/?CONTRIBUTOR=Peter+Gauer,Kjetil+Møkkelgjerd&size=8"), + URI.create("https://x.org/?CONTRIBUTOR=https://api.dev.nva.aws.unit.no/cristin/person/1136254&size=2"), + URI.create("https://x.org/?CONTRIBUTOR_NOT" + + "=https://api.dev.nva.aws.unit.no/cristin/person/1136254,Peter+Gauer&size=12"), + URI.create("https://x.org/?DOI=https://doi.org/10.1371/journal.pone.0047887&size=1"), + URI.create("https://x.org/?DOI_NOT=https://doi.org/10.1371/journal.pone.0047887&size=18"), + URI.create("https://x.org/?DOI_SHOULD=https://doi.org/10.1371/journal.pone.0047887&size=2"), + URI.create("https://x.org/?doi=https://doi.org/10.1371/journal.pone.0047855&size=1"), + URI.create("https://x.org/?doi_should=.pone.0047855,pone.0047887&size=2"), + URI.create("https://x.org/?funding=AFR:296896&size=1"), + URI.create("https://x.org/?funding=NFR:1296896&size=2"), + URI.create("https://x.org/?funding=NFR:296896&size=2"), + URI.create("https://x.org/?funding_source=Norges+forskningsråd&size=2"), + URI.create("https://x.org/?funding_source_not=Norges+forskningsråd&size=18"), + URI.create("https://x.org/?funding_source_SHOULD=Norges&size=2"), + URI.create("https://x.org/?funding_source=Research+Council+of+Norway+(RCN)&size=2"), + URI.create("https://x.org/?ID=018ba3cfcb9c-94f77a1e-ac36-430a-84b0-0619ecbbaf39&size=1"), + URI.create("https://x.org/?ID_NOT=018ba3cfcb9c-94f77a1e-ac36-430a-84b0-0619ecbbaf39&size=19"), + URI.create("https://x.org/?ID_SHOULD=018ba3cfcb9c-94f77a1e-ac36-430a-84b0-0619ecbbaf39&size=1"), + URI.create("https://x.org/?id=018b857b77b7-697ebc73-5195-4ce4-9ba1-1d5a7b540642&size=1"), + URI.create("https://x.org/?id_should=018b857b77b7-697ebc73-5195-4ce4-9ba1-1d5a7b540642" + + "&id_not=018b857b77b7-697ebc73-5195-4ce4-9ba1-1d5a7b540642&size=0"), + URI.create("https://x.org/?id_should=018b857b77b7-697ebc73-5195-4ce4-9ba1-1d5a7b540642&size=1"), + URI.create("https://x.org/?INSTANCE_TYPE=AcademicArticle&size=9"), + URI.create("https://x.org/?INSTANCE_TYPE_NOT=AcademicArticle&size=11"), + URI.create("https://x.org/?INSTANCE_TYPE_SHOULD=AcademicArticle&size=9"), + URI.create("https://x.org/?INSTITUTION" + + "=https://api.dev.nva.aws.unit.no/cristin/organization/20754.6.0.0&size=1"), + URI.create("https://x.org/?INSTITUTION_NOT" + + "=https://api.dev.nva.aws.unit.no/cristin/organization/20754.6.0.0&size=19"), + URI.create("https://x.org/?INSTITUTION_SHOULD=Forsvarets+høgskole&size=2"), + URI.create("https://x.org/?INSTITUTION=1627.0.0.0&size=0"), + URI.create("https://x.org/?INSTITUTION=Forsvarets+høgskole&size=2"), + URI.create("https://x.org/?INSTITUTION=Norwegian+Defence+University+College&size=2"), + URI.create("https://x.org/?INSTITUTION" + + "=https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0&size=2"), + URI.create("https://x.org/?INSTITUTION_NOT=Forsvarets+høgskole&size=18"), + URI.create("https://x.org/?INSTITUTION_NOT" + + "=https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0&size=18"), + URI.create("https://x.org/?INSTITUTION_SHOULD=1627.0.0.0&size=2"), + URI.create("https://x.org/?INSTITUTION_SHOULD=1627.0.0.0,20754.6.0.0&size=2"), + URI.create("https://x.org/?INSTITUTION_SHOULD" + + "=https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0&size=2"), + URI.create("https://x.org/?INSTITUTION_should=194.63.55.0&size=1"), + URI.create("https://x.org/?ISBN=9788202535032&size=1"), + URI.create("https://x.org/?ISBN_NOT=9788202535032&size=19"), + URI.create("https://x.org/?ISBN_SHOULD=9788202535032&size=1"), + URI.create("https://x.org/?issn=1872-9460&size=0"), + URI.create("https://x.org/?ISSN=1435-9529&size=1"), + URI.create("https://x.org/?ISSN_NOT=1435-9529&size=19"), + URI.create("https://x.org/?ISSN_SHOULD=1435-9529&size=1"), + URI.create("https://x.org/?ORCID=https://sandbox.orcid.org/0000-0003-4147-3499&size=2"), + URI.create("https://x.org/?ORCID_NOT=https://sandbox.orcid.org/0000-0003-4147-3499&size=18"), + URI.create("https://x.org/?ORCID_SHOULD=4147-3499&size=2"), + URI.create("https://x.org/?PARENT_PUBLICATION=test&size=0"), + URI.create("https://x.org/?PARENT_PUBLICATION_SHOULD=test&size=0"), + URI.create("https://x.org/?PROJECT=https://api.dev.nva.aws.unit.no/cristin/project/14334813&size=1"), + URI.create("https://x.org/?PROJECT_NOT" + + "=https://api.dev.nva.aws.unit.no/cristin/project/14334813&size=19"), + URI.create("https://x.org/?PROJECT_SHOULD" + + "=https://api.dev.nva.aws.unit.no/cristin/project/14334813&size=1"), + URI.create("https://x.org/?SEARCH_ALL=Fakultet+for+arkitektur&size=1"), + URI.create("https://x.org/?TITLE=Kjetils+ticket+test&size=1"), + URI.create("https://x.org/?TITLE_NOT=Kjetils+ticket+test&size=17"), + URI.create("https://x.org/?TITLE_SHOULD=Simple&size=3"), + URI.create("https://x.org/?TOP_LEVEL_ORGANIZATION" + + "=https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0&size=2"), + URI.create("https://x.org/?UNIT" + + "=https://api.dev.nva.aws.unit.no/cristin/organization/45220004.0.0.0&size=2"), + URI.create("https://x.org/?UNIT_NOT" + + "=https://api.dev.nva.aws.unit.no/cristin/organization/45220004.0.0.0&size=18"), + URI.create("https://x.org/?UNIT_SHOULD=194.63.55.0&size=1"), + URI.create("https://x.org/?USER=1136254@20754.0.0.0&size=2"), + URI.create("https://x.org/?USER_NOT=1136254@20754.0.0.0&size=18"), + URI.create("https://x.org/?USER_SHOULD=1136254@&size=2"), + URI.create("https://x.org/?MODIFIED_BEFORE=1872-01-01&MODIFIED_SINCE=9460-01-01&size=0"), + URI.create("https://x.org/?PUBLICATION_YEAR=2022&size=2"), + URI.create("https://x.org/?PUBLICATION_YEAR_SHOULD=2022&size=2"), + URI.create("https://x.org/?fields=category,title,CONTRIBUTOR&query=Kjetil+Møkkelgjerd&size=2"), + URI.create("https://x.org/?from=0&size=2&topLevelOrganization" + + "=https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0"), + URI.create("https://x.org/?published_before=2023-09-29&size=5"), + URI.create("https://x.org/?published_since=2023-11-05&size=1"), + URI.create("https://x.org/?query=018b857b77b7-697ebc73-5195-4ce4-9ba1-1d5a7b540642" + + "&id_not=018b857b77b7-697ebc73-5195-4ce4-9ba1-1d5a7b540642&size=0"), + URI.create("https://x.org/?query=Forsvarets+høgskole&fields=INSTITUTION&size=2"), + URI.create("https://x.org/?query=Forsvarets+høgskole&size=2"), + URI.create("https://x.org/?query=Kjetil+Møkkelgjerd&fields=CONTRIBUTOR&size=2"), + URI.create("https://x.org/?query=observations&fields=all&size=3"), + URI.create("https://x.org/?query=https://api.dev.nva.aws.unit.no/cristin/organization/20754.6.0.0" + + "&fields=INSTITUTION&size=1"), + URI.create("https://x.org/?fields=CONTRIBUTOR" + + "&query=https://api.dev.nva.aws.unit.no/cristin/person/1136254&size=2") + ); + } + } + + private static void populateIndex() { + var jsonFile = stringFromResources(Path.of("sample_resources_search.json")); + var jsonNodes = + attempt(() -> JsonUtils.dtoObjectMapper.readTree(jsonFile)).orElseThrow(); + + jsonNodes.forEach(node -> { + try { + var attributes = new EventConsumptionAttributes(indexName, SortableIdentifier.next()); + indexingClient.addDocumentToIndex(new IndexDocument(attributes, node)); + } catch (IOException e) { + throw new RuntimeException(e); } + }); + } + + private static void createIndex() throws IOException { + var mappingsJson = stringFromResources(Path.of(TEST_RESOURCES_MAPPINGS)); + var type = new TypeReference>() { }; + var mappings = attempt(() -> JsonUtils.dtoObjectMapper.readValue(mappingsJson, type)).orElseThrow(); + indexingClient.createIndex(indexName, mappings); + } + + private static String generateIndexName() { + return "resources"; } } \ No newline at end of file diff --git a/search-commons/src/test/java/no/unit/nva/search2/ResourceQueryTest.java b/search-commons/src/test/java/no/unit/nva/search2/ResourceQueryTest.java index 62877c412..eabfe0728 100644 --- a/search-commons/src/test/java/no/unit/nva/search2/ResourceQueryTest.java +++ b/search-commons/src/test/java/no/unit/nva/search2/ResourceQueryTest.java @@ -1,16 +1,16 @@ package no.unit.nva.search2; import static java.util.Objects.nonNull; -import static no.unit.nva.search2.model.ParameterKeyResource.CATEGORY; -import static no.unit.nva.search2.model.ParameterKeyResource.CREATED_BEFORE; -import static no.unit.nva.search2.model.ParameterKeyResource.DOI; -import static no.unit.nva.search2.model.ParameterKeyResource.FROM; -import static no.unit.nva.search2.model.ParameterKeyResource.MODIFIED_BEFORE; -import static no.unit.nva.search2.model.ParameterKeyResource.PAGE; -import static no.unit.nva.search2.model.ParameterKeyResource.PUBLISHED_BEFORE; -import static no.unit.nva.search2.model.ParameterKeyResource.PUBLISHED_SINCE; -import static no.unit.nva.search2.model.ParameterKeyResource.SIZE; -import static no.unit.nva.search2.model.ParameterKeyResource.SORT; +import static no.unit.nva.search2.enums.ResourceParameter.CREATED_BEFORE; +import static no.unit.nva.search2.enums.ResourceParameter.DOI; +import static no.unit.nva.search2.enums.ResourceParameter.FROM; +import static no.unit.nva.search2.enums.ResourceParameter.INSTANCE_TYPE; +import static no.unit.nva.search2.enums.ResourceParameter.MODIFIED_BEFORE; +import static no.unit.nva.search2.enums.ResourceParameter.PAGE; +import static no.unit.nva.search2.enums.ResourceParameter.PUBLISHED_BEFORE; +import static no.unit.nva.search2.enums.ResourceParameter.PUBLISHED_SINCE; +import static no.unit.nva.search2.enums.ResourceParameter.SIZE; +import static no.unit.nva.search2.enums.ResourceParameter.SORT; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -18,7 +18,7 @@ import java.net.URI; import java.util.stream.Collectors; import java.util.stream.Stream; -import no.unit.nva.search2.model.OpenSearchQuery; +import no.unit.nva.search2.common.Query; import nva.commons.apigateway.exceptions.BadRequestException; import nva.commons.core.paths.UriWrapper; import org.joda.time.DateTime; @@ -36,7 +36,7 @@ class ResourceQueryTest { void buildOpenSearchSwsUriFromGatewayUri(URI uri) throws BadRequestException { var resourceParameters = ResourceQuery.builder() - .fromQueryParameters(OpenSearchQuery.queryToMapEntries(uri)) + .fromQueryParameters(Query.queryToMapEntries(uri)) .withRequiredParameters(FROM, SIZE, SORT) .build(); assertNotNull(resourceParameters.getValue(FROM).as()); @@ -44,23 +44,22 @@ void buildOpenSearchSwsUriFromGatewayUri(URI uri) throws BadRequestException { var uri2 = UriWrapper.fromUri(resourceParameters.getNvaSearchApiUri()) .addQueryParameters(resourceParameters.toNvaSearchApiRequestParameter()).getUri(); - - logger.info(resourceParameters - .toNvaSearchApiRequestParameter() - .entrySet().stream() - .map(entry -> entry.getKey() + "=" + entry.getValue()) - .collect(Collectors.joining("&"))); + + logger.info( + resourceParameters.toNvaSearchApiRequestParameter() + .entrySet().stream() + .map(entry -> entry.getKey() + "=" + entry.getValue()) + .collect(Collectors.joining("&"))); logger.info(uri2.toString()); assertNotEquals(uri, resourceParameters.getNvaSearchApiUri()); } - @ParameterizedTest @MethodSource("uriDatesProvider") void uriParamsDateToResourceParams(URI uri) throws BadRequestException { var resourceParameters = ResourceQuery.builder() - .fromQueryParameters(OpenSearchQuery.queryToMapEntries(uri)) + .fromQueryParameters(Query.queryToMapEntries(uri)) .withRequiredParameters(FROM, SIZE, SORT) .build(); @@ -93,7 +92,7 @@ void uriParamsDateToResourceParams(URI uri) throws BadRequestException { } var category = - resourceParameters.getValue(CATEGORY).as(); + resourceParameters.getValue(INSTANCE_TYPE).as(); if (nonNull(category)) { logger.info("category: {}", category); } @@ -102,53 +101,44 @@ void uriParamsDateToResourceParams(URI uri) throws BadRequestException { @ParameterizedTest @MethodSource("uriSortingProvider") void uriParamsToResourceParams(URI uri) throws BadRequestException { - var resourceParameters = - ResourceQuery.builder() - .fromQueryParameters(OpenSearchQuery.queryToMapEntries(uri)) - .withRequiredParameters(FROM, SIZE, SORT) - .build(); + var resourceParameters = ResourceQuery.builder() + .fromQueryParameters(Query.queryToMapEntries(uri)) + .withRequiredParameters(FROM, SIZE, SORT) + .build(); assertNotNull(resourceParameters.getValue(FROM).as()); assertNull(resourceParameters.getValue(PAGE).as()); assertNotNull(resourceParameters.getValue(SORT).as()); - } @ParameterizedTest @MethodSource("uriProvider") void failToBuildOpenSearchSwsUriFromMissingRequired(URI uri) { - assertThrows(BadRequestException.class, - () -> ResourceQuery.builder() - .fromQueryParameters(OpenSearchQuery.queryToMapEntries(uri)) - .withRequiredParameters(FROM, SIZE, DOI) - .build() - .getOpenSearchUri()); + assertThrows(BadRequestException.class, () -> ResourceQuery.builder() + .fromQueryParameters(Query.queryToMapEntries(uri)) + .withRequiredParameters(FROM, SIZE, DOI) + .build() + .getOpenSearchUri()); } - @ParameterizedTest @MethodSource("invalidUriProvider") void failToBuildOpenSearchSwsUriFromInvalidGatewayUri(URI uri) { - assertThrows(BadRequestException.class, - () -> ResourceQuery.builder() - .fromQueryParameters(OpenSearchQuery.queryToMapEntries(uri)) - .withRequiredParameters(FROM, SIZE) - .build() - .getOpenSearchUri()); + assertThrows(BadRequestException.class, () -> ResourceQuery.builder() + .fromQueryParameters(Query.queryToMapEntries(uri)) + .withRequiredParameters(FROM, SIZE) + .build() + .getOpenSearchUri()); } - static Stream uriProvider() { return Stream.of( URI.create("https://example.com/"), URI.create("https://example.com/?fields=category,title,created_date"), URI.create("https://example.com/?query=Muhammad+Yahya&fields=CONTRIBUTOR"), URI.create("https://example.com/?CONTRIBUTOR=https://api.dev.nva.aws.unit.no/cristin/person/1136254"), - URI.create("https://example.com/?CONTRIBUTOR_SHOULD=" - + "https://api.dev.nva.aws.unit.no/cristin/person/1136254+" - + "https://api.dev.nva.aws.unit.no/cristin/person/1135555"), URI.create("https://example.com/?CONTRIBUTOR_NOT=" - + "https://api.dev.nva.aws.unit.no/cristin/person/1136254+" - + "https://api.dev.nva.aws.unit.no/cristin/person/1135555"), + + "https://api.dev.nva.aws.unit.no/cristin/person/1136254+" + + "https://api.dev.nva.aws.unit.no/cristin/person/1135555"), URI.create("https://example.com/?fields=all"), URI.create("https://example.com/?category=hello+world&page=1&user=12%203"), URI.create("https://example.com/?category=hello+world&sort=created_date&order=asc"), @@ -157,9 +147,12 @@ static Stream uriProvider() { URI.create("https://example.com/?category=hello+world&user=12%203&page=2"), URI.create("https://example.com/?category=hello+world&user=12%203&offset=30"), URI.create("https://example.com/?category=hello+world&user=12%203&from=30&results=10"), + URI.create( + "https://example.com/?PARENT_PUBLICATION=https://api.dev.nva.aws.unit" + + ".no/publication/018b80c90f4a-75942f6d-544e-4d5b-8129-7b81b957678c"), URI.create("https://example.com/?published_before=2020-01-01&lang=en&user=1%2023"), URI.create("https://example.com/?published_since=2019-01-01&institution=uib&funding_source=NFR&user=Per" - + "%20Eplekjekk")); + + "%20Eplekjekk")); } static Stream uriSortingProvider() { diff --git a/search-commons/src/test/java/no/unit/nva/search2/UserSettingsClientTest.java b/search-commons/src/test/java/no/unit/nva/search2/UserSettingsClientTest.java index 95b039c29..46c8417e0 100644 --- a/search-commons/src/test/java/no/unit/nva/search2/UserSettingsClientTest.java +++ b/search-commons/src/test/java/no/unit/nva/search2/UserSettingsClientTest.java @@ -1,11 +1,11 @@ package no.unit.nva.search2; import static no.unit.nva.indexing.testutils.MockedJwtProvider.setupMockedCachedJwtProvider; -import static no.unit.nva.search2.model.OpenSearchQuery.queryToMapEntries; -import static no.unit.nva.search2.model.ParameterKeyResource.FROM; -import static no.unit.nva.search2.model.ParameterKeyResource.SIZE; -import static no.unit.nva.search2.model.ParameterKeyResource.SORT; -import static nva.commons.core.ioutils.IoUtils.stringFromResources; +import static no.unit.nva.search2.common.MockedHttpResponse.mockedHttpResponse; +import static no.unit.nva.search2.common.Query.queryToMapEntries; +import static no.unit.nva.search2.enums.ResourceParameter.FROM; +import static no.unit.nva.search2.enums.ResourceParameter.SIZE; +import static no.unit.nva.search2.enums.ResourceParameter.SORT; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -13,17 +13,8 @@ import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; -import java.net.http.HttpHeaders; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.nio.file.Path; -import java.util.Collections; -import java.util.Map; -import java.util.Optional; import java.util.stream.Stream; -import javax.net.ssl.SSLSession; import nva.commons.apigateway.exceptions.ApiGatewayException; -import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -34,8 +25,7 @@ class UserSettingsClientTest { private UserSettingsClient userSettingsClient; private static final Logger logger = LoggerFactory.getLogger(UserSettingsClientTest.class); - public static final String SAMPLE_USERSETTINGS_RESPONSE - = "user_settings.json"; + public static final String SAMPLE_USER_SETTINGS_RESPONSE = "user_settings.json"; @BeforeEach public void setUp() throws IOException, InterruptedException { @@ -43,7 +33,7 @@ public void setUp() throws IOException, InterruptedException { var cachedJwtProvider = setupMockedCachedJwtProvider(); userSettingsClient = new UserSettingsClient(cachedJwtProvider, httpClient); when(httpClient.send(any(), any())) - .thenReturn(mockedHttpResponse(SAMPLE_USERSETTINGS_RESPONSE)); + .thenReturn(mockedHttpResponse(SAMPLE_USER_SETTINGS_RESPONSE)); } @ParameterizedTest @@ -72,50 +62,4 @@ static Stream uriProvider() { URI.create("https://example.com/?query=hello+world&fields=all")); } - - @NotNull - public static HttpResponse mockedHttpResponse(String filename) { - return new HttpResponse<>() { - @Override - public int statusCode() { - return 200; - } - - @Override - public HttpRequest request() { - return null; - } - - @Override - public Optional> previousResponse() { - return Optional.empty(); - } - - @Override - public HttpHeaders headers() { - return HttpHeaders.of(Map.of("Content-Type", Collections.singletonList("application/json")), - (s, s2) -> true); - } - - @Override - public String body() { - return stringFromResources(Path.of(filename)); - } - - @Override - public Optional sslSession() { - return Optional.empty(); - } - - @Override - public URI uri() { - return null; - } - - @Override - public HttpClient.Version version() { - return null; - } - }; - } } \ No newline at end of file diff --git a/search-commons/src/test/java/no/unit/nva/search2/common/MockedHttpResponse.java b/search-commons/src/test/java/no/unit/nva/search2/common/MockedHttpResponse.java new file mode 100644 index 000000000..39e09a7d3 --- /dev/null +++ b/search-commons/src/test/java/no/unit/nva/search2/common/MockedHttpResponse.java @@ -0,0 +1,63 @@ +package no.unit.nva.search2.common; + +import static nva.commons.core.ioutils.IoUtils.stringFromResources; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpHeaders; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import javax.net.ssl.SSLSession; +import org.jetbrains.annotations.NotNull; + +public class MockedHttpResponse { + + @NotNull + public static HttpResponse mockedHttpResponse(String filename) { + return new HttpResponse<>() { + @Override + public int statusCode() { + return 200; + } + + @Override + public HttpRequest request() { + return null; + } + + @Override + public Optional> previousResponse() { + return Optional.empty(); + } + + @Override + public HttpHeaders headers() { + return HttpHeaders.of(Map.of("Content-Type", Collections.singletonList("application/json")), + (s, s2) -> true); + } + + @Override + public String body() { + return stringFromResources(Path.of(filename)); + } + + @Override + public Optional sslSession() { + return Optional.empty(); + } + + @Override + public URI uri() { + return null; + } + + @Override + public HttpClient.Version version() { + return null; + } + }; + } +} diff --git a/search-commons/src/test/resources/sample_aggregations.json b/search-commons/src/test/resources/sample_aggregations.json new file mode 100644 index 000000000..38ef025d1 --- /dev/null +++ b/search-commons/src/test/resources/sample_aggregations.json @@ -0,0 +1,4536 @@ +{ + "aggregations": { + "entityDescription": { + "docCount": 37, + "reference": { + "docCount": 37, + "publicationInstance": { + "docCount": 37, + "type": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "AcademicArticle", + "docCount": 36 + }, + { + "key": "AcademicLiteratureReview", + "docCount": 1 + } + ] + } + }, + "publicationContext": { + "docCount": 37, + "publisher": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "id": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + "contributors": { + "docCount": 255, + "identity": { + "docCount": 255, + "id": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/13241", + "docCount": 3, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Ingebjørg Seljeflot", + "docCount": 3 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/13353", + "docCount": 2, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Alf Åge Reistad Pettersen", + "docCount": 2 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/21841", + "docCount": 2, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Harald Arnesen", + "docCount": 2 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/23084", + "docCount": 2, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Lise-Lotte Gundersen", + "docCount": 2 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/10746", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Michael Abdelnoor", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/10824", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Linda Møllersen", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/11391", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Trine Baur Opstad", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/11787", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Gunn Annette Hildrestrand", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/12337", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Tor Svendsen Bjørheim", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/12980", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Ute Krengel", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/13306", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Mats Ökvist", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/13348", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Arnljot Flaa", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/14068", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Felix M Gradstein", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/14940", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Anette Karlsen", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/15544", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Anne Bjørhovde Rossebø", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/16374", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Arne Klungland", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/17038", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Magnar Bjørås", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/17980", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Morten Rostrup", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/18306", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Karl Ludvig Reichelt", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/18517", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Westlye, Lars Tjelta", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/1956", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Anja Bjølgerud", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/22114", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Reidar Haugsrud", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/22874", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Størmer, Erling", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/23750", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Sverre Erik Kjeldsen", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/23831", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Bengt Gunnar Svensson", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/24592", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Truls Norby", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/26268", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Mikal Heldal", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/26703", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Tron Frede Thingstad", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/27869", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Gunnar Bratbak", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/28939", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Gabriel Kiss", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/31796", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Justin W Wells", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/332081", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Ann-Mari Knivsberg", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/37859", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Holtermann, Andreas", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/388595", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Benjamin Storm", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/393240", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Ida Unhammer Njerve", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/39427", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Frode Seland", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/39598", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Hans Torp", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/40139", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Håvard Karoliussen", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/404567", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Sigrid Lædre", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/409254", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Stefan Pieter Sobolowski", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/412582", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Anders Ødegård", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/42659", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Eirik Skogvoll", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/43933", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Ole Edvard Kongstein", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/44093", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Charlotte Ingeborg Björk Ingul", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/446", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Vincent Leroux", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/45052", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Xiang Wang", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/45435", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Adrian Tiron", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/45712", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Jan Martin Nordbotten", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/45802", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Jan Mangerud", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/46036", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Dag Haugland", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/46118", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Harald Furnes", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/46166", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Egil Severin Erichsen", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/47136", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Herbjørn Presthus Heggen", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/47284", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Einar Skulstad Davidsen", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/47694", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Dana Cramariuc", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/47766", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Nickolay V Bukoreshtliev", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/4932", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Lars Sundnes Løvlie", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/50017", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Øystein Strand Lohne", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/50400", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "John-Inge Svendsen", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/50496", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Svein Norland", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/50744", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Fedor Fomin", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/5081", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Jindrich Kania", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/509693", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Linda Augustin Tveterås", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/51894", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Daniel Fliegel", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/5200", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Steffi Munack", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/52853", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Eva Gerdts", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/52990", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Per Magnus Jørgensen", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/53082", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Hans-Hermann Gerdes", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/53115", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Clive R. Bramham", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/531156", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Silvio Funtowicz", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/56283", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Bente Nilsen", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/56740", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Knut Tore Lappegård", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/5731", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Jan Hendrik Van Eerde", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/57601", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Ole-Jakob How", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/5761", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Skjalg Hassellund", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/6007", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Alexander D. Rowe", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/6784", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Erik Waage Nielsen", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/798679", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Bjørn Ove Faldaas", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/8178", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Zuoan Li", + "docCount": 1 + } + ] + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/person/9186", + "docCount": 1, + "name": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Jonathan Marc Polfus", + "docCount": 1 + } + ] + } + } + ] + } + } + } + }, + "associatedArtifacts": { + "docCount": 10 + }, + "resourceOwner.ownerAffiliation": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/184.0.0.0", + "docCount": 11 + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/185.90.0.0", + "docCount": 9 + }, + { + "key": "https://api.dev.nva.aws.unit.no/customer/bb3d0c0c-5065-4623-9b98-5810983c2478", + "docCount": 9 + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0", + "docCount": 2 + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0", + "docCount": 2 + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/1936.0.0.0", + "docCount": 1 + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/2012.0.0.0", + "docCount": 1 + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/2057.0.0.0", + "docCount": 1 + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/217.0.0.0", + "docCount": 1 + } + ] + }, + "resourceOwner.owner": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "uib@184.0.0.0", + "docCount": 11 + }, + { + "key": "uio@185.90.0.0", + "docCount": 9 + }, + { + "key": "1136326@20754.0.0.0", + "docCount": 7 + }, + { + "key": "ntnu@194.0.0.0", + "docCount": 2 + }, + { + "key": "1128464@20754.0.0.0", + "docCount": 1 + }, + { + "key": "1136254@20754.0.0.0", + "docCount": 1 + }, + { + "key": "34322@20754.0.0.0", + "docCount": 1 + }, + { + "key": "41902@20754.0.0.0", + "docCount": 1 + }, + { + "key": "hbe@1936.0.0.0", + "docCount": 1 + }, + { + "key": "norce@2057.0.0.0", + "docCount": 1 + }, + { + "key": "ous@2012.0.0.0", + "docCount": 1 + }, + { + "key": "uis@217.0.0.0", + "docCount": 1 + } + ] + }, + "topLevelOrganizations": { + "docCount": 142, + "id": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/185.90.0.0", + "docCount": 14, + "labels": { + "docCount": 14, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Universitetet i Oslo", + "docCount": 14 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Oslo", + "docCount": 14 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/184.0.0.0", + "docCount": 11, + "labels": { + "docCount": 11, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Universitetet i Bergen", + "docCount": 11 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Bergen", + "docCount": 11 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/2012.0.0.0", + "docCount": 8, + "labels": { + "docCount": 8, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Oslo universitetssykehus HF", + "docCount": 8 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Oslo University Hospital", + "docCount": 8 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/9126.0.0.0", + "docCount": 7, + "labels": { + "docCount": 7, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Andre institusjoner", + "docCount": 7 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0", + "docCount": 6, + "labels": { + "docCount": 6, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Noregs teknisk-naturvitskaplege universitet", + "docCount": 6 + } + ] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Norges teknisk-naturvitenskapelige universitet", + "docCount": 6 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Norwegian University of Science and Technology", + "docCount": 6 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13100099.0.0.0", + "docCount": 3, + "labels": { + "docCount": 3, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Szkola Glówna Gospodarstwa Wiejskiego w Warszawie", + "docCount": 3 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Warsaw University of Life Sciences", + "docCount": 3 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/186.0.0.0", + "docCount": 3, + "labels": { + "docCount": 3, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "UiT Norges arktiske universitet", + "docCount": 3 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "UiT The Arctic University of Norway", + "docCount": 3 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/9127.0.0.0", + "docCount": 3, + "labels": { + "docCount": 3, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Utenlandsk utdanningsinstitusjon", + "docCount": 3 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/10100086.0.0.0", + "docCount": 2, + "labels": { + "docCount": 2, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Syddansk Universitet", + "docCount": 2 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Southern Denmark", + "docCount": 2 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/10600044.0.0.0", + "docCount": 2, + "labels": { + "docCount": 2, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Sveriges lantbruksuniversitet", + "docCount": 2 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Swedish University of Agricultural Sciences", + "docCount": 2 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/12300000.0.0.0", + "docCount": 2, + "labels": { + "docCount": 2, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Italia", + "docCount": 2 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Italy", + "docCount": 2 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13100115.0.0.0", + "docCount": 2, + "labels": { + "docCount": 2, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Uniwersytet w Bialymstoku", + "docCount": 2 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Bialystok", + "docCount": 2 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/14400003.0.0.0", + "docCount": 2, + "labels": { + "docCount": 2, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Albert-Ludwigs-Universität Freiburg", + "docCount": 2 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Freiburg", + "docCount": 2 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/14400181.0.0.0", + "docCount": 2, + "labels": { + "docCount": 2, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Humboldt-Universität zu Berlin", + "docCount": 2 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Humboldt University Berlin", + "docCount": 2 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/15800012.0.0.0", + "docCount": 2, + "labels": { + "docCount": 2, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Univerzita Karlova v Praze", + "docCount": 2 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Charles University, Prague", + "docCount": 2 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/68400996.0.0.0", + "docCount": 2, + "labels": { + "docCount": 2, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Princeton University", + "docCount": 2 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization", + "docCount": 1, + "labels": { + "docCount": 0, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/10100000.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Danmark", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Denmark", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/10100002.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Aalborg Universitet", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Aalborg University", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/10100014.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Danmarks Tekniske Universitet", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Technical University of Denmark", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/10101907.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Rigshospitalet - København Universitetshospital", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Copenhagen University Hospital", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/10107411.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Det Nationale Forskningscenter for Arbejdsmiljø", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "National Research Centre for the Working Environment", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/10300000.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Finland", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Finland", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/10300010.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Helsingin yliopisto / Helsingfors universitet", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Helsinki", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/10600028.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Linköpings universitet", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Linköping University", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/10600048.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Umeå universitet", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Umeå University", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/11200246.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Université de Liège", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/11700000.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Frankrike", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "France", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/11700396.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Université Paris Diderot", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Paris Diderot University Paris VII)", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/11700450.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Université de Nice-Sophia Antipolis", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Nice-Sophia Antipolis", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/11701921.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Assistance Publique - Hôpitaux de Paris", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/11705901.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Centre national de la recherche scientifique", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "National Center for Scientific Research", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/11707410.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Institut National de Recherche en Informatique et en Automatique", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "The French National Institute for Research in Computer Science and Control", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/11900006.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Ethnikon kai Kapodistriakon Panepistimion Athinon", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "National and Kapodistrian University of Athens", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/12300023.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Università degli Studi 'Federico II' di Napoli", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Naples 'Federico II'", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/12300044.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Università degli Studi di Foggia", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Foggia", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/12300050.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Università degli Studi di Milano", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Milan", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/12300066.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Università degli Studi di Torino", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Turin", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/12300089.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Università Politecnica delle Marche", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/12700073.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Universiteit Maastricht", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Maastricht University", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/12700075.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Universiteit Utrecht", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Utrecht University", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/12700076.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Universiteit van Amsterdam", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Amsterdam", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13107410.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Instytut Biologii Doswiadczalnej im. M. Nenckiengo PAN", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Nencki Institute of Experimental Biology", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13200149.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Universidade do Algarve", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Algarve", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13700070.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Universitat Politècnica de Catalunya", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Polytechnic University of Catalonia", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13701931.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Hospital Universitario La Paz", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "La Paz University Hospital", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13900000.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Storbritannia og Nord-Irland", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "United Kingdom", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13900054.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Loughborough University", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13900100.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University College London", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13900152.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Glasgow", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13900223.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Plymouth", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13901925.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Newcastle upon Tyne Hospitals", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/13907410.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "British Antarctic Survey", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/14100003.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Eidgenössische Technische Hochschule Zürich", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Swiss Federal Institute of Technology Zürich", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/14300068.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Bitlis Eren Universitesi", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Bitlis Eren University", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/14400296.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Universität Ulm", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Ulm", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/14400299.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Universität des Saarlandes", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Saarland University", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/14407424.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "GeoForschungsZentrum Potsdam", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Helmholtz Centre Potsdam", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/150.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Norges idrettshøgskole", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Norwegian School of Sport Sciences", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/15300000.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Østerrike", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Austria", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/15300081.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Medizinische Universität Wien", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Medical University of Vienna", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/15801901.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Fakultní nemocnice v Motole", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Motol University Hospital", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/1904.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Nordlandssykehuset HF", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Nordland Hospital Trust", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/1936.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Helse Bergen HF - Haukeland universitetssykehus", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Bergen Hospital Trust - Haukeland University Hospital", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/204.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Nord universitet", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Nord University", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/2057.3.0.0", + "docCount": 1, + "labels": { + "docCount": 0, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Sikt – Kunnskapssektorens tjenesteleverandør", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Sikt - Norwegian Agency for Shared Services in Education and Research", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/217.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Universitetet i Stavanger", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Stavanger", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/42800000.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Filippinene", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Philippines", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/48400694.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Chinese Academy of Sciences", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/61200007.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Alberta", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/61200045.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Carleton University", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/61200062.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Ottawa", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/68400000.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "USA", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "USA", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/68400196.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of California, San Diego", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/68400232.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Colorado at Boulder", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/68400514.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Purdue University", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/68401210.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of North Carolina at Chapel Hill", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/68405903.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "National Institutes of Health", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "National Institutes of Health", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/68420033.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Harvard Medical School", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/7401.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "SINTEF AS", + "docCount": 1 + } + ] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "SINTEF AS", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "SINTEF", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/7431.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Havforskningsinstituttet", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Institute of Marine Research", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/7464.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Norsk institutt for vannforsking", + "docCount": 1 + } + ] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Norsk institutt for vannforskning", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Norwegian Institute of Water Research", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/76000042.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Universidad Peruana 'Cayetano Heredia'", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Peruvian University 'Cayetano Heredia', San Martín de Porres", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/80500066.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of New South Wales", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/80500073.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "University of Sydney", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "https://api.dev.nva.aws.unit.no/cristin/organization/9198.0.0.0", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Diverse norske bedrifter og organisasjoner", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + } + ] + } + }, + "fundings": { + "docCount": 14, + "identifier": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "NFR", + "docCount": 10, + "labels": { + "docCount": 10, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Norges forskningsråd", + "docCount": 10 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Research Council of Norway (RCN)", + "docCount": 10 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "EU", + "docCount": 2, + "labels": { + "docCount": 2, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "EU", + "docCount": 2 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "EU", + "docCount": 2 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "EC/H2020", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "EC/H2020", + "docCount": 1 + } + ] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "EC/H2020", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "EC/H2020", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + }, + { + "key": "NILU", + "docCount": 1, + "labels": { + "docCount": 1, + "nn": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + }, + "nb": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "NILU - Norsk institutt for luftforskning", + "docCount": 1 + } + ] + }, + "en": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [ + { + "key": "Norwegian Institute for Air Research", + "docCount": 1 + } + ] + }, + "sme": { + "docCountErrorUpperBound": 0, + "sumOtherDocCount": 0, + "buckets": [] + } + } + } + ] + } + } + } +} diff --git a/search-commons/src/test/resources/sample_import_candidate_search.json b/search-commons/src/test/resources/sample_import_candidate_search.json new file mode 100644 index 000000000..e43e94762 --- /dev/null +++ b/search-commons/src/test/resources/sample_import_candidate_search.json @@ -0,0 +1,1563 @@ +[ + { + "importStatus": { + "candidateStatus": "NOT_IMPORTED", + "modifiedDate": "2023-11-20T19:38:32.362135196Z" + }, + "collaborationType": "NonCollaborative", + "type": "ImportCandidateSummary", + "publicationInstance": { + "volume": "60", + "issue": "3", + "articleNumber": "036102", + "type": "AcademicArticle" + }, + "associatedArtifacts": [], + "journal": { + "id": "https://api.dev.nva.aws.unit.no/publication-channels-v2/journal/899497CD-FC96-431D-BE38-5B10F1428969/2021", + "type": "Journal" + }, + "createdDate": "2023-11-20T19:38:32.361612653Z", + "totalVerifiedContributors": 0, + "mainTitle": "All-optical multi-wavelength regenerator based on four-wave mixing", + "organizations": [], + "additionalIdentifiers": [ + { + "sourceName": "Scopus", + "type": "AdditionalIdentifier", + "value": "2-s2.0-85104787031" + } + ], + "publicationYear": "2021", + "id": "https://api.dev.nva.aws.unit.no/publication/import-candidate/018bee3ddae4-653812a8-ed19-469b-8078-c3b488f71f74", + "contributors": [ + { + "sequence": 1, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Muhammad Usama Khan", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "type": "Organization", + "labels": { + "en": "National University of Sciences and Technology, School of Electrical Engineering and Computer Science" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 2, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Abdulah Jeza Aljohani", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/54400004.0.0.0", + "type": "Organization", + "labels": { + "nb": "King Abdul Aziz University", + "en": "King Abdul Aziz University" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 3, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Aamir Gulistan", + "orcId": "https://orcid.org/0000-0002-9520-4211", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20277.0.0.0", + "type": "Organization", + "labels": { + "nb": "Simula Metropolitan Center for Digital Engineering" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/7498.0.0.0", + "type": "Organization", + "labels": { + "nb": "Simula Research Laboratory" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 4, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Salman Ghafoor", + "orcId": "https://orcid.org/0000-0002-1031-4471", + "type": "Identity" + }, + "correspondingAuthor": true, + "affiliations": [ + { + "type": "Organization", + "labels": { + "en": "National University of Sciences and Technology, School of Electrical Engineering and Computer Science" + } + } + ], + "type": "Contributor" + } + ], + "doi": "https://doi.org/10.1117/1.OE.60.3.036102", + "totalContributors": 4 + }, + { + "importStatus": { + "candidateStatus": "NOT_IMPORTED", + "modifiedDate": "2023-11-20T19:38:58.568863583Z" + }, + "collaborationType": "NonCollaborative", + "type": "ImportCandidateSummary", + "publicationInstance": { + "volume": "13", + "pages": { + "end": "1323", + "type": "Range", + "begin": "1285" + }, + "issue": "3", + "type": "AcademicLiteratureReview" + }, + "associatedArtifacts": [ + { + "identifier": "8ffecd57-3130-4c18-b9b3-267e2d6a176b", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 2716847, + "publisherAuthority": false, + "name": "Best+therapeutic+practices+for+the+use+of+antibacterial+agents+in+finfish+aquaculture_2021_Rigos_et_al.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T19:39:00.332108791Z", + "type": "PublishedFile", + "visibleForNonOwner": true + }, + { + "identifier": "5e2a88ae-26ea-45fe-a1e7-eafacf84f6c6", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 2699482, + "publisherAuthority": false, + "name": "raq.12523.pdf", + "administrativeAgreement": false, + "mimeType": "application/octet-stream", + "publishedDate": "2023-11-20T19:39:01.551163279Z", + "type": "PublishedFile", + "visibleForNonOwner": true + } + ], + "journal": { + "id": "https://api.dev.nva.aws.unit.no/publication-channels-v2/journal/B812F187-1A4E-4348-8158-C10371B8A08C/2021", + "type": "Journal" + }, + "createdDate": "2023-11-20T19:38:58.568858915Z", + "totalVerifiedContributors": 0, + "mainTitle": "Best therapeutic practices for the use of antibacterial agents in finfish aquaculture: a particular view on European seabass (Dicentrarchus labrax) and gilthead seabream (Sparus aurata) in Mediterranean aquaculture", + "organizations": [], + "additionalIdentifiers": [ + { + "sourceName": "Scopus", + "type": "AdditionalIdentifier", + "value": "2-s2.0-85098160364" + } + ], + "publicationYear": "2021", + "id": "https://api.dev.nva.aws.unit.no/publication/import-candidate/018bee3e4a96-4e698b67-310f-4e75-9765-3c87589a7bf8", + "contributors": [ + { + "sequence": 1, + "role": { + "type": "Creator" + }, + "identity": { + "name": "George Rigos", + "orcId": "https://orcid.org/0000-0002-3148-6213", + "type": "Identity" + }, + "correspondingAuthor": true, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/11907400.0.0.0", + "type": "Organization", + "labels": { + "nb": "Hellenic Centre for Marine Research" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 2, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Dimitra Kogiannou", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/11907400.0.0.0", + "type": "Organization", + "labels": { + "nb": "Hellenic Centre for Marine Research" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 3, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Francesc Padrós", + "orcId": "https://orcid.org/0000-0002-8610-5692", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/13700067.0.0.0", + "type": "Organization", + "labels": { + "nb": "Universitat Autònoma de Barcelona", + "en": "Autonomous University of Barcelona" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 4, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Carles Cristòfol", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/13700067.0.0.0", + "type": "Organization", + "labels": { + "nb": "Universitat Autònoma de Barcelona", + "en": "Autonomous University of Barcelona" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 5, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Daniela Florio", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/12300036.0.0.0", + "type": "Organization", + "labels": { + "nb": " Università degli Studi di Bologna", + "en": "University of Bologna" + } + } + ], + "type": "Contributor" + } + ], + "doi": "https://doi.org/10.1111/raq.12523", + "totalContributors": 7 + }, + { + "importStatus": { + "candidateStatus": "NOT_IMPORTED", + "modifiedDate": "2023-11-20T19:38:19.691279631Z" + }, + "collaborationType": "Collaborative", + "type": "ImportCandidateSummary", + "publicationInstance": { + "pages": { + "end": "202", + "type": "Range", + "begin": "197" + }, + "type": "AcademicChapter" + }, + "associatedArtifacts": [ + { + "identifier": "ca8c63c7-d7ac-43f5-bca5-19051faf1fed", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 3249110, + "publisherAuthority": false, + "name": "3524273.3532886.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T19:38:21.554335620Z", + "type": "PublishedFile", + "visibleForNonOwner": true + } + ], + "createdDate": "2023-11-20T19:38:19.691273690Z", + "totalVerifiedContributors": 3, + "mainTitle": "Njord: A Fishing Trawler Dataset", + "organizations": [ + { + "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", + "type": "Organization", + "labels": { + "nb": "Universitetet i Oslo", + "en": "University of Oslo" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/customer/2d35d439-055d-40e5-94de-a9ec28493835", + "type": "Organization", + "labels": { + "nb": "UiT Norges arktiske universitet", + "en": "UiT The Arctic University of Norway" + } + } + ], + "additionalIdentifiers": [ + { + "sourceName": "Scopus", + "type": "AdditionalIdentifier", + "value": "2-s2.0-85137144310" + } + ], + "publicationYear": "2022", + "id": "https://api.dev.nva.aws.unit.no/publication/import-candidate/018bee3f4c8c-edc1bd12-fe88-41a2-a906-10159164307a", + "contributors": [ + { + "sequence": 1, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Tor Arne Schmidt Nordmo", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/186.0.0.0", + "type": "Organization", + "labels": { + "nb": "UiT Norges arktiske universitet", + "en": "UiT The Arctic University of Norway" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 2, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Aril Bernhard Ovesen", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/186.0.0.0", + "type": "Organization", + "labels": { + "nb": "UiT Norges arktiske universitet", + "en": "UiT The Arctic University of Norway" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 3, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Bjørn Aslak Juliussen", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/186.0.0.0", + "type": "Organization", + "labels": { + "nb": "UiT Norges arktiske universitet", + "en": "UiT The Arctic University of Norway" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 4, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Steven Alexander Hicks", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20277.0.0.0", + "type": "Organization", + "labels": { + "nb": "Simula Metropolitan Center for Digital Engineering" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 5, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Vajira Thambawita", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20277.0.0.0", + "type": "Organization", + "labels": { + "nb": "Simula Metropolitan Center for Digital Engineering" + } + } + ], + "type": "Contributor" + } + ], + "doi": "https://doi.org/10.1145/3524273.3532886", + "totalContributors": 9 + }, + { + "importStatus": { + "candidateStatus": "NOT_IMPORTED", + "modifiedDate": "2023-11-20T19:40:54.004861974Z" + }, + "collaborationType": "Collaborative", + "type": "ImportCandidateSummary", + "publicationInstance": { + "volume": "18", + "issue": "5", + "articleNumber": "e1003603", + "type": "AcademicArticle" + }, + "associatedArtifacts": [ + { + "identifier": "244b4efd-252e-4f3f-8de2-406ad64afaca", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 1268667, + "publisherAuthority": false, + "name": "journal.pmed.1003603.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T19:40:55.022348938Z", + "type": "PublishedFile", + "visibleForNonOwner": true + }, + { + "identifier": "cd4d3ae5-0667-476f-acce-b40e0f7dfb1f", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 1381772, + "publisherAuthority": false, + "name": "86199b9e-ca75-4504-a411-f77b7a847c3f.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T19:40:55.640931444Z", + "type": "PublishedFile", + "visibleForNonOwner": true + }, + { + "identifier": "ab82cc55-c834-4169-ac69-38f7fdf216ec", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 1381772, + "publisherAuthority": false, + "name": "36823bf7-aa70-44e5-812d-e9636c4a9bbc.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T19:40:56.144752645Z", + "type": "PublishedFile", + "visibleForNonOwner": true + } + ], + "journal": { + "id": "https://api.dev.nva.aws.unit.no/publication-channels-v2/journal/948B1795-A32A-4525-998B-36579C43795F/2021", + "type": "Journal" + }, + "createdDate": "2023-11-20T19:40:54.004856328Z", + "totalVerifiedContributors": 3, + "mainTitle": "Risk of miscarriage in women with chronic diseases in Norway: A registry linkage study", + "organizations": [ + { + "id": "https://api.dev.nva.aws.unit.no/customer/95bfedd6-0a44-4013-8e96-256b0efb7d28", + "type": "Organization", + "labels": { + "nb": "Folkehelseinstituttet", + "en": "Norwegian Institute of Public Health" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/customer/d039e7ea-1380-46f1-bb7d-b6456ddc0fc2", + "type": "Organization", + "labels": { + "nb": "NORCE Norwegian Research Centre AS", + "en": "NORCE Norwegian Research Centre AS" + } + } + ], + "additionalIdentifiers": [ + { + "sourceName": "Scopus", + "type": "AdditionalIdentifier", + "value": "2-s2.0-85106378132" + } + ], + "publicationYear": "2021", + "id": "https://api.dev.nva.aws.unit.no/publication/import-candidate/018bee400a1f-9c4f3d49-316e-48c0-91f0-45046f382735", + "contributors": [ + { + "sequence": 1, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Maria C. Magnus", + "type": "Identity" + }, + "correspondingAuthor": true, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/7502.0.0.0", + "type": "Organization", + "labels": { + "nb": "Folkehelseinstituttet", + "en": "Norwegian Institute of Public Health" + } + }, + { + "type": "Organization", + "labels": { + "en": "MRC IntegrativeEpidemiology Unit at the University of Bristol" + } + }, + { + "type": "Organization", + "labels": { + "en": "Population Health Sciences, BristolMedical School" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 2, + "role": { + "type": "Creator" + }, + "identity": { + "verificationStatus": "Verified", + "name": "Nils-Halvdan Morken", + "id": "https://api.dev.nva.aws.unit.no/cristin/person/51762", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1936.12.0.0", + "type": "Organization", + "labels": { + "nb": "Overlege / forsker" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/184.13.25.0", + "type": "Organization", + "labels": { + "nb": "Professor", + "en": "Professor" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/7502.0.0.0", + "type": "Organization", + "labels": { + "nb": "Folkehelseinstituttet", + "en": "Norwegian Institute of Public Health" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 3, + "role": { + "type": "Creator" + }, + "identity": { + "verificationStatus": "Verified", + "name": "Knut-Arne Wensaas", + "id": "https://api.dev.nva.aws.unit.no/cristin/person/52969", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/2057.91.17.12", + "type": "Organization", + "labels": { + "nb": "Forsker ii", + "en": "Researcher ii" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 4, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Allen J. Wilcox", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/68405928.0.0.0", + "type": "Organization", + "labels": { + "nb": "National Institute of Environmental Health Sciences" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 5, + "role": { + "type": "Creator" + }, + "identity": { + "verificationStatus": "Verified", + "name": "Siri Eldevik Håberg", + "id": "https://api.dev.nva.aws.unit.no/cristin/person/12282", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/7502.2.2.0", + "type": "Organization", + "labels": { + "nb": "Fagdirektør", + "en": "Scientific director" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/7502.0.0.0", + "type": "Organization", + "labels": { + "nb": "Folkehelseinstituttet", + "en": "Norwegian Institute of Public Health" + } + } + ], + "type": "Contributor" + } + ], + "doi": "https://doi.org/10.1371/journal.pmed.1003603", + "totalContributors": 5 + }, + { + "importStatus": { + "candidateStatus": "IMPORTED", + "modifiedDate": "2023-11-21T07:28:37.017917397Z", + "nvaPublicationId": "https://api.dev.nva.aws.unit.no/publication/018bf0c7ed0d-589a7f72-4b6e-4651-b902-7621439a9f06", + "setBy": "1136326@20754.0.0.0" + }, + "collaborationType": "NonCollaborative", + "type": "ImportCandidateSummary", + "publicationInstance": { + "volume": "2020", + "pages": { + "end": "149", + "type": "Range", + "begin": "114" + }, + "issue": "36", + "type": "AcademicArticle" + }, + "associatedArtifacts": [ + { + "identifier": "5d710b12-601b-49f6-87b5-32905f9c5099", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 1731956, + "publisherAuthority": false, + "name": "373847-Article Text-540578-1-10-20200930.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T15:58:23.784905592Z", + "type": "PublishedFile", + "visibleForNonOwner": true + } + ], + "journal": { + "id": "https://api.dev.nva.aws.unit.no/publication-channels-v2/journal/D04CBD05-5396-425E-8777-79181FE32E6D/2020", + "type": "Journal" + }, + "createdDate": "2023-11-20T15:58:21.739094338Z", + "totalVerifiedContributors": 1, + "mainTitle": "Lexicons, Literacies and Design Futures", + "organizations": [], + "additionalIdentifiers": [ + { + "sourceName": "Scopus", + "type": "AdditionalIdentifier", + "value": "2-s2.0-85109415624" + } + ], + "publicationYear": "2020", + "id": "https://api.dev.nva.aws.unit.no/publication/import-candidate/018bed744c78-f53e06f7-74da-4c91-969f-ec307a7e7816", + "contributors": [ + { + "sequence": 1, + "role": { + "type": "Creator" + }, + "identity": { + "verificationStatus": "Verified", + "name": "Andrew Morrison", + "id": "https://api.dev.nva.aws.unit.no/cristin/person/23666", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/189.2.0.0", + "type": "Organization", + "labels": { + "nb": "Professor", + "en": "Professor" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/189.0.0.0", + "type": "Organization", + "labels": { + "nb": "Arkitektur- og designhøgskolen i Oslo", + "en": "The Oslo School of Architecture and Design" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 2, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Nina Bjørnstad", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/189.0.0.0", + "type": "Organization", + "labels": { + "nb": "Arkitektur- og designhøgskolen i Oslo", + "en": "The Oslo School of Architecture and Design" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 3, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Einar Sneve Martinussen", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/189.0.0.0", + "type": "Organization", + "labels": { + "nb": "Arkitektur- og designhøgskolen i Oslo", + "en": "The Oslo School of Architecture and Design" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 4, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Bjørn Johansen", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/185.0.0.0", + "type": "Organization", + "labels": { + "nb": "Universitetet i Oslo", + "en": "University of Oslo" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 5, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Bastien Kerspern", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "type": "Organization", + "labels": { + "en": "Design Friction" + } + } + ], + "type": "Contributor" + } + ], + "doi": "https://doi.org/10.46467/TdD36.2020.114-149", + "totalContributors": 6 + }, + { + "importStatus": { + "candidateStatus": "IMPORTED", + "modifiedDate": "2023-11-21T07:14:20.984810674Z", + "nvaPublicationId": "https://api.dev.nva.aws.unit.no/publication/018bf0badda1-f251e5ad-f5d2-4e5b-bb67-a8f78a12aa5c", + "setBy": "1136326@20754.0.0.0" + }, + "collaborationType": "Collaborative", + "type": "ImportCandidateSummary", + "publicationInstance": { + "volume": "111", + "pages": { + "end": "108", + "type": "Range", + "begin": "106" + }, + "type": "JournalLetter" + }, + "associatedArtifacts": [ + { + "identifier": "fcdf655e-4206-4e0f-8f94-30e281d0a7cd", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 0, + "publisherAuthority": true, + "name": "4c78a1db-ede3-4344-a9a3-c72b771a295e.pdf", + "administrativeAgreement": false, + "publishedDate": "2023-11-20T15:35:36.102946529Z", + "type": "PublishedFile", + "visibleForNonOwner": true + } + ], + "journal": { + "id": "https://api.dev.nva.aws.unit.no/publication-channels-v2/journal/497EF4B2-D0DE-4525-AF6E-B53E30A55420/2023", + "type": "Journal" + }, + "createdDate": "2023-11-20T15:35:34.955496291Z", + "totalVerifiedContributors": 2, + "mainTitle": "In reply: Why big data carries big potential rather than big trouble", + "organizations": [ + { + "id": "https://api.dev.nva.aws.unit.no/customer/95bfedd6-0a44-4013-8e96-256b0efb7d28", + "type": "Organization", + "labels": { + "nb": "Folkehelseinstituttet", + "en": "Norwegian Institute of Public Health" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/customer/fe945ea8-22d1-481c-b5be-4e0447d5656c", + "type": "Organization", + "labels": { + "nb": "Høgskulen på Vestlandet", + "en": "Western Norway University of Applied Sciences" + } + } + ], + "additionalIdentifiers": [ + { + "sourceName": "Scopus", + "type": "AdditionalIdentifier", + "value": "2-s2.0-85168575107" + } + ], + "publicationYear": "2023", + "id": "https://api.dev.nva.aws.unit.no/publication/import-candidate/018bed5f6e4c-4878afe2-498c-4595-a762-e9d976b9acd8", + "contributors": [ + { + "sequence": 1, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Julie Werenberg Dreier", + "orcId": "https://orcid.org/0000-0002-9339-4170", + "type": "Identity" + }, + "correspondingAuthor": true, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/10100003.0.0.0", + "type": "Organization", + "labels": { + "nb": "Aarhus Universitet", + "en": "Aarhus University" + } + }, + { + "type": "Organization", + "labels": { + "en": "Department of Clinical Medicine, University of Bergen" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 2, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Marte Helene Bjørk", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/184.0.0.0", + "type": "Organization", + "labels": { + "nb": "Universitetet i Bergen", + "en": "University of Bergen" + } + }, + { + "type": "Organization", + "labels": { + "en": "Department of Neurology, Haukeland University Hospital" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 3, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Silje Alvestad", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/184.0.0.0", + "type": "Organization", + "labels": { + "nb": "Universitetet i Bergen", + "en": "University of Bergen" + } + }, + { + "type": "Organization", + "labels": { + "en": "National Center for Epilepsy, Member of the European Reference Network EpiCARE, Oslo University Hospital" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 4, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Mika Gissler", + "orcId": "https://orcid.org/0000-0001-8254-7525", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "type": "Organization", + "labels": { + "en": "Knowledge Brokers, Finnish Institute for Health and Welfare" + } + }, + { + "type": "Organization", + "labels": { + "en": "Region Stockholm, Academic Primary Health Care Centre" + } + }, + { + "type": "Organization", + "labels": { + "en": "Karolinska Institute, Department of Molecular Medicine and Surgery" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 5, + "role": { + "type": "Creator" + }, + "identity": { + "verificationStatus": "Verified", + "name": "Jannicke Igland", + "id": "https://api.dev.nva.aws.unit.no/cristin/person/49545", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/184.13.26.0", + "type": "Organization", + "labels": { + "nb": "Senioringeniør", + "en": "Senior engineer" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/203.11.12.0", + "type": "Organization", + "labels": { + "nb": "Førsteamanuensis", + "en": "Associate professor" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/184.0.0.0", + "type": "Organization", + "labels": { + "nb": "Universitetet i Bergen", + "en": "University of Bergen" + } + } + ], + "type": "Contributor" + } + ], + "doi": "https://doi.org/10.1016/j.seizure.2023.08.007", + "totalContributors": 12 + }, + { + "importStatus": { + "candidateStatus": "IMPORTED", + "modifiedDate": "2023-11-21T14:08:13.790302707Z", + "nvaPublicationId": "https://api.dev.nva.aws.unit.no/publication/018bf235c52d-17bd8622-fabb-4a32-bcc6-3f4f1d2a3184", + "setBy": "1136254@20754.0.0.0" + }, + "collaborationType": "NonCollaborative", + "type": "ImportCandidateSummary", + "publicationInstance": { + "type": "AcademicArticle" + }, + "associatedArtifacts": [ + { + "identifier": "53a0da3e-99bf-479f-a77a-84caf7112e83", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 693555, + "publisherAuthority": false, + "name": "f18e6206-2446-49e3-83c1-f47110e6c46d.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T15:42:52.057941723Z", + "type": "PublishedFile", + "visibleForNonOwner": true + }, + { + "identifier": "ef857f01-f956-4b98-bb15-d139358414d0", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 693555, + "publisherAuthority": false, + "name": "Ciao+AI+the+Italian+adaptation+and+validation+of+the+Chatbot+Usability+Scale.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T15:42:53.388182377Z", + "type": "PublishedFile", + "visibleForNonOwner": true + }, + { + "identifier": "a24e3612-20b9-4493-b2b9-d0a5849d2d4f", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 693555, + "publisherAuthority": false, + "name": "Chatbot AI Responsibility.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T15:42:54.325310885Z", + "type": "PublishedFile", + "visibleForNonOwner": true + }, + { + "identifier": "e6d4a143-a6db-48cb-ba5b-4bb65506e29b", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 693555, + "publisherAuthority": false, + "name": "90288b89-bec2-4204-9911-0a9c9a396eb5.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T15:42:54.809584369Z", + "type": "PublishedFile", + "visibleForNonOwner": true + }, + { + "identifier": "37e8b303-b316-4baa-adb1-e0b5b569d747", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 693555, + "publisherAuthority": false, + "name": "Chatbot AI Responsibility.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T15:42:55.706393787Z", + "type": "PublishedFile", + "visibleForNonOwner": true + } + ], + "journal": { + "id": "https://api.dev.nva.aws.unit.no/publication-channels-v2/journal/22E08234-76E2-4708-BE1F-12488411E67B/2023", + "type": "Journal" + }, + "createdDate": "2023-11-20T15:42:51.488078044Z", + "totalVerifiedContributors": 0, + "mainTitle": "Ciao AI: the Italian adaptation and validation of the Chatbot Usability Scale", + "organizations": [], + "additionalIdentifiers": [ + { + "sourceName": "Scopus", + "type": "AdditionalIdentifier", + "value": "2-s2.0-85160834649" + } + ], + "publicationYear": "2023", + "id": "https://api.dev.nva.aws.unit.no/publication/import-candidate/018bed662332-010a374d-bbda-4446-8f28-d7d28ec1c94c", + "contributors": [ + { + "sequence": 1, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Simone Borsci", + "orcId": "https://orcid.org/0000-0002-3591-3577", + "type": "Identity" + }, + "correspondingAuthor": true, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/12700074.0.0.0", + "type": "Organization", + "labels": { + "nb": "Universiteit Twente", + "en": "University of Twente, Enschede" + } + }, + { + "type": "Organization", + "labels": { + "en": "Department of Surgery and Cancer, Faculty of Medicine, NIHR London IVD, Imperial College of London" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 2, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Elisa Prati", + "orcId": "https://orcid.org/0000-0002-3088-3735", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/12300051.0.0.0", + "type": "Organization", + "labels": { + "nb": "Università degli Studi di Modena e Reggio Emilia", + "en": "University of Modena and Reggio Emilia" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 3, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Alessio Malizia", + "orcId": "https://orcid.org/0000-0002-2601-7009", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization", + "type": "Organization", + "labels": {} + }, + { + "type": "Organization", + "labels": { + "en": "Molde University College" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 4, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Martin Schmettow", + "orcId": "https://orcid.org/0000-0003-0240-4087", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/12700074.0.0.0", + "type": "Organization", + "labels": { + "nb": "Universiteit Twente", + "en": "University of Twente, Enschede" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 5, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Alan Chamberlain", + "orcId": "https://orcid.org/0000-0002-2122-8077", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization", + "type": "Organization", + "labels": {} + } + ], + "type": "Contributor" + } + ], + "doi": "https://doi.org/10.1007/s00779-023-01731-2", + "totalContributors": 6 + }, + { + "importStatus": { + "candidateStatus": "IMPORTED", + "modifiedDate": "2023-11-21T13:56:42.220681536Z", + "nvaPublicationId": "https://api.dev.nva.aws.unit.no/publication/018bf22b3a94-35be3f58-6dfd-47cd-b1ed-de80224c2fca", + "setBy": "1136254@20754.0.0.0" + }, + "collaborationType": "NonCollaborative", + "type": "ImportCandidateSummary", + "publicationInstance": { + "volume": "13", + "issue": "1", + "articleNumber": "11686", + "type": "AcademicArticle" + }, + "associatedArtifacts": [ + { + "identifier": "0f7178fa-8f3d-4ed5-a240-f602095cc659", + "license": "https://creativecommons.org/licenses/by/4.0", + "rightsRetentionStrategy": { + "type": "NullRightsRetentionStrategy" + }, + "size": 3493842, + "publisherAuthority": false, + "name": "bbc76824-5752-45c9-8093-7d8468e24cfa.pdf", + "administrativeAgreement": false, + "mimeType": "application/pdf", + "publishedDate": "2023-11-20T15:44:06.742491250Z", + "type": "PublishedFile", + "visibleForNonOwner": true + } + ], + "journal": { + "id": "https://api.dev.nva.aws.unit.no/publication-channels-v2/journal/4CE88F3B-DEC2-4893-A1D0-A8186BF64290/2023", + "type": "Journal" + }, + "createdDate": "2023-11-20T15:44:04.623421255Z", + "totalVerifiedContributors": 1, + "mainTitle": "An in-depth characterisation of European seabass intestinal segments for assessing the impact of an algae-based functional diet on intestinal health", + "organizations": [ + { + "id": "https://api.dev.nva.aws.unit.no/customer/f94d1d3e-e05a-41f9-8eb8-f891ccd25666", + "type": "Organization", + "labels": { + "nb": "Nord universitet", + "en": "Nord University" + } + } + ], + "additionalIdentifiers": [ + { + "sourceName": "Scopus", + "type": "AdditionalIdentifier", + "value": "2-s2.0-85165328932" + } + ], + "publicationYear": "2023", + "id": "https://api.dev.nva.aws.unit.no/publication/import-candidate/018bed6738f1-e3867e28-c464-4785-b17e-5dc91050267e", + "contributors": [ + { + "sequence": 1, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Mariana Ferreira", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "type": "Organization", + "labels": { + "pt": "CIIMAR/CIMAR-LA, Centro Interdisciplinar de Investigação Marinha e Ambiental" + } + }, + { + "type": "Organization", + "labels": { + "pt": "ICBAS, Instituto de Ciências Biomédicas de Abel Salazar, Universidade Do Porto" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 2, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Vera Sousa", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "type": "Organization", + "labels": { + "pt": "CIIMAR/CIMAR-LA, Centro Interdisciplinar de Investigação Marinha e Ambiental" + } + }, + { + "type": "Organization", + "labels": { + "pt": "ICBAS, Instituto de Ciências Biomédicas de Abel Salazar, Universidade Do Porto" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 3, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Beatriz Oliveira", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "type": "Organization", + "labels": { + "pt": "CIIMAR/CIMAR-LA, Centro Interdisciplinar de Investigação Marinha e Ambiental" + } + }, + { + "type": "Organization", + "labels": { + "pt": "ICBAS, Instituto de Ciências Biomédicas de Abel Salazar, Universidade Do Porto" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 4, + "role": { + "type": "Creator" + }, + "identity": { + "name": "Ana Canadas-Sousa", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/13200151.0.0.0", + "type": "Organization", + "labels": { + "nb": "Universidade do Porto", + "en": "University of Porto" + } + }, + { + "type": "Organization", + "labels": { + "pt": "EUVG, Escola Universitária Vasco da Gama, Quinta de S. Jorge, Estrada da Conraria" + } + } + ], + "type": "Contributor" + }, + { + "sequence": 5, + "role": { + "type": "Creator" + }, + "identity": { + "name": "H. Abreu", + "type": "Identity" + }, + "correspondingAuthor": false, + "affiliations": [ + { + "type": "Organization", + "labels": { + "en": "ALGAplus, Production and Trading of Seaweed and Derived Products Ltd" + } + } + ], + "type": "Contributor" + } + ], + "doi": "https://doi.org/10.1038/s41598-023-38826-y", + "totalContributors": 8 + } +] \ No newline at end of file diff --git a/search-commons/src/test/resources/sample_resources_search.json b/search-commons/src/test/resources/sample_resources_search.json index 479e09866..ffacc2908 100644 --- a/search-commons/src/test/resources/sample_resources_search.json +++ b/search-commons/src/test/resources/sample_resources_search.json @@ -1,3392 +1,3712 @@ -[{ - "type": "Publication", - "publicationContextUris": ["https://api.dev.nva.aws.unit.no/publication-channels-v2/publisher/944351B3-DC14-4F62-9939-7A2793D6F0B1/2023"], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018ba3cfcb9c-94f77a1e-ac36-430a-84b0-0619ecbbaf39", - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "95ffa438-7367-49aa-ade7-5851daa6a8a3", - "license": "https://creativecommons.org/licenses/by/4.0", - "mimeType": "image/jpeg", - "name": "osteloff.jpg", - "publishedDate": "2023-11-06T08:48:11.786959336Z", - "publisherAuthority": false, - "size": 4656, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-11-06T08:46:26.204053625Z", - "entityDescription": { - "type": "EntityDescription", - "alternativeAbstracts": {}, - "contributors": [{ - "type": "Contributor", - "affiliations": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/45220004.0.0.0", +[ + { + "type": "Publication", + "publicationContextUris": [ + "https://api.dev.nva.aws.unit.no/publication-channels-v2/publisher/944351B3-DC14-4F62-9939-7A2793D6F0B1/2023" + ], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018ba3cfcb9c-94f77a1e-ac36-430a-84b0-0619ecbbaf39", + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "95ffa438-7367-49aa-ade7-5851daa6a8a3", + "license": "https://creativecommons.org/licenses/by/4.0", + "mimeType": "image/jpeg", + "name": "osteloff.jpg", + "publishedDate": "2023-11-06T08:48:11.786959336Z", + "publisherAuthority": false, + "size": 4656, + "visibleForNonOwner": true + } + ], + "createdDate": "2023-11-06T08:46:26.204053625Z", + "entityDescription": { + "type": "EntityDescription", + "alternativeAbstracts": {}, + "contributors": [ + { + "type": "Contributor", + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/45220004.0.0.0", + "type": "Organization", + "countryCode": "IQ", + "labels": { + "nn": "Al-Iraqia University", + "nb": "Al-Iraqia University", + "en": "Al-Iraqia University" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.6.0.0", + "type": "Organization", + "countryCode": "NO", + "labels": { + "nn": "Avdeling for kunde og kommunikasjon", + "nb": "Avdeling for kunde og kommunikasjon", + "en": "The Customer and Communication Department" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0", + "type": "Organization", + "countryCode": "NO", + "labels": { + "en": "Norwegian Defence University College", + "nb": "Forsvarets høgskole" + } + } + ], + "correspondingAuthor": false, + "identity": { + "id": "https://api.dev.nva.aws.unit.no/cristin/person/1136254", + "type": "Identity", + "name": "Kjetil Møkkelgjerd", + "orcId": "https://sandbox.orcid.org/0000-0003-4147-3499", + "verificationStatus": "Verified" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 + } + ], + "mainTitle": "Kjetils ticket test", + "publicationDate": { + "type": "PublicationDate", + "day": "6", + "month": "11", + "year": "2023" + }, + "reference": { + "type": "Reference", + "doi": "https://doi.org/10.1371/journal.pone.0047887", + "publicationContext": { + "type": "Report", + "isbnList": [ + "9788202535032" + ], + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/publication-channels-v2/publisher/944351B3-DC14-4F62-9939-7A2793D6F0B1/2023", + "type": "Publisher", + "isbnPrefix": "978-91-27", + "name": "Natur och kultur", + "sameAs": "https://kanalregister.hkdir.no/publiseringskanaler/KanalForlagInfo?pid=944351B3-DC14-4F62-9939-7A2793D6F0B1", + "scientificValue": "LevelOne", + "valid": true + }, + "series": { + "type": "UnconfirmedSeries" + } + }, + "publicationInstance": { + "type": "ReportResearch", + "pages": { + "type": "MonographPages", + "illustrated": false + } + } + } + }, + "identifier": "018ba3cfcb9c-94f77a1e-ac36-430a-84b0-0619ecbbaf39", + "modelVersion": "0.20.54", + "modifiedDate": "2023-11-06T08:48:11.943422687Z", + "nviType": "NonNviCandidate", + "publishedDate": "2023-11-06T08:48:11.936406187Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/bb3d0c0c-5065-4623-9b98-5810983c2478", + "type": "Organization" + }, + "resourceOwner": { + "owner": "1136254@20754.0.0.0", + "ownerAffiliation": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + }, + "status": "PUBLISHED", + "topLevelOrganizations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0", "type": "Organization", - "countryCode": "IQ", + "countryCode": "NO", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.1.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "UA", + "labels": { + "nn": "Divisjon for utdanning og administrasjon", + "nb": "Divisjon utdanning og administrasjon", + "en": "The Education and Administration Division" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.2.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FK", + "labels": { + "nn": "Divisjon for forskings- og kunnskapsressursar", + "nb": "Divisjon forsknings- og kunnskapsressurser", + "en": "The Research and Education Resources Division" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.4.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "ORG", + "labels": { + "nn": "Avdeling for organisasjonsutvikling", + "nb": "Avdeling for organisasjonsutvikling", + "en": "The Organisational Development Department" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.6.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "KUNDE", + "countryCode": "NO", + "labels": { + "nn": "Avdeling for kunde og kommunikasjon", + "nb": "Avdeling for kunde og kommunikasjon", + "en": "The Customer and Communication Department" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.5.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VIRK", + "labels": { + "nn": "Avdeling for verksemdstyring", + "nb": "Avdeling for virksomhetsstyring", + "en": "The Corporate Governance Department" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.3.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "DI", + "labels": { + "nn": "Divisjon for data og infrastruktur", + "nb": "Divisjon data og infrastruktur", + "en": "The Organisational Development Department" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + } + } + ], "labels": { - "nn": "Al-Iraqia University", - "nb": "Al-Iraqia University", - "en": "Al-Iraqia University" + "nb": "Sikt – Kunnskapssektorens tjenesteleverandør", + "en": "Sikt - Norwegian Agency for Shared Services in Education and Research" } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.6.0.0", + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/45220004.0.0.0", "type": "Organization", - "countryCode": "NO", + "countryCode": "IQ", "labels": { - "nn": "Avdeling for kunde og kommunikasjon", - "nb": "Avdeling for kunde og kommunikasjon", - "en": "The Customer and Communication Department" + "nb": "Al-Iraqia Universitet", + "nn": "Universitet i Irak", + "en": "Al-Iraqia University" } - }, { + }, + { "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0", "type": "Organization", "countryCode": "NO", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.4.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "KS", + "labels": { + "nb": "Krigsskolen (KS)" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.7.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IFF", + "labels": { + "nb": "Institutt for forsvarsstudier" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.5.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FIH", + "labels": { + "nb": "Cyberingeniørskolen" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.2.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "LKSK", + "labels": { + "nb": "Luftkrigsskolen (LKSK)" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.8.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FSK", + "labels": { + "nb": "Institutt for militær ledelse og operasjoner" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.9.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "BEFAL", + "labels": { + "nb": "Befalsskolen", + "en": "Officer Candidate School" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.3.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SKSK", + "labels": { + "nb": "Sjøkrigsskolen (SKSK)" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + } + ], "labels": { - "en": "Norwegian Defence University College", - "nb": "Forsvarets høgskole" + "nb": "Forsvarets høgskole", + "en": "Norwegian Defence University College" } } - ], - "correspondingAuthor": false, - "identity": { - "id": "https://api.dev.nva.aws.unit.no/cristin/person/1136254", - "type": "Identity", - "name": "Kjetil Møkkelgjerd", - "orcId": "https://sandbox.orcid.org/0000-0003-4147-3499", - "verificationStatus": "Verified" - }, - "role": { - "type": "Creator" - }, - "sequence": 1 - } + ] + }, + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b857b77b7-697ebc73-5195-4ce4-9ba1-1d5a7b540642", + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "98893bfd-82d3-44d8-af10-9d1097c9510e", + "license": "https://rightsstatements.org/page/inc/1.0", + "mimeType": "application/pdf", + "name": "20200017-03-TN_Release_area_variability.pdf", + "publishedDate": "2023-10-31T11:25:43.223366513Z", + "publisherAuthority": false, + "size": 699309, + "visibleForNonOwner": false + } ], - "mainTitle": "Kjetils ticket test", - "publicationDate": { - "type": "PublicationDate", - "day": "6", - "month": "11", - "year": "2023" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "Report", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/publication-channels-v2/publisher/944351B3-DC14-4F62-9939-7A2793D6F0B1/2023", - "type": "Publisher", - "isbnPrefix": "978-91-27", - "name": "Natur och kultur", - "sameAs": "https://kanalregister.hkdir.no/publiseringskanaler/KanalForlagInfo?pid=944351B3-DC14-4F62-9939-7A2793D6F0B1", - "scientificValue": "LevelOne", - "valid": true - }, - "series": { - "type": "UnconfirmedSeries" + "createdDate": "2023-09-29T12:14:46Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "The hazard mapping tool NAKSIN estimates the release probability of potential release areas (PRAs) by testing a stability criterion based on the infinite-slope approximation with a large sample of synthetic weather situations. The release area is thus assumed to comprise the entire PRA, which is unrealistic for avalanches with return periods shorter than 100–300 y. To remedy this, a stability criterion is proposed that accounts for stabilizing forces across the slab perimeter and so is sensitive to the slab extent. The criterion is applied to a sequence of subareas of the PRA with increasing minimum slope angle to find the subarea with maximum release probability. The method is described and formulated mathematically. Also, tools for coding it are suggested but implementation in NAKSIN and testing are left for future work.", + "alternativeAbstracts": {}, + "contributors": [ + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Dieter Issler" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 } - }, - "publicationInstance": { - "type": "ReportResearch", - "pages": { - "type": "MonographPages", - "illustrated": false + ], + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "A Simple Model for the Variability of Release Area Size", + "publicationDate": { + "type": "PublicationDate", + "day": "24", + "month": "08", + "year": "2023" + }, + "reference": { + "type": "Reference", + "doi": "https://doi.org/10.1371/journal.pone.0047855", + "publicationContext": { + "type": "Report", + "publisher": { + "type": "UnconfirmedPublisher", + "name": "NGI – Norges Geotekniske institutt", + "valid": true + }, + "series": { + "type": "UnconfirmedSeries", + "title": "NGI-Rapport" + }, + "seriesNumber": "20200017‐03‐TN" + }, + "publicationInstance": { + "type": "ReportResearch", + "pages": { + "type": "MonographPages", + "illustrated": false, + "pages": "16" + } } - } - } - }, - "identifier": "018ba3cfcb9c-94f77a1e-ac36-430a-84b0-0619ecbbaf39", - "modelVersion": "0.20.54", - "modifiedDate": "2023-11-06T08:48:11.943422687Z", - "nviType": "NonNviCandidate", - "publishedDate": "2023-11-06T08:48:11.936406187Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/bb3d0c0c-5065-4623-9b98-5810983c2478", - "type": "Organization" - }, - "resourceOwner": { - "owner": "1136254@20754.0.0.0", - "ownerAffiliation": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - }, - "status": "PUBLISHED", - "topLevelOrganizations": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0", - "type": "Organization", - "countryCode": "NO", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.1.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "UA", - "labels": { - "nn": "Divisjon for utdanning og administrasjon", - "nb": "Divisjon utdanning og administrasjon", - "en": "The Education and Administration Division" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.2.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FK", - "labels": { - "nn": "Divisjon for forskings- og kunnskapsressursar", - "nb": "Divisjon forsknings- og kunnskapsressurser", - "en": "The Research and Education Resources Division" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.4.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "ORG", - "labels": { - "nn": "Avdeling for organisasjonsutvikling", - "nb": "Avdeling for organisasjonsutvikling", - "en": "The Organisational Development Department" }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.6.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "KUNDE", - "countryCode": "NO", - "labels": { - "nn": "Avdeling for kunde og kommunikasjon", - "nb": "Avdeling for kunde og kommunikasjon", - "en": "The Customer and Communication Department" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.5.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VIRK", - "labels": { - "nn": "Avdeling for verksemdstyring", - "nb": "Avdeling for virksomhetsstyring", - "en": "The Corporate Governance Department" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.3.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "DI", - "labels": { - "nn": "Divisjon for data og infrastruktur", - "nb": "Divisjon data og infrastruktur", - "en": "The Organisational Development Department" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + "tags": [ + "Avalanche-RnD", + "Slope Stability", + "Snøskred-FoU", + "NAKSIN", + "Release probability", + "Avalanche release", + "Release area size", + "Snow avalanches" + ] + }, + "handle": "https://hdl.handle.net/11250/3093139", + "identifier": "018b857b77b7-697ebc73-5195-4ce4-9ba1-1d5a7b540642", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T12:14:46Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", + "type": "Organization" + }, + "resourceOwner": { + "owner": "ngi@7452.0.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + }, + "status": "PUBLISHED" + }, + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b8581b2d1-b46eec8b-01c0-409f-b609-1f1f3ad6fa4a", + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": true, + "identifier": "82c86bd2-f6d1-408f-b315-19e6258e3fd9", + "license": "https://rightsstatements.org/page/inc/1.0", + "mimeType": "application/pdf", + "name": "20200017-10-TN_Outline_PSA_model.pdf", + "publishedDate": "2023-10-31T11:32:31.569492596Z", + "publisherAuthority": false, + "size": 605173, + "visibleForNonOwner": true } - } ], - "labels": { - "nb": "Sikt – Kunnskapssektorens tjenesteleverandør", - "en": "Sikt - Norwegian Agency for Shared Services in Education and Research" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/45220004.0.0.0", - "type": "Organization", - "countryCode": "IQ", - "labels": { - "nn": "Al-Iraqia University", - "nb": "Al-Iraqia University", - "en": "Al-Iraqia University" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0", - "type": "Organization", - "countryCode": "NO", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.4.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "KS", - "labels": { - "nb": "Krigsskolen (KS)" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.7.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IFF", - "labels": { - "nb": "Institutt for forsvarsstudier" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.5.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FIH", - "labels": { - "nb": "Cyberingeniørskolen" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.2.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "LKSK", - "labels": { - "nb": "Luftkrigsskolen (LKSK)" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.8.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FSK", - "labels": { - "nb": "Institutt for militær ledelse og operasjoner" + "createdDate": "2023-09-29T12:11:12Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "This Note discusses a quasi-three-dimensional model of mixed snow avalanches that could replace the code MoT-Voellmy in NAKSIN. As a starting point, the two-layer model by Eglit is slightly simplified and extended from a profile line to a general topography in three-dimensional space. Possible modifications of the closures proposed by Eglit are discussed. For rapid development, it is suggested to base the new code either on MoT-Voellmy or possibly on the code development system ExaHyPE.", + "alternativeAbstracts": {}, + "contributors": [ + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Dieter Issler" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 + } + ], + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Outline of a Simple Model of Mixed Snow Avalanches", + "publicationDate": { + "type": "PublicationDate", + "day": "24", + "month": "08", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "Report", + "publisher": { + "type": "UnconfirmedPublisher", + "name": "NGI – Norges Geotekniske institutt", + "valid": true + }, + "series": { + "type": "UnconfirmedSeries", + "title": "NGI-Rapport" + }, + "seriesNumber": "20200017‐10‐TN" + }, + "publicationInstance": { + "type": "ReportResearch", + "pages": { + "type": "MonographPages", + "illustrated": false, + "pages": "19" + } + } }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + "tags": [ + "Snow avalanches", + "Numerical Modeling", + "Avalanche-RnD", + "Entrainment functions", + "Mixed snow avalanches", + "Eglit model", + "Snøskred-FoU" + ] + }, + "handle": "https://hdl.handle.net/11250/3093134", + "identifier": "018b8581b2d1-b46eec8b-01c0-409f-b609-1f1f3ad6fa4a", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T12:11:12Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", + "type": "Organization" + }, + "resourceOwner": { + "owner": "ngi@7452.0.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + }, + "status": "PUBLISHED" + }, + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b8579f0ad-db0bd29b-ad7c-4068-afa3-f300a1af61ef", + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "679555f3-8cae-40e2-bd95-80eb56fc8adb", + "license": "https://rightsstatements.org/page/inc/1.0", + "mimeType": "application/pdf", + "name": "20200431-01-TN.APALI_concept.pdf", + "publishedDate": "2023-10-31T11:24:03.117194851Z", + "publisherAuthority": false, + "size": 519969, + "visibleForNonOwner": true } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.9.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "BEFAL", - "labels": { - "nb": "Befalsskolen", - "en": "Officer Candidate School" + ], + "createdDate": "2023-09-29T12:07:34Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "To secure linear infrastructure in the most cost-efficient manner, hazard hot-spots need to be known not only with regard to the intensity of possible events but also their probability. Traditional hazard mapping methods rely on analysis of historical records—which are often missing or scarce—or on experts’ subjective judgment. Either approach is timeconsuming and expensive. The hazard mapping system NAKSIN for snow avalanches contains a module for estimating avalanche release probability automatically using topographical, weather and forest data and calculates avalanche run-out for one target return period. This Note outlines how NAKSIN can be modified to produce maps of avalanche hit probability and optionally probability distribution functions of impact pressure and/or flow velocity. While the needed modifications are easy to implement, the NAKSIN module for release probability requires improvements to produce more reliable estimates in areas with continental climate.", + "alternativeAbstracts": {}, + "contributors": [ + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Dieter Issler" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 + } + ], + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "APALI – Avalanche Probability Along Linear Infrastructure", + "publicationDate": { + "type": "PublicationDate", + "day": "28", + "month": "09", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "Report", + "publisher": { + "type": "UnconfirmedPublisher", + "name": "NGI – Norges Geotekniske institutt", + "valid": true + }, + "series": { + "type": "UnconfirmedSeries", + "title": "NGI-Rapport" + }, + "seriesNumber": "20200431‐01‐TN" + }, + "publicationInstance": { + "type": "ReportResearch", + "pages": { + "type": "MonographPages", + "illustrated": false, + "pages": "12" + } + } }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + "tags": [ + "Avalanche-RnD", + "Snøskred-FoU" + ] + }, + "handle": "https://hdl.handle.net/11250/3093129", + "identifier": "018b8579f0ad-db0bd29b-ad7c-4068-afa3-f300a1af61ef", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T12:07:34Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", + "type": "Organization" + }, + "resourceOwner": { + "owner": "ngi@7452.0.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + }, + "status": "PUBLISHED" + }, + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b858395d7-02aaf128-dc44-457e-b471-675a952e8cff", + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "d42613f9-c721-4368-a346-c1886c5073c6", + "license": "https://rightsstatements.org/page/inc/1.0", + "mimeType": "application/pdf", + "name": "20200017-02-R.pdf", + "publishedDate": "2023-10-31T11:34:35.223834762Z", + "publisherAuthority": false, + "size": 3325931, + "visibleForNonOwner": true } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.3.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SKSK", - "labels": { - "nb": "Sjøkrigsskolen (SKSK)" + ], + "createdDate": "2023-09-29T12:04:08Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "During the first year of the project period 2020-2022 of NGIs research project on Snow avalanches, Applied Avalanche Research in Norway (AARN), work was conducted in all three work packages (WP 1 – Avalanche formation and release, WP 2 – Avalanche dynamics, WP 3 – Avalanche interaction) and several cross-package topics. In addition, several significant upgrades were made to the research infrastructure at Fonnbu and Ryggfonn. During 2020, the results of the research activities have been published in peer-reviewed journals, summarised in technical notes, and presented online at national and international conferences and seminars. AARN personnel have been actively engaged in educational outreach activities, including as lecturers and student supervisors.", + "alternativeAbstracts": {}, + "contributors": [ + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Kate Robinson" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Zhongqiang Liu" + }, + "role": { + "type": "Creator" + }, + "sequence": 2 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Dieter Issler" + }, + "role": { + "type": "Creator" + }, + "sequence": 3 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Ulrik Domaas" + }, + "role": { + "type": "Creator" + }, + "sequence": 4 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Christian Jaedicke" + }, + "role": { + "type": "Creator" + }, + "sequence": 5 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Sean Salazar" + }, + "role": { + "type": "Creator" + }, + "sequence": 6 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Regula Frauenfelder" + }, + "role": { + "type": "Creator" + }, + "sequence": 7 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Graham Gilbert" + }, + "role": { + "type": "Creator" + }, + "sequence": 8 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Peter Gauer" + }, + "role": { + "type": "Creator" + }, + "sequence": 9 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Henrik Langeland" + }, + "role": { + "type": "Creator" + }, + "sequence": 10 + } + ], + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Annual Report 2020", + "publicationDate": { + "type": "PublicationDate", + "day": "19", + "month": "03", + "year": "2021" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "Report", + "publisher": { + "type": "UnconfirmedPublisher", + "name": "NGI – Norges Geotekniske institutt", + "valid": true + }, + "series": { + "type": "UnconfirmedSeries", + "title": "NGI-Rapport" + }, + "seriesNumber": "20200017-02-R" + }, + "publicationInstance": { + "type": "ReportResearch", + "pages": { + "type": "MonographPages", + "illustrated": false, + "pages": "26" + } + } }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + "tags": [ + "Avalanche-RnD", + "Snøskred-FoU" + ] + }, + "handle": "https://hdl.handle.net/11250/3093125", + "identifier": "018b858395d7-02aaf128-dc44-457e-b471-675a952e8cff", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T12:04:08Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", + "type": "Organization" + }, + "resourceOwner": { + "owner": "ngi@7452.0.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + }, + "status": "PUBLISHED" + }, + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b857af565-f63a53df-6c4f-4051-8686-8547f45ef726", + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "ae0539fe-0d67-4854-80bc-b2e906b55ee1", + "license": "https://rightsstatements.org/page/inc/1.0", + "mimeType": "application/pdf", + "name": "20200017-03-R.pdf", + "publishedDate": "2023-10-31T11:25:09.861695292Z", + "publisherAuthority": false, + "size": 5659255, + "visibleForNonOwner": true } - } ], - "labels": { - "en": "Norwegian Defence University College", - "nb": "Forsvarets høgskole" - } - } - ] -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b857b77b7-697ebc73-5195-4ce4-9ba1-1d5a7b540642", - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "98893bfd-82d3-44d8-af10-9d1097c9510e", - "license": "https://rightsstatements.org/page/inc/1.0", - "mimeType": "application/pdf", - "name": "20200017-03-TN_Release_area_variability.pdf", - "publishedDate": "2023-10-31T11:25:43.223366513Z", - "publisherAuthority": false, - "size": 699309, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T12:14:46Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "The hazard mapping tool NAKSIN estimates the release probability of potential release areas (PRAs) by testing a stability criterion based on the infinite-slope approximation with a large sample of synthetic weather situations. The release area is thus assumed to comprise the entire PRA, which is unrealistic for avalanches with return periods shorter than 100–300 y. To remedy this, a stability criterion is proposed that accounts for stabilizing forces across the slab perimeter and so is sensitive to the slab extent. The criterion is applied to a sequence of subareas of the PRA with increasing minimum slope angle to find the subarea with maximum release probability. The method is described and formulated mathematically. Also, tools for coding it are suggested but implementation in NAKSIN and testing are left for future work.", - "alternativeAbstracts": {}, - "contributors": [{ - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Dieter Issler" - }, - "role": { - "type": "Creator" + "createdDate": "2023-09-29T12:00:47Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "During the second year of the project period 2020-2022 of NGIs research project on snow avalanches, Applied Avalanche Research in Norway (AARN), work was conducted in all three work packages (WP 1 – Avalanche formation and release, WP 2 – Avalanche dynamics, WP 3 – Avalanche interaction) and several cross-package topics. The successful avalanche experiment in April 2021 has given us valuable insight into the dynamics of a large avalanche event and showed that the Ryggfonn test site produces the avalanches that are needed for the AARN research. During 2021, the results of the research activities have been published in peer-reviewed journals, summarised in technical notes, and presented online at national and international conferences and seminars. AARN personnel have been actively engaged in educational outreach activities, including as lecturers and student supervisors.", + "alternativeAbstracts": {}, + "contributors": [ + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Christian Jaedicke" + }, + "role": { + "type": "Creator" + }, + "sequence": 4 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Sean Salazar" + }, + "role": { + "type": "Creator" + }, + "sequence": 5 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Dieter Issler" + }, + "role": { + "type": "Creator" + }, + "sequence": 3 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Regula Frauenfelder" + }, + "role": { + "type": "Creator" + }, + "sequence": 6 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Peter Gauer" + }, + "role": { + "type": "Creator" + }, + "sequence": 8 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Kate Robinson" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Zhongqiang Liu" + }, + "role": { + "type": "Creator" + }, + "sequence": 2 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Graham Gilbert" + }, + "role": { + "type": "Creator" + }, + "sequence": 7 + } + ], + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Annual Report 2021", + "publicationDate": { + "type": "PublicationDate", + "day": "08", + "month": "04", + "year": "2022" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "Report", + "publisher": { + "type": "UnconfirmedPublisher", + "name": "NGI – Norges Geotekniske institutt", + "valid": true + }, + "series": { + "type": "UnconfirmedSeries", + "title": "NGI-Rapport" + }, + "seriesNumber": "20200017-03-R" + }, + "publicationInstance": { + "type": "ReportResearch", + "pages": { + "type": "MonographPages", + "illustrated": false, + "pages": "38" + } + } }, - "sequence": 1 - } - ], - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "A Simple Model for the Variability of Release Area Size", - "publicationDate": { - "type": "PublicationDate", - "day": "24", - "month": "08", - "year": "2023" + "tags": [ + "Avalanche-RnD", + "Snøskred-FoU" + ] }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "Report", - "publisher": { - "type": "UnconfirmedPublisher", - "name": "NGI – Norges Geotekniske institutt", - "valid": true - }, - "series": { - "type": "UnconfirmedSeries", - "title": "NGI-Rapport" - }, - "seriesNumber": "20200017‐03‐TN" - }, - "publicationInstance": { - "type": "ReportResearch", - "pages": { - "type": "MonographPages", - "illustrated": false, - "pages": "16" - } - } + "handle": "https://hdl.handle.net/11250/3093123", + "identifier": "018b857af565-f63a53df-6c4f-4051-8686-8547f45ef726", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T12:00:47Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", + "type": "Organization" }, - "tags": ["Avalanche-RnD", "Slope Stability", "Snøskred-FoU", "NAKSIN", "Release probability", "Avalanche release", "Release area size", "Snow avalanches"] - }, - "handle": "https://hdl.handle.net/11250/3093139", - "identifier": "018b857b77b7-697ebc73-5195-4ce4-9ba1-1d5a7b540642", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T12:14:46Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", - "type": "Organization" - }, - "resourceOwner": { - "owner": "ngi@7452.0.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + "resourceOwner": { + "owner": "ngi@7452.0.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + }, + "status": "PUBLISHED" }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b8581b2d1-b46eec8b-01c0-409f-b609-1f1f3ad6fa4a", - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "82c86bd2-f6d1-408f-b315-19e6258e3fd9", - "license": "https://rightsstatements.org/page/inc/1.0", - "mimeType": "application/pdf", - "name": "20200017-10-TN_Outline_PSA_model.pdf", - "publishedDate": "2023-10-31T11:32:31.569492596Z", - "publisherAuthority": false, - "size": 605173, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T12:11:12Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "This Note discusses a quasi-three-dimensional model of mixed snow avalanches that could replace the code MoT-Voellmy in NAKSIN. As a starting point, the two-layer model by Eglit is slightly simplified and extended from a profile line to a general topography in three-dimensional space. Possible modifications of the closures proposed by Eglit are discussed. For rapid development, it is suggested to base the new code either on MoT-Voellmy or possibly on the code development system ExaHyPE.", - "alternativeAbstracts": {}, - "contributors": [{ - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Dieter Issler" - }, - "role": { - "type": "Creator" - }, - "sequence": 1 - } + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b8579ef63-3985cba8-f6e8-4038-8282-e7ffb88c6c27", + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "b4cb1f7c-9f93-486f-b963-bce60da36002", + "license": "https://rightsstatements.org/page/inc/1.0", + "mimeType": "application/pdf", + "name": "20200017-04-TN.pdf", + "publishedDate": "2023-10-31T11:24:02.787013542Z", + "publisherAuthority": false, + "size": 3514827, + "visibleForNonOwner": true + } ], - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Outline of a Simple Model of Mixed Snow Avalanches", - "publicationDate": { - "type": "PublicationDate", - "day": "24", - "month": "08", - "year": "2023" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "Report", - "publisher": { - "type": "UnconfirmedPublisher", - "name": "NGI – Norges Geotekniske institutt", - "valid": true - }, - "series": { - "type": "UnconfirmedSeries", - "title": "NGI-Rapport" - }, - "seriesNumber": "20200017‐10‐TN" - }, - "publicationInstance": { - "type": "ReportResearch", - "pages": { - "type": "MonographPages", - "illustrated": false, - "pages": "19" + "createdDate": "2023-09-29T11:57:21Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "Hazard assessment for landuse planning in snow avalanche prone areas requires, besides knowledge of return periods, the specification of expected runout distances. For a complete risk assessment, additionally, the intensity of the event, often expressed in terms of impact pressures, and the corresponding vulnerability of endangered objects are needed.To obtain dynamical parameters, such as velocity, it has become state of practice to use 2-dimensional depth integrated avalanche models like RAMMS (Christen et al. 2010)or SAMOS-AT (Sampl and Granig, 2009). However, those models still lack a thorough and documented validation - which is partly caused by the lack of sufficient avalanchedata - and therefore, it requires extensive experience from practitioners to assess the model results. Mainly, the models are calibrated based on runout observation, however runout observations provide limited constraints for the validation of the empirical parameters used in common present-day numerical avalanche models. On the other hand side, observations of runout distances combined with velocity meas urements suggest that \"major'' dry-mixed avalanches show a scale invariance to the total drop height HSC. This is in accordance to the proposed upper-limit envelope of the maximum velocity by McClung and Schaerer (2003) and a simple scaling analysis using a simple mass block model on cycloidal and parabolic tracks (Gauer, 2018). Therefore, those combined observations give a much more stringent constrain for the parameter choice.", + "alternativeAbstracts": {}, + "contributors": [ + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Annicken Helene Aalerud" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Nellie Sofie Body" + }, + "role": { + "type": "Creator" + }, + "sequence": 2 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Peter Gauer" + }, + "role": { + "type": "Creator" + }, + "sequence": 3 } - } + ], + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Avalanche observations versus numerical avalanche model: Simple test of model performance", + "publicationDate": { + "type": "PublicationDate", + "day": "22", + "month": "03", + "year": "2021" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "Report", + "publisher": { + "type": "UnconfirmedPublisher", + "name": "NGI – Norges Geotekniske institutt", + "valid": true + }, + "series": { + "type": "UnconfirmedSeries", + "title": "NGI-Rapport" + }, + "seriesNumber": "20200017-04-TN" + }, + "publicationInstance": { + "type": "ReportResearch", + "pages": { + "type": "MonographPages", + "illustrated": false, + "pages": "21" + } + } + }, + "tags": [ + "Norwegian avalanche grant", + "Snøskred-FoU", + "Avalanche-RnD" + ] }, - "tags": ["Snow avalanches", "Numerical Modeling", "Avalanche-RnD", "Entrainment functions", "Mixed snow avalanches", "Eglit model", "Snøskred-FoU"] - }, - "handle": "https://hdl.handle.net/11250/3093134", - "identifier": "018b8581b2d1-b46eec8b-01c0-409f-b609-1f1f3ad6fa4a", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T12:11:12Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", - "type": "Organization" - }, - "resourceOwner": { - "owner": "ngi@7452.0.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + "handle": "https://hdl.handle.net/11250/3093120", + "identifier": "018b8579ef63-3985cba8-f6e8-4038-8282-e7ffb88c6c27", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T11:57:21Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", + "type": "Organization" + }, + "resourceOwner": { + "owner": "ngi@7452.0.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + }, + "status": "PUBLISHED" }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b8579f0ad-db0bd29b-ad7c-4068-afa3-f300a1af61ef", - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "679555f3-8cae-40e2-bd95-80eb56fc8adb", - "license": "https://rightsstatements.org/page/inc/1.0", - "mimeType": "application/pdf", - "name": "20200431-01-TN.APALI_concept.pdf", - "publishedDate": "2023-10-31T11:24:03.117194851Z", - "publisherAuthority": false, - "size": 519969, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T12:07:34Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "To secure linear infrastructure in the most cost-efficient manner, hazard hot-spots need to be known not only with regard to the intensity of possible events but also their probability. Traditional hazard mapping methods rely on analysis of historical records—which are often missing or scarce—or on experts’ subjective judgment. Either approach is timeconsuming and expensive. The hazard mapping system NAKSIN for snow avalanches contains a module for estimating avalanche release probability automatically using topographical, weather and forest data and calculates avalanche run-out for one target return period. This Note outlines how NAKSIN can be modified to produce maps of avalanche hit probability and optionally probability distribution functions of impact pressure and/or flow velocity. While the needed modifications are easy to implement, the NAKSIN module for release probability requires improvements to produce more reliable estimates in areas with continental climate.", - "alternativeAbstracts": {}, - "contributors": [{ - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Dieter Issler" - }, - "role": { - "type": "Creator" - }, - "sequence": 1 - } + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b857a85ae-110bf68d-c0f7-42b5-b635-b154ed6208dd", + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "1a3203fc-3d7d-4e21-8fab-fc2d58dfc878", + "license": "https://rightsstatements.org/page/inc/1.0", + "mimeType": "application/pdf", + "name": "20200017-09-TN.pdf", + "publishedDate": "2023-10-31T11:24:41.262439430Z", + "publisherAuthority": false, + "size": 2355368, + "visibleForNonOwner": true + } ], - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "APALI – Avalanche Probability Along Linear Infrastructure", - "publicationDate": { - "type": "PublicationDate", - "day": "28", - "month": "09", - "year": "2023" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "Report", - "publisher": { - "type": "UnconfirmedPublisher", - "name": "NGI – Norges Geotekniske institutt", - "valid": true - }, - "series": { - "type": "UnconfirmedSeries", - "title": "NGI-Rapport" - }, - "seriesNumber": "20200431‐01‐TN" - }, - "publicationInstance": { - "type": "ReportResearch", - "pages": { - "type": "MonographPages", - "illustrated": false, - "pages": "12" + "createdDate": "2023-09-29T11:53:36Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "The Norwegian building code regulates the societal acceptable risk from avalanches for three building classes (S1, S1, and S3). The corresponding highest allowed nominal annual probabilities of avalanches reaching the building for these classes are set as 1/100, 1/1000 and 1/5000 respectively (TEK17, 2017). That is, avalanches should not reach a building, or the accompanying outdoor area and cause (considerable) damage more often than the building class permits. These hazard classes are used for delineation of avalanche hazard zones for land use planning (TEK17, 2017). For the assessment of the quantitative risk of avalanches reaching existing settlements only limited methods are available. Thus, historical observations can be of special importance, as they may be direct indicators for the real hazard in the area of interest. To a certain degree, they can also provide an indication of a possible change of hazard over time due to environmental changes. However, historical observations are affected by inherent uncertainties and many questions remain open. Here, we aim to combine results from several work packages to develop a more consistent method of using historical observations that may help improve quantitative hazard assessments and evaluation of the uncertainties involved.", + "alternativeAbstracts": {}, + "contributors": [ + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Peter Gauer" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 } - } + ], + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "CPT 3 – Quantitative risk assessment: Remarks on the uncertainty in the delimitation of hazard zones based on historical observations", + "publicationDate": { + "type": "PublicationDate", + "day": "22", + "month": "03", + "year": "2022" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "Report", + "publisher": { + "type": "UnconfirmedPublisher", + "name": "NGI – Norges Geotekniske institutt", + "valid": true + }, + "series": { + "type": "UnconfirmedSeries", + "title": "NGI-Rapport" + }, + "seriesNumber": "20200017-09-TN" + }, + "publicationInstance": { + "type": "ReportResearch", + "pages": { + "type": "MonographPages", + "illustrated": false, + "pages": "18" + } + } + }, + "tags": [ + "Runout Distances", + "Snow avalanches", + "Avalanche-RnD", + "Norwegian avalanche grant", + "Hazard maps", + "Uncertainty", + "Frequency", + "Snøskred-FoU", + "Return Period" + ] }, - "tags": ["Avalanche-RnD", "Snøskred-FoU"] - }, - "handle": "https://hdl.handle.net/11250/3093129", - "identifier": "018b8579f0ad-db0bd29b-ad7c-4068-afa3-f300a1af61ef", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T12:07:34Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", - "type": "Organization" - }, - "resourceOwner": { - "owner": "ngi@7452.0.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + "handle": "https://hdl.handle.net/11250/3093118", + "identifier": "018b857a85ae-110bf68d-c0f7-42b5-b635-b154ed6208dd", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T11:53:36Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", + "type": "Organization" + }, + "resourceOwner": { + "owner": "ngi@7452.0.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + }, + "status": "PUBLISHED" }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b858395d7-02aaf128-dc44-457e-b471-675a952e8cff", - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "d42613f9-c721-4368-a346-c1886c5073c6", - "license": "https://rightsstatements.org/page/inc/1.0", - "mimeType": "application/pdf", - "name": "20200017-02-R.pdf", - "publishedDate": "2023-10-31T11:34:35.223834762Z", - "publisherAuthority": false, - "size": 3325931, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T12:04:08Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "During the first year of the project period 2020-2022 of NGIs research project on Snow avalanches, Applied Avalanche Research in Norway (AARN), work was conducted in all three work packages (WP 1 – Avalanche formation and release, WP 2 – Avalanche dynamics, WP 3 – Avalanche interaction) and several cross-package topics. In addition, several significant upgrades were made to the research infrastructure at Fonnbu and Ryggfonn. During 2020, the results of the research activities have been published in peer-reviewed journals, summarised in technical notes, and presented online at national and international conferences and seminars. AARN personnel have been actively engaged in educational outreach activities, including as lecturers and student supervisors.", - "alternativeAbstracts": {}, - "contributors": [{ - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Regula Frauenfelder" - }, - "role": { - "type": "Creator" - }, - "sequence": 7 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Henrik Langeland" - }, - "role": { - "type": "Creator" - }, - "sequence": 10 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Sean Salazar" - }, - "role": { - "type": "Creator" - }, - "sequence": 6 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Ulrik Domaas" - }, - "role": { - "type": "Creator" - }, - "sequence": 4 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Christian Jaedicke" - }, - "role": { - "type": "Creator" - }, - "sequence": 5 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Peter Gauer" - }, - "role": { - "type": "Creator" - }, - "sequence": 9 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Kate Robinson" - }, - "role": { - "type": "Creator" - }, - "sequence": 1 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Zhongqiang Liu" - }, - "role": { - "type": "Creator" - }, - "sequence": 2 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Dieter Issler" - }, - "role": { - "type": "Creator" - }, - "sequence": 3 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Graham Gilbert" - }, - "role": { - "type": "Creator" - }, - "sequence": 8 - } + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b857b89d9-b5053ac9-fe14-4ea9-9922-8130b306b720", + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "197afe52-704e-4b56-b3e1-ff6e0fc6b73e", + "license": "https://rightsstatements.org/page/inc/1.0", + "mimeType": "application/pdf", + "name": "20200017-01-R.pdf", + "publishedDate": "2023-10-31T11:25:47.865702950Z", + "publisherAuthority": false, + "size": 1234363, + "visibleForNonOwner": true + } ], - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Annual Report 2020", - "publicationDate": { - "type": "PublicationDate", - "day": "19", - "month": "03", - "year": "2021" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "Report", - "publisher": { - "type": "UnconfirmedPublisher", - "name": "NGI – Norges Geotekniske institutt", - "valid": true - }, - "series": { - "type": "UnconfirmedSeries", - "title": "NGI-Rapport" - }, - "seriesNumber": "20200017-02-R" - }, - "publicationInstance": { - "type": "ReportResearch", - "pages": { - "type": "MonographPages", - "illustrated": false, - "pages": "26" + "createdDate": "2023-09-29T11:49:09Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "Snow avalanches are a significant natural hazard and common phenomenon in Norway. Each year, avalanches result in fatalities, evacuations, and interruptions or damage to infrastructure networks such as roads, railways, and electrical transmission lines. Persistent avalanche hazard in steep terrain is a major factor considered during land-use planning and development. During the snow season, daily or weekly variations in the avalanche danger identified in regional and applied bulletins influence the operation of transportation networks. Applied research on avalanches and their societal impacts has been conducted at the Norwegian Geotechnical Institute (NGI) since 1973. This research has been funded in part by an annual grant from the Norwegian parliament, administered by the Norwegian Water Resources and Energy Directorate (NVE – Norges vassdrags- og energi-direktorat). Recent research activities have improved our understanding of avalanche formation, movement, and impacts. Enhanced knowledge of the individual processes leading to avalanche initiation, avalanche dynamics, and avalanche impacts has been applied to developing tools to help predict avalanche occurrence, runout distance, and impact pressures. While much has been accomplished within the avalanche research community in recent years, many key questions remain. This project plan: (1) presents the research goals for the 2020-2022 period, (2) outlines the projects organization – including potential for external collaboration, and (3) presents the work-package structure and specific research tasks to be undertaken by the applied avalanche research group at NGI over the next three years.", + "alternativeAbstracts": {}, + "contributors": [ + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Regula Frauenfelder" + }, + "role": { + "type": "Creator" + }, + "sequence": 5 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Kjersti Gisnås" + }, + "role": { + "type": "Creator" + }, + "sequence": 3 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Peter Gauer" + }, + "role": { + "type": "Creator" + }, + "sequence": 6 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Dieter Issler" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Christian Jaedicke" + }, + "role": { + "type": "Creator" + }, + "sequence": 2 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Sean Salazar" + }, + "role": { + "type": "Creator" + }, + "sequence": 4 } - } + ], + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Research Plan 2020–2022", + "publicationDate": { + "type": "PublicationDate", + "day": "23", + "month": "04", + "year": "2020" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "Report", + "publisher": { + "type": "UnconfirmedPublisher", + "name": "NGI – Norges Geotekniske institutt", + "valid": true + }, + "series": { + "type": "UnconfirmedSeries", + "title": "NGI-Rapport" + }, + "seriesNumber": "20200017-01-R" + }, + "publicationInstance": { + "type": "ReportResearch", + "pages": { + "type": "MonographPages", + "illustrated": false, + "pages": "25" + } + } + }, + "tags": [ + "Research plan", + "Snow avalanches", + "Avalanche-RnD", + "Snøskred-FoU" + ] }, - "tags": ["Avalanche-RnD", "Snøskred-FoU"] - }, - "handle": "https://hdl.handle.net/11250/3093125", - "identifier": "018b858395d7-02aaf128-dc44-457e-b471-675a952e8cff", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T12:04:08Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", - "type": "Organization" - }, - "resourceOwner": { - "owner": "ngi@7452.0.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + "handle": "https://hdl.handle.net/11250/3093114", + "identifier": "018b857b89d9-b5053ac9-fe14-4ea9-9922-8130b306b720", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T11:49:09Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", + "type": "Organization" + }, + "resourceOwner": { + "owner": "ngi@7452.0.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + }, + "status": "PUBLISHED" }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b857af565-f63a53df-6c4f-4051-8686-8547f45ef726", - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "ae0539fe-0d67-4854-80bc-b2e906b55ee1", - "license": "https://rightsstatements.org/page/inc/1.0", - "mimeType": "application/pdf", - "name": "20200017-03-R.pdf", - "publishedDate": "2023-10-31T11:25:09.861695292Z", - "publisherAuthority": false, - "size": 5659255, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T12:00:47Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "During the second year of the project period 2020-2022 of NGIs research project on snow avalanches, Applied Avalanche Research in Norway (AARN), work was conducted in all three work packages (WP 1 – Avalanche formation and release, WP 2 – Avalanche dynamics, WP 3 – Avalanche interaction) and several cross-package topics. The successful avalanche experiment in April 2021 has given us valuable insight into the dynamics of a large avalanche event and showed that the Ryggfonn test site produces the avalanches that are needed for the AARN research. During 2021, the results of the research activities have been published in peer-reviewed journals, summarised in technical notes, and presented online at national and international conferences and seminars. AARN personnel have been actively engaged in educational outreach activities, including as lecturers and student supervisors.", - "alternativeAbstracts": {}, - "contributors": [{ - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Christian Jaedicke" - }, - "role": { - "type": "Creator" - }, - "sequence": 4 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Sean Salazar" - }, - "role": { - "type": "Creator" - }, - "sequence": 5 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Dieter Issler" - }, - "role": { - "type": "Creator" - }, - "sequence": 3 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Regula Frauenfelder" - }, - "role": { - "type": "Creator" - }, - "sequence": 6 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Peter Gauer" - }, - "role": { - "type": "Creator" - }, - "sequence": 8 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Kate Robinson" - }, - "role": { - "type": "Creator" - }, - "sequence": 1 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Zhongqiang Liu" - }, - "role": { - "type": "Creator" - }, - "sequence": 2 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Graham Gilbert" - }, - "role": { - "type": "Creator" - }, - "sequence": 7 - } + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b857b28b5-25e3138f-5914-44e3-b322-5ed790a97f36", + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "7752c3c4-cf86-4dff-8ce8-d4f61c935ca0", + "license": "https://rightsstatements.org/page/inc/1.0", + "mimeType": "application/pdf", + "name": "20200017-05-TN.pdf", + "publishedDate": "2023-10-31T11:25:22.997593612Z", + "publisherAuthority": false, + "size": 5148309, + "visibleForNonOwner": true + } ], - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Annual Report 2021", - "publicationDate": { - "type": "PublicationDate", - "day": "08", - "month": "04", - "year": "2022" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "Report", - "publisher": { - "type": "UnconfirmedPublisher", - "name": "NGI – Norges Geotekniske institutt", - "valid": true - }, - "series": { - "type": "UnconfirmedSeries", - "title": "NGI-Rapport" - }, - "seriesNumber": "20200017-03-R" + "createdDate": "2023-09-29T11:40:07Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "NGI is operating the avalanche test site at Ryggfonn in Stryn municipality, Vestland county, western Norway (61.969°N, 7.275°E) since early 1980s. In addition to the field work and data collection in frame work of WP2, necessary repairs and updating of the data acquisition system at the Ryggfonn avalanche test site were carried out under this task. This is to ensure that the site is ready for the winter season 2020/2021.", + "alternativeAbstracts": {}, + "contributors": [ + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Peter Gauer" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Henrik Langeland" + }, + "role": { + "type": "Creator" + }, + "sequence": 2 + } + ], + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "WP 2 – Full-scale experiments at Ryggfonn Ryggfonn avalanche observations 2019/2020", + "publicationDate": { + "type": "PublicationDate", + "day": "22", + "month": "03", + "year": "2021" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "Report", + "publisher": { + "type": "UnconfirmedPublisher", + "name": "NGI – Norges Geotekniske institutt", + "valid": true + }, + "series": { + "type": "UnconfirmedSeries", + "title": "NGI-Rapport" + }, + "seriesNumber": "20200017-05-TN" + }, + "publicationInstance": { + "type": "ReportResearch", + "pages": { + "type": "MonographPages", + "illustrated": false, + "pages": "21" + } + } }, - "publicationInstance": { - "type": "ReportResearch", - "pages": { - "type": "MonographPages", - "illustrated": false, - "pages": "38" + "tags": [ + "Avalanche-RnD", + "Norwegian avalanche grant", + "Snøskred-FoU" + ] + }, + "handle": "https://hdl.handle.net/11250/3093107", + "identifier": "018b857b28b5-25e3138f-5914-44e3-b322-5ed790a97f36", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T11:40:07Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", + "type": "Organization" + }, + "resourceOwner": { + "owner": "ngi@7452.0.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + }, + "status": "PUBLISHED" + }, + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b857d48b0-cbcc81bf-0feb-4058-bf0a-8254b02b4cbd", + "additionalIdentifiers": [ + { + "type": "AdditionalIdentifier", + "sourceName": "Cristin", + "value": "2185090" + } + ], + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "ecee2024-7d86-4f5b-b642-2f464c18ad13", + "license": "https://rightsstatements.org/page/inc/1.0", + "mimeType": "application/pdf", + "name": "s00603-023-03585-9.pdf", + "publishedDate": "2023-10-31T11:27:42.251599563Z", + "publisherAuthority": true, + "size": 2892259, + "visibleForNonOwner": true + } + ], + "createdDate": "2023-10-20T21:17:59Z", + "entityDescription": { + "type": "EntityDescription", + "alternativeAbstracts": {}, + "alternativeTitles": { + "en": "Validity of the NTNU Prediction Model for D&B Tunnelling" + }, + "contributors": [ + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Sondre Gjengedal" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Pål Drevland Jakobsen" + }, + "role": { + "type": "Creator" + }, + "sequence": 3 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Amund Bruland" + }, + "role": { + "type": "Creator" + }, + "sequence": 2 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Eivind Grøv" + }, + "role": { + "type": "Creator" + }, + "sequence": 4 + } + ], + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Validity of the NTNU Prediction Model for D&B Tunnelling", + "publicationDate": { + "type": "PublicationDate", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "UnconfirmedJournal", + "printIssn": "0723-2632", + "title": "Rock Mechanics and Rock Engineering" + }, + "publicationInstance": { + "type": "AcademicArticle", + "pages": { + "type": "Range" + } } } }, - "tags": ["Avalanche-RnD", "Snøskred-FoU"] - }, - "handle": "https://hdl.handle.net/11250/3093123", - "identifier": "018b857af565-f63a53df-6c4f-4051-8686-8547f45ef726", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T12:00:47Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", - "type": "Organization" - }, - "resourceOwner": { - "owner": "ngi@7452.0.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + "handle": "https://hdl.handle.net/11250/3097894", + "identifier": "018b857d48b0-cbcc81bf-0feb-4058-bf0a-8254b02b4cbd", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-10-20T21:17:59Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", + "type": "Organization" + }, + "resourceOwner": { + "owner": "ngi@7452.0.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + }, + "status": "PUBLISHED" }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b8579ef63-3985cba8-f6e8-4038-8282-e7ffb88c6c27", - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "b4cb1f7c-9f93-486f-b963-bce60da36002", - "license": "https://rightsstatements.org/page/inc/1.0", - "mimeType": "application/pdf", - "name": "20200017-04-TN.pdf", - "publishedDate": "2023-10-31T11:24:02.787013542Z", - "publisherAuthority": false, - "size": 3514827, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T11:57:21Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "Hazard assessment for landuse planning in snow avalanche prone areas requires, besides knowledge of return periods, the specification of expected runout distances. For a complete risk assessment, additionally, the intensity of the event, often expressed in terms of impact pressures, and the corresponding vulnerability of endangered objects are needed.To obtain dynamical parameters, such as velocity, it has become state of practice to use 2-dimensional depth integrated avalanche models like RAMMS (Christen et al. 2010)or SAMOS-AT (Sampl and Granig, 2009). However, those models still lack a thorough and documented validation - which is partly caused by the lack of sufficient avalanchedata - and therefore, it requires extensive experience from practitioners to assess the model results. Mainly, the models are calibrated based on runout observation, however runout observations provide limited constraints for the validation of the empirical parameters used in common present-day numerical avalanche models. On the other hand side, observations of runout distances combined with velocity meas urements suggest that \"major'' dry-mixed avalanches show a scale invariance to the total drop height HSC. This is in accordance to the proposed upper-limit envelope of the maximum velocity by McClung and Schaerer (2003) and a simple scaling analysis using a simple mass block model on cycloidal and parabolic tracks (Gauer, 2018). Therefore, those combined observations give a much more stringent constrain for the parameter choice.", - "alternativeAbstracts": {}, - "contributors": [{ - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Annicken Helene Aalerud" - }, - "role": { - "type": "Creator" - }, - "sequence": 1 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Nellie Sofie Body" - }, - "role": { - "type": "Creator" - }, - "sequence": 2 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Peter Gauer" - }, - "role": { - "type": "Creator" - }, - "sequence": 3 - } + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018ba39a451a-7cd6f672-40e2-4c53-b0c5-501be59a8f0b", + "additionalIdentifiers": [ + { + "type": "AdditionalIdentifier", + "sourceName": "Cristin", + "value": "2179561" + } ], - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Avalanche observations versus numerical avalanche model: Simple test of model performance", - "publicationDate": { - "type": "PublicationDate", - "day": "22", - "month": "03", - "year": "2021" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "Report", - "publisher": { - "type": "UnconfirmedPublisher", - "name": "NGI – Norges Geotekniske institutt", - "valid": true - }, - "series": { - "type": "UnconfirmedSeries", - "title": "NGI-Rapport" - }, - "seriesNumber": "20200017-04-TN" - }, - "publicationInstance": { - "type": "ReportResearch", - "pages": { - "type": "MonographPages", - "illustrated": false, - "pages": "21" + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "52eeff6b-796b-49e9-b536-0b3e07c2f065", + "license": "https://creativecommons.org/licenses/by-nc/4.0", + "mimeType": "application/pdf", + "name": "2023_Conway-Moore_CoCreate+policy+ideas.pdf", + "publishedDate": "2023-11-06T07:47:58.358558928Z", + "publisherAuthority": false, + "size": 546287, + "visibleForNonOwner": true + } + ], + "createdDate": "2023-09-29T15:19:31Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "Summary Despite growing recognition of the importance of applying a systems lens to action on obesity, there has only been limited analysis of the extent to which this lens has actually been applied. The CO‐CREATE project used a youth‐led participatory action research approach to generate policy ideas towards the reduction of adolescent overweight and obesity across Europe. In order to assess the extent to which these youth‐generated policy ideas take a systems approach, we analyzed them using the Intervention Level Framework (ILF). The ILF ascribes actions to one of five system levels, from Structural Elements , the least engaged with system change, up to Paradigm , which is the system's deepest held beliefs and thus the most difficult level at which to intervene. Of the 106 policy ideas generated by young people during the CO‐CREATE project, 91 (86%) were categorized at the level of Structural Elements . This emphasis on operational rather than systems level responses echoes findings from a previous study on obesity strategies. Analyzing the distribution of systems level responses using the ILF has the potential to support more effective action on obesity by allowing identification of opportunities to strengthen systems level responses overall.\n", + "alternativeAbstracts": {}, + "alternativeTitles": { + "en": "ENEngelskEnglishCo-creating obesity prevention policies with youth: Policy ideas generated through the CO-CREATE project" + }, + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Co-creating obesity prevention policies with youth: Policy ideas generated through the CO-CREATE project", + "publicationDate": { + "type": "PublicationDate", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "UnconfirmedJournal" + }, + "publicationInstance": { + "type": "AcademicArticle", + "pages": { + "type": "Range" + } } } }, - "tags": ["Norwegian avalanche grant", "Snøskred-FoU", "Avalanche-RnD"] - }, - "handle": "https://hdl.handle.net/11250/3093120", - "identifier": "018b8579ef63-3985cba8-f6e8-4038-8282-e7ffb88c6c27", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T11:57:21Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", - "type": "Organization" - }, - "resourceOwner": { - "owner": "ngi@7452.0.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + "handle": "https://hdl.handle.net/10852/105383", + "identifier": "018ba39a451a-7cd6f672-40e2-4c53-b0c5-501be59a8f0b", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T15:19:31Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", + "type": "Organization" + }, + "resourceOwner": { + "owner": "uio@185.90.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" + }, + "status": "PUBLISHED" }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b857a85ae-110bf68d-c0f7-42b5-b635-b154ed6208dd", - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "1a3203fc-3d7d-4e21-8fab-fc2d58dfc878", - "license": "https://rightsstatements.org/page/inc/1.0", - "mimeType": "application/pdf", - "name": "20200017-09-TN.pdf", - "publishedDate": "2023-10-31T11:24:41.262439430Z", - "publisherAuthority": false, - "size": 2355368, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T11:53:36Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "The Norwegian building code regulates the societal acceptable risk from avalanches for three building classes (S1, S1, and S3). The corresponding highest allowed nominal annual probabilities of avalanches reaching the building for these classes are set as 1/100, 1/1000 and 1/5000 respectively (TEK17, 2017). That is, avalanches should not reach a building, or the accompanying outdoor area and cause (considerable) damage more often than the building class permits. These hazard classes are used for delineation of avalanche hazard zones for land use planning (TEK17, 2017). For the assessment of the quantitative risk of avalanches reaching existing settlements only limited methods are available. Thus, historical observations can be of special importance, as they may be direct indicators for the real hazard in the area of interest. To a certain degree, they can also provide an indication of a possible change of hazard over time due to environmental changes. However, historical observations are affected by inherent uncertainties and many questions remain open. Here, we aim to combine results from several work packages to develop a more consistent method of using historical observations that may help improve quantitative hazard assessments and evaluation of the uncertainties involved.", - "alternativeAbstracts": {}, - "contributors": [{ - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Peter Gauer" - }, - "role": { - "type": "Creator" - }, - "sequence": 1 - } + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018ba39a40f9-2c909b04-6380-4af3-9b7f-c1a447fba075", + "additionalIdentifiers": [ + { + "type": "AdditionalIdentifier", + "sourceName": "Cristin", + "value": "2179545" + } ], - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "CPT 3 – Quantitative risk assessment: Remarks on the uncertainty in the delimitation of hazard zones based on historical observations", - "publicationDate": { - "type": "PublicationDate", - "day": "22", - "month": "03", - "year": "2022" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "Report", - "publisher": { - "type": "UnconfirmedPublisher", - "name": "NGI – Norges Geotekniske institutt", - "valid": true - }, - "series": { - "type": "UnconfirmedSeries", - "title": "NGI-Rapport" - }, - "seriesNumber": "20200017-09-TN" - }, - "publicationInstance": { - "type": "ReportResearch", - "pages": { - "type": "MonographPages", - "illustrated": false, - "pages": "18" + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "744dc95f-19c6-4bf6-a1f7-94d81ce615f3", + "license": "https://creativecommons.org/licenses/by-nc/4.0", + "mimeType": "application/pdf", + "name": "2023_Aguiar_CoCreate+mental+wellbeing.pdf", + "publishedDate": "2023-11-06T07:47:57.300374215Z", + "publisherAuthority": false, + "size": 1406575, + "visibleForNonOwner": true + } + ], + "createdDate": "2023-09-29T15:18:43Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "Summary Both obesity and poor mental wellbeing have a high prevalence in European youth. Adolescents in six countries identified mental wellbeing factors as main drivers of youth obesity through systems mapping. This study sought to (1) explore the dynamics of the interplay between poor mental wellbeing, energy balance‐related behaviors, and adolescent overweight and obesity prevalence and (2) test the effect of intervention point scenarios to reduce adolescent obesity. Drawing on the youth‐generated systems maps and a literature synthesis, we built a simulation model that represents the links from major feedback pathways for poor mental wellbeing to changes in dietary, physical activity, and sleep behaviors. The model was calibrated using survey data from Norway, expert input, and literature and shows a good fit between simulated behavior and available statistical data. The simulations indicate that adolescent mental wellbeing is harmed by socio‐cultural pressures and stressors, which trigger reinforcing feedback mechanisms related to emotional/binge eating, lack of motivation to engage in physical activity, and sleep difficulty. Targeting a combination of intervention points that support a 25% reduction of pressure on body image and psychosocial stress showed potentially favorable effects on mental wellbeing—doubling on average for boys and girls and decreasing obesity prevalence by over 4%.\n", + "alternativeAbstracts": {}, + "alternativeTitles": { + "en": "ENEngelskEnglishUnderstanding the dynamics emerging from the interplay among poor mental wellbeing, energy balance-related behaviors, and obesity prevalence in adolescents: A simulation-based study" + }, + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Understanding the dynamics emerging from the interplay among poor mental wellbeing, energy balance-related behaviors, and obesity prevalence in adolescents: A simulation-based study", + "publicationDate": { + "type": "PublicationDate", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "UnconfirmedJournal" + }, + "publicationInstance": { + "type": "AcademicArticle", + "pages": { + "type": "Range" + } } } }, - "tags": ["Runout Distances", "Snow avalanches", "Avalanche-RnD", "Norwegian avalanche grant", "Hazard maps", "Uncertainty", "Frequency", "Snøskred-FoU", "Return Period"] - }, - "handle": "https://hdl.handle.net/11250/3093118", - "identifier": "018b857a85ae-110bf68d-c0f7-42b5-b635-b154ed6208dd", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T11:53:36Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", - "type": "Organization" - }, - "resourceOwner": { - "owner": "ngi@7452.0.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + "handle": "https://hdl.handle.net/10852/105382", + "identifier": "018ba39a40f9-2c909b04-6380-4af3-9b7f-c1a447fba075", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T15:18:43Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", + "type": "Organization" + }, + "resourceOwner": { + "owner": "uio@185.90.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" + }, + "status": "PUBLISHED" }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b857b89d9-b5053ac9-fe14-4ea9-9922-8130b306b720", - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "197afe52-704e-4b56-b3e1-ff6e0fc6b73e", - "license": "https://rightsstatements.org/page/inc/1.0", - "mimeType": "application/pdf", - "name": "20200017-01-R.pdf", - "publishedDate": "2023-10-31T11:25:47.865702950Z", - "publisherAuthority": false, - "size": 1234363, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T11:49:09Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "Snow avalanches are a significant natural hazard and common phenomenon in Norway. Each year, avalanches result in fatalities, evacuations, and interruptions or damage to infrastructure networks such as roads, railways, and electrical transmission lines. Persistent avalanche hazard in steep terrain is a major factor considered during land-use planning and development. During the snow season, daily or weekly variations in the avalanche danger identified in regional and applied bulletins influence the operation of transportation networks. Applied research on avalanches and their societal impacts has been conducted at the Norwegian Geotechnical Institute (NGI) since 1973. This research has been funded in part by an annual grant from the Norwegian parliament, administered by the Norwegian Water Resources and Energy Directorate (NVE – Norges vassdrags- og energi-direktorat). Recent research activities have improved our understanding of avalanche formation, movement, and impacts. Enhanced knowledge of the individual processes leading to avalanche initiation, avalanche dynamics, and avalanche impacts has been applied to developing tools to help predict avalanche occurrence, runout distance, and impact pressures. While much has been accomplished within the avalanche research community in recent years, many key questions remain. This project plan: (1) presents the research goals for the 2020-2022 period, (2) outlines the projects organization – including potential for external collaboration, and (3) presents the work-package structure and specific research tasks to be undertaken by the applied avalanche research group at NGI over the next three years.", - "alternativeAbstracts": {}, - "contributors": [{ - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Regula Frauenfelder" - }, - "role": { - "type": "Creator" - }, - "sequence": 5 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Kjersti Gisnås" - }, - "role": { - "type": "Creator" - }, - "sequence": 3 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Peter Gauer" - }, - "role": { - "type": "Creator" - }, - "sequence": 6 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Dieter Issler" - }, - "role": { - "type": "Creator" - }, - "sequence": 1 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Christian Jaedicke" - }, - "role": { - "type": "Creator" - }, - "sequence": 2 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Sean Salazar" - }, - "role": { - "type": "Creator" - }, - "sequence": 4 - } + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018ba39c10de-cad0ae46-6d06-4c28-a1d2-ae0f46235a3a", + "additionalIdentifiers": [ + { + "type": "AdditionalIdentifier", + "sourceName": "Cristin", + "value": "2179523" + } ], - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Research Plan 2020–2022", - "publicationDate": { - "type": "PublicationDate", - "day": "23", - "month": "04", - "year": "2020" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "Report", - "publisher": { - "type": "UnconfirmedPublisher", - "name": "NGI – Norges Geotekniske institutt", - "valid": true - }, - "series": { - "type": "UnconfirmedSeries", - "title": "NGI-Rapport" - }, - "seriesNumber": "20200017-01-R" - }, - "publicationInstance": { - "type": "ReportResearch", - "pages": { - "type": "MonographPages", - "illustrated": false, - "pages": "25" + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "e4b822fc-349f-429e-b9c9-cc3187c205e3", + "license": "https://creativecommons.org/licenses/by-nc/4.0", + "mimeType": "application/pdf", + "name": "2023_Aguiar_SD+simulation+models+on+overweight+and+obesity.pdf", + "publishedDate": "2023-11-06T07:49:56.053770685Z", + "publisherAuthority": false, + "size": 483531, + "visibleForNonOwner": true + } + ], + "createdDate": "2023-09-29T15:17:49Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "Summary It has increasingly been recognized that developing successful obesity prevention policies and interventions requires understanding of the complex mechanisms driving the obesity pandemic and that models could be useful tools for simulating policies. This paper reviews system dynamics simulation models of mechanisms driving childhood overweight and obesity and/or testing of preventive interventions. A systematic literature search was conducted in six databases from inception to January 2023 using terms related to overweight/obesity, children, and system dynamics. Study descriptives, mechanisms, and where to intervene (the leverage points), as well as quality assessments of the simulation models were extracted by two researchers into a predetermined template and narratively synthesized. Seventeen papers describing 15 models were included. Models describing the mechanisms ranged from only intrapersonal factors to models cutting across multiple levels of the ecological model, but mechanisms across levels were lacking. The majority of interventions tested in the simulation models were changes to existing model parameters with less emphasis on models that alter system structure. In conclusion, existing models included mechanisms driving youth obesity at multiple levels of the ecological model. This is useful for developing an integrated simulation model combining mechanisms at multiple levels and allowing for testing fundamental system changes.\n", + "alternativeAbstracts": {}, + "alternativeTitles": { + "en": "ENEngelskEnglishSystem dynamics simulation models on overweight and obesity in children and adolescents: A systematic review" + }, + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "System dynamics simulation models on overweight and obesity in children and adolescents: A systematic review", + "publicationDate": { + "type": "PublicationDate", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "UnconfirmedJournal" + }, + "publicationInstance": { + "type": "AcademicArticle", + "pages": { + "type": "Range" + } } } }, - "tags": ["Research plan", "Snow avalanches", "Avalanche-RnD", "Snøskred-FoU"] - }, - "handle": "https://hdl.handle.net/11250/3093114", - "identifier": "018b857b89d9-b5053ac9-fe14-4ea9-9922-8130b306b720", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T11:49:09Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", - "type": "Organization" - }, - "resourceOwner": { - "owner": "ngi@7452.0.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + "handle": "https://hdl.handle.net/10852/105381", + "identifier": "018ba39c10de-cad0ae46-6d06-4c28-a1d2-ae0f46235a3a", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-29T15:17:49Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", + "type": "Organization" + }, + "resourceOwner": { + "owner": "uio@185.90.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" + }, + "status": "PUBLISHED" }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b857b28b5-25e3138f-5914-44e3-b322-5ed790a97f36", - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "7752c3c4-cf86-4dff-8ce8-d4f61c935ca0", - "license": "https://rightsstatements.org/page/inc/1.0", - "mimeType": "application/pdf", - "name": "20200017-05-TN.pdf", - "publishedDate": "2023-10-31T11:25:22.997593612Z", - "publisherAuthority": false, - "size": 5148309, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T11:40:07Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "NGI is operating the avalanche test site at Ryggfonn in Stryn municipality, Vestland county, western Norway (61.969°N, 7.275°E) since early 1980s. In addition to the field work and data collection in frame work of WP2, necessary repairs and updating of the data acquisition system at the Ryggfonn avalanche test site were carried out under this task. This is to ensure that the site is ready for the winter season 2020/2021.", - "alternativeAbstracts": {}, - "contributors": [{ - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Peter Gauer" - }, - "role": { - "type": "Creator" - }, - "sequence": 1 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Henrik Langeland" - }, - "role": { - "type": "Creator" - }, - "sequence": 2 - } + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b857fbe4e-2d1e7fb3-5e9f-4149-8606-62164ff2e61c", + "additionalIdentifiers": [ + { + "type": "AdditionalIdentifier", + "sourceName": "Cristin", + "value": "2178703" + } ], - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "WP 2 – Full-scale experiments at Ryggfonn Ryggfonn avalanche observations 2019/2020", - "publicationDate": { - "type": "PublicationDate", - "day": "22", - "month": "03", - "year": "2021" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "Report", - "publisher": { - "type": "UnconfirmedPublisher", - "name": "NGI – Norges Geotekniske institutt", - "valid": true - }, - "series": { - "type": "UnconfirmedSeries", - "title": "NGI-Rapport" - }, - "seriesNumber": "20200017-05-TN" - }, - "publicationInstance": { - "type": "ReportResearch", - "pages": { - "type": "MonographPages", - "illustrated": false, - "pages": "21" + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "c0d766f6-982a-490c-9ff9-d8175e77478d", + "license": "https://rightsstatements.org/page/inc/1.0", + "mimeType": "application/pdf", + "name": "Stein_Langford_Kahlstr%C3%B6m%282023%29.pdf", + "publishedDate": "2023-10-31T11:30:23.434987647Z", + "publisherAuthority": true, + "size": 3194143, + "visibleForNonOwner": true + } + ], + "createdDate": "2023-09-26T05:51:17Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "Time series modelling: applications for groundwater control in urban tunnelling\nWater ingress to tunnels may result in pore pressure drawdown and consolidation settlements in areas above tunnels founded on soft soil deposits, potentially causing damage to buildings and infrastructure. To limit pore pressure drawdown, requirements are set on water ingress to bedrock tunnels. To meet these requirements, pre-excavation grouting is often performed to reduce the hydraulic conductivity of the rock mass surrounding the tunnel. Real-time pore pressure monitoring may be used to document pore pressure drawdown during construction. However, the effect of tunnel water ingress can be difficult to distinguish from natural pore pressure fluctuations. This paper presents a tunnel case in Oslo, Norway, where time series modelling was applied to local pore pressure data using the transfer function model framework. The input to the models was daily meteorological data considering precipitation and evapotranspiration, and the output was simulated pore pressure levels with impulse response functions. The models were optimised with data from before tunnel excavation, and simulations were run during the tunnel excavation period. Simulated pore pressure levels were compared with observed pore pressure levels to assess tunnelling-induced drawdown. Model uncertainty ranges were used to produce upper, lower, and best estimates of the drawdown. The findings show that time series modelling with transfer function models may be used in tunnel projects to continuously assess the impact on the local groundwater environment, for better evaluation of the pre-grouting performance, and for quantifying both the temporary and long-term drawdown with increased accuracy.\n", + "alternativeAbstracts": {}, + "alternativeTitles": { + "en": "Time series modelling: applications for groundwater control in urban tunnelling" + }, + "contributors": [ + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Mats Johan Kahlström" + }, + "role": { + "type": "Creator" + }, + "sequence": 3 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Eivind Stein" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 + }, + { + "type": "Contributor", + "correspondingAuthor": false, + "identity": { + "type": "Identity", + "name": "Jenny Langford" + }, + "role": { + "type": "Creator" + }, + "sequence": 2 + } + ], + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Time series modelling: applications for groundwater control in urban tunnelling", + "publicationDate": { + "type": "PublicationDate", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "UnconfirmedJournal", + "printIssn": "1435-9529", + "title": "Bulletin of Engineering Geology and the Environment" + }, + "publicationInstance": { + "type": "AcademicArticle", + "pages": { + "type": "Range" + }, + "volume": "82" } } }, - "tags": ["Avalanche-RnD", "Norwegian avalanche grant", "Snøskred-FoU"] - }, - "handle": "https://hdl.handle.net/11250/3093107", - "identifier": "018b857b28b5-25e3138f-5914-44e3-b322-5ed790a97f36", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T11:40:07Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", - "type": "Organization" - }, - "resourceOwner": { - "owner": "ngi@7452.0.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" - }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b857d48b0-cbcc81bf-0feb-4058-bf0a-8254b02b4cbd", - "additionalIdentifiers": [{ - "type": "AdditionalIdentifier", - "sourceName": "Cristin", - "value": "2185090" - } - ], - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "ecee2024-7d86-4f5b-b642-2f464c18ad13", - "license": "https://rightsstatements.org/page/inc/1.0", - "mimeType": "application/pdf", - "name": "s00603-023-03585-9.pdf", - "publishedDate": "2023-10-31T11:27:42.251599563Z", - "publisherAuthority": true, - "size": 2892259, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-10-20T21:17:59Z", - "entityDescription": { - "type": "EntityDescription", - "alternativeAbstracts": {}, - "alternativeTitles": { - "en": "Validity of the NTNU Prediction Model for D&B Tunnelling" + "handle": "https://hdl.handle.net/11250/3091888", + "identifier": "018b857fbe4e-2d1e7fb3-5e9f-4149-8606-62164ff2e61c", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-26T05:51:17Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", + "type": "Organization" }, - "contributors": [{ - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Sondre Gjengedal" - }, - "role": { - "type": "Creator" - }, - "sequence": 1 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Pål Drevland Jakobsen" - }, - "role": { - "type": "Creator" - }, - "sequence": 3 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Amund Bruland" - }, - "role": { - "type": "Creator" - }, - "sequence": 2 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Eivind Grøv" - }, - "role": { - "type": "Creator" - }, - "sequence": 4 - } - ], - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Validity of the NTNU Prediction Model for D&B Tunnelling", - "publicationDate": { - "type": "PublicationDate", - "year": "2023" + "resourceOwner": { + "owner": "ngi@7452.0.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "UnconfirmedJournal", - "printIssn": "0723-2632", - "title": "Rock Mechanics and Rock Engineering" - }, - "publicationInstance": { - "type": "AcademicArticle", - "pages": { - "type": "Range" + "status": "PUBLISHED" + }, + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018ba39a3a43-092f5bfa-4def-4b5d-af78-1c48cf4bd0fc", + "additionalIdentifiers": [ + { + "type": "AdditionalIdentifier", + "sourceName": "Cristin", + "value": "2133164" + } + ], + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "a01ac781-2b66-4885-800d-de27cbde85c7", + "license": "https://creativecommons.org/licenses/by/4.0", + "mimeType": "application/pdf", + "name": "Linking+brain+maturation+and+puberty+during+early+adolescence+using+longitudinal+brain+age+prediction+in+the+ABCD+cohort.pdf", + "publishedDate": "2023-11-06T07:47:55.582942300Z", + "publisherAuthority": false, + "size": 2159271, + "visibleForNonOwner": true + } + ], + "createdDate": "2023-09-21T15:46:41Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "The temporal characteristics of adolescent neurodevelopment are shaped by a complex interplay of genetic, biological, and environmental factors. Using a large longitudinal dataset of children aged 9–13 from the Adolescent Brain Cognitive Development (ABCD) study we tested the associations between pubertal status and brain maturation. Brain maturation was assessed using brain age prediction based on convolutional neural networks and minimally processed T1-weighted structural MRI data. Brain age prediction provided highly accurate and reliable estimates of individual age, with an overall mean absolute error of 0.7 and 1.4 years at the two timepoints respectively, and an intraclass correlation of 0.65. Linear mixed effects (LME) models accounting for age and sex showed that on average, a one unit increase in pubertal maturational level was associated with a 2.22 months higher brain age across time points (β = 0.10, p < .001). Moreover, annualized change in pubertal development was weakly related to the rate of change in brain age (β = .047, p = 0.04). These results demonstrate a link between sexual development and brain maturation in early adolescence, and provides a basis for further investigations of the complex sociobiological impacts of puberty on life outcomes.\n", + "alternativeAbstracts": {}, + "alternativeTitles": { + "en": "ENEngelskEnglishLinking brain maturation and puberty during early adolescence using longitudinal brain age prediction in the ABCD cohort" + }, + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Linking brain maturation and puberty during early adolescence using longitudinal brain age prediction in the ABCD cohort", + "publicationDate": { + "type": "PublicationDate", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "UnconfirmedJournal" + }, + "publicationInstance": { + "type": "AcademicArticle", + "pages": { + "type": "Range" + } } } - } - }, - "handle": "https://hdl.handle.net/11250/3097894", - "identifier": "018b857d48b0-cbcc81bf-0feb-4058-bf0a-8254b02b4cbd", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-10-20T21:17:59Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", - "type": "Organization" - }, - "resourceOwner": { - "owner": "ngi@7452.0.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" - }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018ba39a451a-7cd6f672-40e2-4c53-b0c5-501be59a8f0b", - "additionalIdentifiers": [{ - "type": "AdditionalIdentifier", - "sourceName": "Cristin", - "value": "2179561" - } - ], - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "52eeff6b-796b-49e9-b536-0b3e07c2f065", - "license": "https://creativecommons.org/licenses/by-nc/4.0", - "mimeType": "application/pdf", - "name": "2023_Conway-Moore_CoCreate+policy+ideas.pdf", - "publishedDate": "2023-11-06T07:47:58.358558928Z", - "publisherAuthority": false, - "size": 546287, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T15:19:31Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "Summary Despite growing recognition of the importance of applying a systems lens to action on obesity, there has only been limited analysis of the extent to which this lens has actually been applied. The CO‐CREATE project used a youth‐led participatory action research approach to generate policy ideas towards the reduction of adolescent overweight and obesity across Europe. In order to assess the extent to which these youth‐generated policy ideas take a systems approach, we analyzed them using the Intervention Level Framework (ILF). The ILF ascribes actions to one of five system levels, from Structural Elements , the least engaged with system change, up to Paradigm , which is the system's deepest held beliefs and thus the most difficult level at which to intervene. Of the 106 policy ideas generated by young people during the CO‐CREATE project, 91 (86%) were categorized at the level of Structural Elements . This emphasis on operational rather than systems level responses echoes findings from a previous study on obesity strategies. Analyzing the distribution of systems level responses using the ILF has the potential to support more effective action on obesity by allowing identification of opportunities to strengthen systems level responses overall.\n", - "alternativeAbstracts": {}, - "alternativeTitles": { - "en": "ENEngelskEnglishCo-creating obesity prevention policies with youth: Policy ideas generated through the CO-CREATE project" }, - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Co-creating obesity prevention policies with youth: Policy ideas generated through the CO-CREATE project", - "publicationDate": { - "type": "PublicationDate", - "year": "2023" + "handle": "https://hdl.handle.net/10852/105188", + "identifier": "018ba39a3a43-092f5bfa-4def-4b5d-af78-1c48cf4bd0fc", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-21T15:46:41Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", + "type": "Organization" }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "UnconfirmedJournal" - }, - "publicationInstance": { - "type": "AcademicArticle", - "pages": { - "type": "Range" + "resourceOwner": { + "owner": "uio@185.90.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" + }, + "status": "PUBLISHED" + }, + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018ba39aafd4-92dd290a-7c0e-4f37-98e7-a61a8d4e9a58", + "additionalIdentifiers": [ + { + "type": "AdditionalIdentifier", + "sourceName": "Cristin", + "value": "2130654" + } + ], + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "35be206e-1884-4b0e-827e-e0c2991137b0", + "license": "https://creativecommons.org/licenses/by/4.0", + "mimeType": "application/pdf", + "name": "Risk+of+recurrent+cardiovascular+events+in+coronary+artery+disease+patients+with+Type+D+personality.pdf", + "publishedDate": "2023-11-06T07:48:25.679851978Z", + "publisherAuthority": false, + "size": 1011761, + "visibleForNonOwner": true + } + ], + "createdDate": "2023-09-21T15:45:17Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "Introduction Data on the association between Type D personality, its traits negative affectivity (NA) and social inhibition (SI), and risk of major adverse cardiac events (MACE) in coronary outpatients is sparse. Furthermore, the associations between Type D subgroups and cardiovascular risk factors are largely unknown.Methods We investigated i) Type D personality, NA and SI and risk of recurrent MACE, and ii) the relationship between Type D subgroups and risk factors in a coronary population. This prospective cohort study included 1083 patients` median 16 months after a myocardial infarction and/or a revascularization procedure who were followed-up for 4.2 (SD 0.4) years. Type D personality was assessed by DS14. Anxiety and depression, statin adherence, and risk factors were assessed by patients’ self-report and a clinical examination with blood samples. MACE, defined as cardiovascular death, myocardial infarction, revascularization, stroke or heart failure, were obtained from hospital records from index event to end of study lasting 5.7 years. Data were analyzed by Cox proportional hazard regression.Results In all, 352 MACE occurred in 230 patients after average 4.2 years follow-up. Higher NA score was associated with MACE after adjustment for age, risk factors and comorbidity (HR 1.02 per unit increase, 95% CI 1.00-1.05), whereas we found a weaker, not statistically significant estimated effect of higher SI score. After additional adjustment for symptoms of anxiety and depression, we found a weaker, not statistically significant association between NA and MACE (HR 1.01 per unit increase, 95% CI 0.98-1.05). Low statin adherence and smoking were more prevalent in the Type D and high NA group.Discussion Our results indicate that the NA trait is related to worse prognosis in outpatients with coronary artery disease.\n", + "alternativeAbstracts": {}, + "alternativeTitles": { + "en": "ENEngelskEnglishRisk of recurrent cardiovascular events in coronary artery disease patients with Type D personality" + }, + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Risk of recurrent cardiovascular events in coronary artery disease patients with Type D personality", + "publicationDate": { + "type": "PublicationDate", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "UnconfirmedJournal" + }, + "publicationInstance": { + "type": "AcademicArticle", + "pages": { + "type": "Range" + } } } - } - }, - "handle": "https://hdl.handle.net/10852/105383", - "identifier": "018ba39a451a-7cd6f672-40e2-4c53-b0c5-501be59a8f0b", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T15:19:31Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", - "type": "Organization" - }, - "resourceOwner": { - "owner": "uio@185.90.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" - }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018ba39a40f9-2c909b04-6380-4af3-9b7f-c1a447fba075", - "additionalIdentifiers": [{ - "type": "AdditionalIdentifier", - "sourceName": "Cristin", - "value": "2179545" - } - ], - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "744dc95f-19c6-4bf6-a1f7-94d81ce615f3", - "license": "https://creativecommons.org/licenses/by-nc/4.0", - "mimeType": "application/pdf", - "name": "2023_Aguiar_CoCreate+mental+wellbeing.pdf", - "publishedDate": "2023-11-06T07:47:57.300374215Z", - "publisherAuthority": false, - "size": 1406575, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T15:18:43Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "Summary Both obesity and poor mental wellbeing have a high prevalence in European youth. Adolescents in six countries identified mental wellbeing factors as main drivers of youth obesity through systems mapping. This study sought to (1) explore the dynamics of the interplay between poor mental wellbeing, energy balance‐related behaviors, and adolescent overweight and obesity prevalence and (2) test the effect of intervention point scenarios to reduce adolescent obesity. Drawing on the youth‐generated systems maps and a literature synthesis, we built a simulation model that represents the links from major feedback pathways for poor mental wellbeing to changes in dietary, physical activity, and sleep behaviors. The model was calibrated using survey data from Norway, expert input, and literature and shows a good fit between simulated behavior and available statistical data. The simulations indicate that adolescent mental wellbeing is harmed by socio‐cultural pressures and stressors, which trigger reinforcing feedback mechanisms related to emotional/binge eating, lack of motivation to engage in physical activity, and sleep difficulty. Targeting a combination of intervention points that support a 25% reduction of pressure on body image and psychosocial stress showed potentially favorable effects on mental wellbeing—doubling on average for boys and girls and decreasing obesity prevalence by over 4%.\n", - "alternativeAbstracts": {}, - "alternativeTitles": { - "en": "ENEngelskEnglishUnderstanding the dynamics emerging from the interplay among poor mental wellbeing, energy balance-related behaviors, and obesity prevalence in adolescents: A simulation-based study" }, - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Understanding the dynamics emerging from the interplay among poor mental wellbeing, energy balance-related behaviors, and obesity prevalence in adolescents: A simulation-based study", - "publicationDate": { - "type": "PublicationDate", - "year": "2023" + "handle": "https://hdl.handle.net/10852/105187", + "identifier": "018ba39aafd4-92dd290a-7c0e-4f37-98e7-a61a8d4e9a58", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-21T15:45:17Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", + "type": "Organization" }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "UnconfirmedJournal" - }, - "publicationInstance": { - "type": "AcademicArticle", - "pages": { - "type": "Range" + "resourceOwner": { + "owner": "uio@185.90.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" + }, + "status": "PUBLISHED" + }, + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018ba39ab1a3-7c09e399-53b4-432a-ae89-adcb4a7a8a1f", + "additionalIdentifiers": [ + { + "type": "AdditionalIdentifier", + "sourceName": "Cristin", + "value": "2139688" + } + ], + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "d3e2bc70-d6f3-4403-946d-56e4735bc5fa", + "license": "https://creativecommons.org/licenses/by/4.0", + "mimeType": "application/pdf", + "name": "Egeland-Eriksen_et_al_International+Journal+of+Hydrogen+Energy_2023.pdf", + "publishedDate": "2023-11-06T07:48:26.143738738Z", + "publisherAuthority": false, + "size": 2993341, + "visibleForNonOwner": true + } + ], + "createdDate": "2023-09-21T15:37:31Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "This work presents simulation results from a system where offshore wind power is used to produce hydrogen via electrolysis. Real-world data from a 2.3 MW floating offshore wind turbine and electricity price data from Nord Pool were used as input to a novel electrolyzer model. Data from five 31-day periods were combined with six system designs, and hydrogen production, system efficiency, and production cost were estimated. A comparison of the overall system performance shows that the hydrogen production and cost can vary by up to a factor of three between the cases. This illustrates the uncertainty related to the hydrogen production and profitability of these systems. The highest hydrogen production achieved in a 31-day period was 17 242 kg using a 1.852 MW electrolyzer (i.e., utilization factor of approximately 68%), the lowest hydrogen production cost was 4.53 $/kg H2, and the system efficiency was in the range 56.1–56.9% in all cases.\n", + "alternativeAbstracts": {}, + "alternativeTitles": { + "en": "ENEngelskEnglishSimulating offshore hydrogen production via PEM electrolysis using real power production data from a 2.3 MW floating offshore wind turbine" + }, + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Simulating offshore hydrogen production via PEM electrolysis using real power production data from a 2.3 MW floating offshore wind turbine", + "publicationDate": { + "type": "PublicationDate", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "UnconfirmedJournal" + }, + "publicationInstance": { + "type": "AcademicArticle", + "pages": { + "type": "Range" + } } } - } - }, - "handle": "https://hdl.handle.net/10852/105382", - "identifier": "018ba39a40f9-2c909b04-6380-4af3-9b7f-c1a447fba075", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T15:18:43Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", - "type": "Organization" - }, - "resourceOwner": { - "owner": "uio@185.90.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" - }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018ba39c10de-cad0ae46-6d06-4c28-a1d2-ae0f46235a3a", - "additionalIdentifiers": [{ - "type": "AdditionalIdentifier", - "sourceName": "Cristin", - "value": "2179523" - } - ], - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "e4b822fc-349f-429e-b9c9-cc3187c205e3", - "license": "https://creativecommons.org/licenses/by-nc/4.0", - "mimeType": "application/pdf", - "name": "2023_Aguiar_SD+simulation+models+on+overweight+and+obesity.pdf", - "publishedDate": "2023-11-06T07:49:56.053770685Z", - "publisherAuthority": false, - "size": 483531, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-29T15:17:49Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "Summary It has increasingly been recognized that developing successful obesity prevention policies and interventions requires understanding of the complex mechanisms driving the obesity pandemic and that models could be useful tools for simulating policies. This paper reviews system dynamics simulation models of mechanisms driving childhood overweight and obesity and/or testing of preventive interventions. A systematic literature search was conducted in six databases from inception to January 2023 using terms related to overweight/obesity, children, and system dynamics. Study descriptives, mechanisms, and where to intervene (the leverage points), as well as quality assessments of the simulation models were extracted by two researchers into a predetermined template and narratively synthesized. Seventeen papers describing 15 models were included. Models describing the mechanisms ranged from only intrapersonal factors to models cutting across multiple levels of the ecological model, but mechanisms across levels were lacking. The majority of interventions tested in the simulation models were changes to existing model parameters with less emphasis on models that alter system structure. In conclusion, existing models included mechanisms driving youth obesity at multiple levels of the ecological model. This is useful for developing an integrated simulation model combining mechanisms at multiple levels and allowing for testing fundamental system changes.\n", - "alternativeAbstracts": {}, - "alternativeTitles": { - "en": "ENEngelskEnglishSystem dynamics simulation models on overweight and obesity in children and adolescents: A systematic review" }, - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "System dynamics simulation models on overweight and obesity in children and adolescents: A systematic review", - "publicationDate": { - "type": "PublicationDate", - "year": "2023" + "handle": "https://hdl.handle.net/10852/105181", + "identifier": "018ba39ab1a3-7c09e399-53b4-432a-ae89-adcb4a7a8a1f", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-21T15:37:31Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", + "type": "Organization" }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "UnconfirmedJournal" - }, - "publicationInstance": { - "type": "AcademicArticle", - "pages": { - "type": "Range" + "resourceOwner": { + "owner": "uio@185.90.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" + }, + "status": "PUBLISHED" + }, + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018ba39a3659-1b6c3851-55fb-4c9a-8dfe-4a005e54e2c2", + "additionalIdentifiers": [ + { + "type": "AdditionalIdentifier", + "sourceName": "Cristin", + "value": "2129196" + } + ], + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "5a8a8e75-4a13-483c-8014-8f6ed75eb468", + "license": "https://creativecommons.org/licenses/by/4.0", + "mimeType": "application/pdf", + "name": "Visual+processing+deficits+in+patients+with+schizophrenia+spectrum+and+bipolar+disorders+and+associations+with+psychotic+symptoms%2C+and+intellectual+abilities.pdf", + "publishedDate": "2023-11-06T07:47:54.580766901Z", + "publisherAuthority": false, + "size": 1578503, + "visibleForNonOwner": true + } + ], + "createdDate": "2023-09-20T16:31:48Z", + "entityDescription": { + "type": "EntityDescription", + "abstract": "Objective\nLow-level sensory disruption is hypothesized as a precursor to clinical and cognitive symptoms in severe mental disorders. We compared visual discrimination performance in patients with schizophrenia spectrum disorder or bipolar disorder with healthy controls, and investigated associations with clinical symptoms and IQ.Methods\nPatients with schizophrenia spectrum disorder (n = 32), bipolar disorder (n = 55) and healthy controls (n = 152) completed a computerized visual discrimination task. Participants responded whether the latter of two consecutive grids had higher or lower spatial frequency, and discrimination thresholds were estimated using an adaptive maximum likelihood procedure. Case-control differences in threshold were assessed using linear regression, F-test and post-hoc pair-wise comparisons. Linear models were used to test for associations between visual discrimination threshold and psychotic symptoms derived from the PANSS and IQ assessed using the Matrix Reasoning and Vocabulary subtests from the Wechsler Abbreviated Scale of Intelligence (WASI).Results\nRobust regression revealed a significant main effect of diagnosis on discrimination threshold (robust F = 6.76, p = .001). Post-hoc comparisons revealed that patients with a schizophrenia spectrum disorder (mean = 14%, SD = 0.08) had higher thresholds compared to healthy controls (mean = 10.8%, SD = 0.07, β = 0.35, t = 3.4, p = .002), as did patients with bipolar disorder (12.23%, SD = 0.07, β = 0.21, t = 2.42, p = .04). There was no significant difference between bipolar disorder and schizophrenia (β = −0.14, t = −1.2, p = .45). Linear models revealed negative associations between IQ and threshold across all participants when controlling for diagnostic group (β = −0.3, t = −3.43, p = .0007). This association was found within healthy controls (t = −3.72, p = .0003) and patients with bipolar disorder (t = −2.53, p = .015), and no significant group by IQ interaction on threshold (F = 0.044, p = .97). There were no significant associations between PANSS domain scores and discrimination threshold.Conclusion\nPatients with schizophrenia spectrum or bipolar disorders exhibited higher visual discrimination thresholds than healthy controls, supporting early visual deficits among patients with severe mental illness. Discrimination threshold was negatively associated with IQ among healthy controls and bipolar disorder patients. These findings elucidate perception-related disease mechanisms in severe mental illness, which warrants replication in independent samples.\n", + "alternativeAbstracts": {}, + "alternativeTitles": { + "en": "ENEngelskEnglishVisual processing deficits in patients with schizophrenia spectrum and bipolar disorders and associations with psychotic symptoms, and intellectual abilities" + }, + "language": "http://lexvo.org/id/iso639-3/eng", + "mainTitle": "Visual processing deficits in patients with schizophrenia spectrum and bipolar disorders and associations with psychotic symptoms, and intellectual abilities", + "publicationDate": { + "type": "PublicationDate", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "type": "UnconfirmedJournal" + }, + "publicationInstance": { + "type": "AcademicArticle", + "pages": { + "type": "Range" + } } } - } - }, - "handle": "https://hdl.handle.net/10852/105381", - "identifier": "018ba39c10de-cad0ae46-6d06-4c28-a1d2-ae0f46235a3a", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-29T15:17:49Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", - "type": "Organization" - }, - "resourceOwner": { - "owner": "uio@185.90.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" - }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b857fbe4e-2d1e7fb3-5e9f-4149-8606-62164ff2e61c", - "additionalIdentifiers": [{ - "type": "AdditionalIdentifier", - "sourceName": "Cristin", - "value": "2178703" - } - ], - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "c0d766f6-982a-490c-9ff9-d8175e77478d", - "license": "https://rightsstatements.org/page/inc/1.0", - "mimeType": "application/pdf", - "name": "Stein_Langford_Kahlstr%C3%B6m%282023%29.pdf", - "publishedDate": "2023-10-31T11:30:23.434987647Z", - "publisherAuthority": true, - "size": 3194143, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-26T05:51:17Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "Time series modelling: applications for groundwater control in urban tunnelling\nWater ingress to tunnels may result in pore pressure drawdown and consolidation settlements in areas above tunnels founded on soft soil deposits, potentially causing damage to buildings and infrastructure. To limit pore pressure drawdown, requirements are set on water ingress to bedrock tunnels. To meet these requirements, pre-excavation grouting is often performed to reduce the hydraulic conductivity of the rock mass surrounding the tunnel. Real-time pore pressure monitoring may be used to document pore pressure drawdown during construction. However, the effect of tunnel water ingress can be difficult to distinguish from natural pore pressure fluctuations. This paper presents a tunnel case in Oslo, Norway, where time series modelling was applied to local pore pressure data using the transfer function model framework. The input to the models was daily meteorological data considering precipitation and evapotranspiration, and the output was simulated pore pressure levels with impulse response functions. The models were optimised with data from before tunnel excavation, and simulations were run during the tunnel excavation period. Simulated pore pressure levels were compared with observed pore pressure levels to assess tunnelling-induced drawdown. Model uncertainty ranges were used to produce upper, lower, and best estimates of the drawdown. The findings show that time series modelling with transfer function models may be used in tunnel projects to continuously assess the impact on the local groundwater environment, for better evaluation of the pre-grouting performance, and for quantifying both the temporary and long-term drawdown with increased accuracy.\n", - "alternativeAbstracts": {}, - "alternativeTitles": { - "en": "Time series modelling: applications for groundwater control in urban tunnelling" }, - "contributors": [{ - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Mats Johan Kahlström" - }, - "role": { - "type": "Creator" - }, - "sequence": 3 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Eivind Stein" - }, - "role": { - "type": "Creator" - }, - "sequence": 1 - }, { - "type": "Contributor", - "correspondingAuthor": false, - "identity": { - "type": "Identity", - "name": "Jenny Langford" - }, - "role": { - "type": "Creator" - }, - "sequence": 2 - } - ], - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Time series modelling: applications for groundwater control in urban tunnelling", - "publicationDate": { - "type": "PublicationDate", - "year": "2023" + "handle": "https://hdl.handle.net/10852/105159", + "identifier": "018ba39a3659-1b6c3851-55fb-4c9a-8dfe-4a005e54e2c2", + "modelVersion": "0.20.54", + "nviType": "NonNviCandidate", + "publishedDate": "2023-09-20T16:31:48Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", + "type": "Organization" + }, + "resourceOwner": { + "owner": "uio@185.90.0.0", + "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "UnconfirmedJournal", - "printIssn": "1435-9529", - "title": "Bulletin of Engineering Geology and the Environment" + "fundings": [ + { + "id": "https://api.dev.nva.aws.unit.no/verified-funding/nfr/1234", + "type": "ConfirmedFunding", + "activeFrom": "2018-12-31T23:00:00Z", + "activeTo": "2019-12-31T23:00:00Z", + "identifier": "1234", + "labels": { + "nb": "Tap av natur som finansiell risiko" + }, + "source": { + "id": "https://api.dev.nva.aws.unit.no/cristin/funding-sources/NFR", + "type": "FundingSource", + "identifier": "NFR", + "labels": { + "nb": "Norges forskningsråd", + "en": "Research Council of Norway (RCN)" + } + } }, - "publicationInstance": { - "type": "AcademicArticle", - "pages": { - "type": "Range" + { + "id": "https://api.dev.nva.aws.unit.no/verified-funding/nfr/3333", + "type": "ConfirmedFunding", + "activeFrom": "2018-12-31T23:00:00Z", + "activeTo": "2019-12-31T23:00:00Z", + "identifier": "3333", + "labels": { + "nb": "Tap av Kaptial som finansiell risiko" }, - "volume": "82" + "source": { + "id": "https://api.dev.nva.aws.unit.no/cristin/funding-sources/CAPS", + "type": "FundingSource", + "identifier": "CAPS", + "labels": { + "nb": "All Kaptial", + "en": "All Caps" + } + } } - } - }, - "handle": "https://hdl.handle.net/11250/3091888", - "identifier": "018b857fbe4e-2d1e7fb3-5e9f-4149-8606-62164ff2e61c", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-26T05:51:17Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/f415cb81-ac56-4244-b31b-25e43dc3027e", - "type": "Organization" - }, - "resourceOwner": { - "owner": "ngi@7452.0.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/7452.0.0.0" + ], + + "status": "PUBLISHED" }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018ba39a3a43-092f5bfa-4def-4b5d-af78-1c48cf4bd0fc", - "additionalIdentifiers": [{ - "type": "AdditionalIdentifier", - "sourceName": "Cristin", - "value": "2133164" - } - ], - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "a01ac781-2b66-4885-800d-de27cbde85c7", - "license": "https://creativecommons.org/licenses/by/4.0", - "mimeType": "application/pdf", - "name": "Linking+brain+maturation+and+puberty+during+early+adolescence+using+longitudinal+brain+age+prediction+in+the+ABCD+cohort.pdf", - "publishedDate": "2023-11-06T07:47:55.582942300Z", - "publisherAuthority": false, - "size": 2159271, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-21T15:46:41Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "The temporal characteristics of adolescent neurodevelopment are shaped by a complex interplay of genetic, biological, and environmental factors. Using a large longitudinal dataset of children aged 9–13 from the Adolescent Brain Cognitive Development (ABCD) study we tested the associations between pubertal status and brain maturation. Brain maturation was assessed using brain age prediction based on convolutional neural networks and minimally processed T1-weighted structural MRI data. Brain age prediction provided highly accurate and reliable estimates of individual age, with an overall mean absolute error of 0.7 and 1.4 years at the two timepoints respectively, and an intraclass correlation of 0.65. Linear mixed effects (LME) models accounting for age and sex showed that on average, a one unit increase in pubertal maturational level was associated with a 2.22 months higher brain age across time points (β = 0.10, p < .001). Moreover, annualized change in pubertal development was weakly related to the rate of change in brain age (β = .047, p = 0.04). These results demonstrate a link between sexual development and brain maturation in early adolescence, and provides a basis for further investigations of the complex sociobiological impacts of puberty on life outcomes.\n", - "alternativeAbstracts": {}, - "alternativeTitles": { - "en": "ENEngelskEnglishLinking brain maturation and puberty during early adolescence using longitudinal brain age prediction in the ABCD cohort" - }, - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Linking brain maturation and puberty during early adolescence using longitudinal brain age prediction in the ABCD cohort", - "publicationDate": { - "type": "PublicationDate", - "year": "2023" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "UnconfirmedJournal" - }, - "publicationInstance": { - "type": "AcademicArticle", - "pages": { - "type": "Range" - } + { + "type": "Publication", + "publicationContextUris": [], + "@context": "https://api.dev.nva.aws.unit.no/publication/context", + "id": "https://api.dev.nva.aws.unit.no/publication/018b80d05df6-7ea5527d-6bf6-47fc-ae66-fc9515b568d4", + "associatedArtifacts": [ + { + "type": "PublishedFile", + "administrativeAgreement": false, + "identifier": "79e7070e-1ae9-4ecb-affa-0d825c5f07f1", + "license": "https://creativecommons.org/licenses/by-nc-sa/4.0", + "mimeType": "image/jpeg", + "name": "osteloff.jpg", + "publishedDate": "2023-10-30T14:08:09.021575617Z", + "publisherAuthority": false, + "size": 4656, + "visibleForNonOwner": true } - } - }, - "handle": "https://hdl.handle.net/10852/105188", - "identifier": "018ba39a3a43-092f5bfa-4def-4b5d-af78-1c48cf4bd0fc", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-21T15:46:41Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", - "type": "Organization" - }, - "resourceOwner": { - "owner": "uio@185.90.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" - }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018ba39aafd4-92dd290a-7c0e-4f37-98e7-a61a8d4e9a58", - "additionalIdentifiers": [{ - "type": "AdditionalIdentifier", - "sourceName": "Cristin", - "value": "2130654" - } - ], - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "35be206e-1884-4b0e-827e-e0c2991137b0", - "license": "https://creativecommons.org/licenses/by/4.0", - "mimeType": "application/pdf", - "name": "Risk+of+recurrent+cardiovascular+events+in+coronary+artery+disease+patients+with+Type+D+personality.pdf", - "publishedDate": "2023-11-06T07:48:25.679851978Z", - "publisherAuthority": false, - "size": 1011761, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-21T15:45:17Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "Introduction Data on the association between Type D personality, its traits negative affectivity (NA) and social inhibition (SI), and risk of major adverse cardiac events (MACE) in coronary outpatients is sparse. Furthermore, the associations between Type D subgroups and cardiovascular risk factors are largely unknown.Methods We investigated i) Type D personality, NA and SI and risk of recurrent MACE, and ii) the relationship between Type D subgroups and risk factors in a coronary population. This prospective cohort study included 1083 patients` median 16 months after a myocardial infarction and/or a revascularization procedure who were followed-up for 4.2 (SD 0.4) years. Type D personality was assessed by DS14. Anxiety and depression, statin adherence, and risk factors were assessed by patients’ self-report and a clinical examination with blood samples. MACE, defined as cardiovascular death, myocardial infarction, revascularization, stroke or heart failure, were obtained from hospital records from index event to end of study lasting 5.7 years. Data were analyzed by Cox proportional hazard regression.Results In all, 352 MACE occurred in 230 patients after average 4.2 years follow-up. Higher NA score was associated with MACE after adjustment for age, risk factors and comorbidity (HR 1.02 per unit increase, 95% CI 1.00-1.05), whereas we found a weaker, not statistically significant estimated effect of higher SI score. After additional adjustment for symptoms of anxiety and depression, we found a weaker, not statistically significant association between NA and MACE (HR 1.01 per unit increase, 95% CI 0.98-1.05). Low statin adherence and smoking were more prevalent in the Type D and high NA group.Discussion Our results indicate that the NA trait is related to worse prognosis in outpatients with coronary artery disease.\n", - "alternativeAbstracts": {}, - "alternativeTitles": { - "en": "ENEngelskEnglishRisk of recurrent cardiovascular events in coronary artery disease patients with Type D personality" - }, - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Risk of recurrent cardiovascular events in coronary artery disease patients with Type D personality", - "publicationDate": { - "type": "PublicationDate", - "year": "2023" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "UnconfirmedJournal" - }, - "publicationInstance": { - "type": "AcademicArticle", - "pages": { - "type": "Range" + ], + "createdDate": "2023-10-30T13:40:21.110219260Z", + "entityDescription": { + "type": "EntityDescription", + "alternativeAbstracts": {}, + "contributors": [ + { + "type": "Contributor", + "affiliations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.55.0", + "type": "Organization", + "countryCode": "NO", + "labels": { + "nb": "Institutt for IKT og realfag", + "en": "Department of ICT and Natural Sciences" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/45220004.0.0.0", + "type": "Organization", + "countryCode": "IQ", + "labels": { + "nn": "Al-Iraqia University", + "nb": "Al-Iraqia University", + "en": "Al-Iraqia University" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0", + "type": "Organization", + "countryCode": "NO", + "labels": { + "nb": "Sikt – Kunnskapssektorens tjenesteleverandør", + "en": "Sikt - Norwegian Agency for Shared Services in Education and Research" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0", + "type": "Organization", + "countryCode": "NO", + "labels": { + "en": "Norwegian Defence University College", + "nb": "Forsvarets høgskole" + } + } + ], + "correspondingAuthor": false, + "identity": { + "id": "https://api.dev.nva.aws.unit.no/cristin/person/1136254", + "type": "Identity", + "name": "Kjetil Møkkelgjerd", + "orcId": "https://sandbox.orcid.org/0000-0003-4147-3499", + "verificationStatus": "Verified" + }, + "role": { + "type": "Creator" + }, + "sequence": 1 + } + ], + "description": "Min beskrivelse", + "mainTitle": "Kjetils kapittel", + "publicationDate": { + "type": "PublicationDate", + "day": "3", + "month": "10", + "year": "2023" + }, + "reference": { + "type": "Reference", + "publicationContext": { + "id": "https://api.dev.nva.aws.unit.no/publication/018b80c90f4a-75942f6d-544e-4d5b-8129-7b81b957678c", + "type": "Anthology", + "entityDescription": { + "type": "EntityDescription", + "contributors": [ + { + "type": "Contributor", + "identity": { + "id": "https://api.dev.nva.aws.unit.no/cristin/person/1136254", + "type": "Identity", + "name": "Kjetil Møkkelgjerd", + "orcId": "https://sandbox.orcid.org/0000-0003-4147-3499", + "verificationStatus": "Verified" + } + } + ], + "mainTitle": "Kjetils Antologi", + "reference": { + "type": "Reference", + "publicationContext": { + "type": "Book", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/publication-channels-v2/publisher/f20577b8-0947-481b-96d4-f5de9ecf7c5f/2023", + "type": "Publisher", + "valid": true + }, + "series": { + "type": "UnconfirmedSeries" + } + } + } + } + }, + "publicationInstance": { + "type": "AcademicChapter", + "pages": { + "type": "Range" + } } } - } - }, - "handle": "https://hdl.handle.net/10852/105187", - "identifier": "018ba39aafd4-92dd290a-7c0e-4f37-98e7-a61a8d4e9a58", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-21T15:45:17Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", - "type": "Organization" - }, - "resourceOwner": { - "owner": "uio@185.90.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" - }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018ba39ab1a3-7c09e399-53b4-432a-ae89-adcb4a7a8a1f", - "additionalIdentifiers": [{ - "type": "AdditionalIdentifier", - "sourceName": "Cristin", - "value": "2139688" - } - ], - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "d3e2bc70-d6f3-4403-946d-56e4735bc5fa", - "license": "https://creativecommons.org/licenses/by/4.0", - "mimeType": "application/pdf", - "name": "Egeland-Eriksen_et_al_International+Journal+of+Hydrogen+Energy_2023.pdf", - "publishedDate": "2023-11-06T07:48:26.143738738Z", - "publisherAuthority": false, - "size": 2993341, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-21T15:37:31Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "This work presents simulation results from a system where offshore wind power is used to produce hydrogen via electrolysis. Real-world data from a 2.3 MW floating offshore wind turbine and electricity price data from Nord Pool were used as input to a novel electrolyzer model. Data from five 31-day periods were combined with six system designs, and hydrogen production, system efficiency, and production cost were estimated. A comparison of the overall system performance shows that the hydrogen production and cost can vary by up to a factor of three between the cases. This illustrates the uncertainty related to the hydrogen production and profitability of these systems. The highest hydrogen production achieved in a 31-day period was 17 242 kg using a 1.852 MW electrolyzer (i.e., utilization factor of approximately 68%), the lowest hydrogen production cost was 4.53 $/kg H2, and the system efficiency was in the range 56.1–56.9% in all cases.\n", - "alternativeAbstracts": {}, - "alternativeTitles": { - "en": "ENEngelskEnglishSimulating offshore hydrogen production via PEM electrolysis using real power production data from a 2.3 MW floating offshore wind turbine" }, - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Simulating offshore hydrogen production via PEM electrolysis using real power production data from a 2.3 MW floating offshore wind turbine", - "publicationDate": { - "type": "PublicationDate", - "year": "2023" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "UnconfirmedJournal" - }, - "publicationInstance": { - "type": "AcademicArticle", - "pages": { - "type": "Range" + "fundings": [ + { + "id": "https://api.dev.nva.aws.unit.no/verified-funding/nfr/296896", + "type": "ConfirmedFunding", + "activeFrom": "2018-12-31T23:00:00Z", + "activeTo": "2019-12-31T23:00:00Z", + "identifier": "296896", + "labels": { + "nb": "Tap av natur som finansiell risiko" + }, + "source": { + "id": "https://api.dev.nva.aws.unit.no/cristin/funding-sources/NFR", + "type": "FundingSource", + "identifier": "NFR", + "labels": { + "nb": "Norges forskningsråd", + "en": "Research Council of Norway (RCN)" + } } } - } - }, - "handle": "https://hdl.handle.net/10852/105181", - "identifier": "018ba39ab1a3-7c09e399-53b4-432a-ae89-adcb4a7a8a1f", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-21T15:37:31Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", - "type": "Organization" - }, - "resourceOwner": { - "owner": "uio@185.90.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" - }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018ba39a3659-1b6c3851-55fb-4c9a-8dfe-4a005e54e2c2", - "additionalIdentifiers": [{ - "type": "AdditionalIdentifier", - "sourceName": "Cristin", - "value": "2129196" - } - ], - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "5a8a8e75-4a13-483c-8014-8f6ed75eb468", - "license": "https://creativecommons.org/licenses/by/4.0", - "mimeType": "application/pdf", - "name": "Visual+processing+deficits+in+patients+with+schizophrenia+spectrum+and+bipolar+disorders+and+associations+with+psychotic+symptoms%2C+and+intellectual+abilities.pdf", - "publishedDate": "2023-11-06T07:47:54.580766901Z", - "publisherAuthority": false, - "size": 1578503, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-09-20T16:31:48Z", - "entityDescription": { - "type": "EntityDescription", - "abstract": "Objective\nLow-level sensory disruption is hypothesized as a precursor to clinical and cognitive symptoms in severe mental disorders. We compared visual discrimination performance in patients with schizophrenia spectrum disorder or bipolar disorder with healthy controls, and investigated associations with clinical symptoms and IQ.Methods\nPatients with schizophrenia spectrum disorder (n = 32), bipolar disorder (n = 55) and healthy controls (n = 152) completed a computerized visual discrimination task. Participants responded whether the latter of two consecutive grids had higher or lower spatial frequency, and discrimination thresholds were estimated using an adaptive maximum likelihood procedure. Case-control differences in threshold were assessed using linear regression, F-test and post-hoc pair-wise comparisons. Linear models were used to test for associations between visual discrimination threshold and psychotic symptoms derived from the PANSS and IQ assessed using the Matrix Reasoning and Vocabulary subtests from the Wechsler Abbreviated Scale of Intelligence (WASI).Results\nRobust regression revealed a significant main effect of diagnosis on discrimination threshold (robust F = 6.76, p = .001). Post-hoc comparisons revealed that patients with a schizophrenia spectrum disorder (mean = 14%, SD = 0.08) had higher thresholds compared to healthy controls (mean = 10.8%, SD = 0.07, β = 0.35, t = 3.4, p = .002), as did patients with bipolar disorder (12.23%, SD = 0.07, β = 0.21, t = 2.42, p = .04). There was no significant difference between bipolar disorder and schizophrenia (β = −0.14, t = −1.2, p = .45). Linear models revealed negative associations between IQ and threshold across all participants when controlling for diagnostic group (β = −0.3, t = −3.43, p = .0007). This association was found within healthy controls (t = −3.72, p = .0003) and patients with bipolar disorder (t = −2.53, p = .015), and no significant group by IQ interaction on threshold (F = 0.044, p = .97). There were no significant associations between PANSS domain scores and discrimination threshold.Conclusion\nPatients with schizophrenia spectrum or bipolar disorders exhibited higher visual discrimination thresholds than healthy controls, supporting early visual deficits among patients with severe mental illness. Discrimination threshold was negatively associated with IQ among healthy controls and bipolar disorder patients. These findings elucidate perception-related disease mechanisms in severe mental illness, which warrants replication in independent samples.\n", - "alternativeAbstracts": {}, - "alternativeTitles": { - "en": "ENEngelskEnglishVisual processing deficits in patients with schizophrenia spectrum and bipolar disorders and associations with psychotic symptoms, and intellectual abilities" + ], + "identifier": "018b80d05df6-7ea5527d-6bf6-47fc-ae66-fc9515b568d4", + "modelVersion": "0.20.54", + "modifiedDate": "2023-11-01T14:03:13.959722824Z", + "nviType": "NonNviCandidate", + "projects": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/project/14334813", + "type": "ResearchProject", + "name": "Utvikling av osteloffen" + } + ], + "publishedDate": "2023-10-30T14:08:09.167891227Z", + "publisher": { + "id": "https://api.dev.nva.aws.unit.no/customer/bb3d0c0c-5065-4623-9b98-5810983c2478", + "type": "Organization" }, - "language": "http://lexvo.org/id/iso639-3/eng", - "mainTitle": "Visual processing deficits in patients with schizophrenia spectrum and bipolar disorders and associations with psychotic symptoms, and intellectual abilities", - "publicationDate": { - "type": "PublicationDate", - "year": "2023" + "resourceOwner": { + "owner": "1136254@20754.0.0.0", + "ownerAffiliation": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" }, - "reference": { - "type": "Reference", - "publicationContext": { - "type": "UnconfirmedJournal" - }, - "publicationInstance": { - "type": "AcademicArticle", - "pages": { - "type": "Range" - } - } - } - }, - "handle": "https://hdl.handle.net/10852/105159", - "identifier": "018ba39a3659-1b6c3851-55fb-4c9a-8dfe-4a005e54e2c2", - "modelVersion": "0.20.54", - "nviType": "NonNviCandidate", - "publishedDate": "2023-09-20T16:31:48Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/8db4a8bd-3db5-420b-a2e4-fc17a489aa6d", - "type": "Organization" - }, - "resourceOwner": { - "owner": "uio@185.90.0.0", - "ownerAffiliation": "https://api.sandbox.nva.aws.unit.no/cristin/organization/185.90.0.0" - }, - "status": "PUBLISHED" -}, { - "type": "Publication", - "publicationContextUris": [], - "@context": "https://api.dev.nva.aws.unit.no/publication/context", - "id": "https://api.dev.nva.aws.unit.no/publication/018b80d05df6-7ea5527d-6bf6-47fc-ae66-fc9515b568d4", - "associatedArtifacts": [{ - "type": "PublishedFile", - "administrativeAgreement": false, - "identifier": "79e7070e-1ae9-4ecb-affa-0d825c5f07f1", - "license": "https://creativecommons.org/licenses/by-nc-sa/4.0", - "mimeType": "image/jpeg", - "name": "osteloff.jpg", - "publishedDate": "2023-10-30T14:08:09.021575617Z", - "publisherAuthority": false, - "size": 4656, - "visibleForNonOwner": true - } - ], - "createdDate": "2023-10-30T13:40:21.110219260Z", - "entityDescription": { - "type": "EntityDescription", - "alternativeAbstracts": {}, - "contributors": [{ - "type": "Contributor", - "affiliations": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.55.0", + "status": "PUBLISHED", + "topLevelOrganizations": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0", "type": "Organization", "countryCode": "NO", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.35.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "KD-ENHETER", + "labels": { + "nb": "Enheter under Kunnskapdepartementet og Utdanningdirektoratet" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.45.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD-ID", + "labels": { + "nb": "Institutt for design", + "en": "Department of Design" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.50.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD-IAP", + "labels": { + "nb": "Institutt for arkitektur og planlegging", + "en": "Department of Architecture and Planning" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.30.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD-KIT", + "labels": { + "nb": "Kunstakademiet i Trondheim", + "en": "Trondheim Academy of Fine Art" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.1.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD-ADM", + "labels": { + "nb": "AD fakultetsadministrasjon", + "en": "AD Faculty Administration" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.55.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD-IAT", + "labels": { + "nb": "Institutt for arkitektur og teknologi", + "en": "Department of Architecture and Technology" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0" + } + } + ], + "labels": { + "nb": "Fakultet for arkitektur og design", + "en": "Faculty of Architecture and Design" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.1.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM-ADM", + "labels": { + "nb": "Vitenskapsmuseet administrasjon", + "en": "Museum administration" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.15.15", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM-ND", + "labels": { + "nb": "Nasjonallaboratoriene for datering", + "en": "National Laboratory for Age Determination" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.10.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM-INH", + "labels": { + "nb": "Institutt for naturhistorie", + "en": "Department of Natural History" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.15.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM-SF", + "labels": { + "nb": "Seksjon for formidling", + "en": "Department of Public Outreach and Exhibitions" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.5.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM-IAK", + "labels": { + "nb": "Institutt for arkeologi og kulturhistorie", + "en": "Department of Archaeology and Cultural History" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0" + } + } + ], + "labels": { + "en": "NTNU University Museum", + "nb": "NTNU Vitenskapsmuseet" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.35.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IPH", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.35.5", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IPH-RKB", + "labels": { + "nb": "RKBU Midt-Norge - Regionalt kunnskapssenter for barn og unge - psykisk helse og barnevern", + "en": "Regional Centre for Child and Youth Mental Health and Child Welfare" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.35.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.35.20", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IPH-NAK", + "labels": { + "nb": "Nasjonalt kompetansemiljø om utviklingshemming (NAKU)", + "en": "The National Institute on Intellectual Disability and Community" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.35.0" + } + } + ], + "labels": { + "nb": "Institutt for psykisk helse", + "en": "Department of Mental Health" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.80.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IHA", + "labels": { + "nb": "Institutt for helsevitenskap Ålesund", + "en": "Department of Health Sciences Ålesund" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.1.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-ADM", + "labels": { + "nb": "MH fakultetsadministrasjon", + "en": "MH Faculty Administration" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.15.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IKOM", + "labels": { + "nb": "Institutt for klinisk og molekylær medisin", + "en": "Department of Clinical and Molecular Medicine" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.30.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-INB", + "labels": { + "nb": "Institutt for nevromedisin og bevegelsesvitenskap", + "en": "Department of Neuromedicine and Movement Science" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.60.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-KIN", + "labels": { + "nb": "Kavliinstitutt for nevrovitenskap", + "en": "Kavli Institute for Systems Neuroscience" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.70.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IHG", + "https://nva.sikt.no/ontology/publication#hasPart": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.70.20", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IHG-OMS", + "labels": { + "nb": "Senter for omsorgsforskning", + "en": "Center for Care Research" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.70.0" + } + }, + "labels": { + "nb": "Institutt for helsevitenskap Gjøvik", + "en": "Department of Health Sciences Gjøvik" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.20.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-ISM", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.20.15", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-ISM-HUN", + "labels": { + "nb": "Helseundersøkelsen i Nord-Trøndelag", + "en": "The Nord-Trøndelag Health Study" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.20.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.20.10", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AFE", + "labels": { + "nb": "Allmennmedisinsk forskningsenhet i Trondheim" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.20.0" + } + } + ], + "labels": { + "nb": "Institutt for samfunnsmedisin og sykepleie", + "en": "Department of Public Health and Nursing" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.25.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-ISB", + "labels": { + "nb": "Institutt for sirkulasjon og bildediagnostikk", + "en": "Department of Circulation and Medical Imaging" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" + } + } + ], + "labels": { + "nb": "Fakultet for medisin og helsevitenskap", + "en": "Faculty of Medicine and Health Sciences" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.94.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-IVB", + "labels": { + "nb": "Institutt for vareproduksjon og byggteknikk", + "en": "Department of Manufacturing and Civil Engineering" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.45.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-KT", + "labels": { + "nb": "Institutt for konstruksjonsteknikk", + "en": "Department of Structural Engineering" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.90.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-IGP", + "labels": { + "nb": "Institutt for geovitenskap og petroleum", + "en": "Department of Geoscience and Petroleum" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.25.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-EPT", + "labels": { + "nb": "Institutt for energi- og prosessteknikk", + "en": "Department of Energy and Process Engineering" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.80.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AMOS", + "labels": { + "nb": "Senter for autonome marine operasjoner og systemer", + "en": "Centre for autonomous marine operations and systems" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.1.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-ADM", + "labels": { + "nb": "IV fakultetsadministrasjon", + "en": "IV Faculty Administration" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.92.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-MTP", + "labels": { + "nb": "Institutt for maskinteknikk og produksjon", + "en": "Department of Mechanical and Industrial Engineering" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.20.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-IMT", + "labels": { + "nb": "Institutt for marin teknikk", + "en": "Department of Marine Technology" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.91.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-IBM", + "labels": { + "nb": "Institutt for bygg- og miljøteknikk", + "en": "Department of Civil and Environmental Engineering" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.93.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-IHB", + "labels": { + "nb": "Institutt for havromsoperasjoner og byggteknikk", + "en": "Department of Ocean Operations and Civil Engineering" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" + } + } + ], + "labels": { + "en": "Faculty of Engineering", + "nb": "Fakultet for ingeniørvitenskap" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.16.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OD", + "https://nva.sikt.no/ontology/publication#hasPart": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.16.90.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OD-KOMM", + "labels": { + "nb": "Kommunikasjonsavdelingen", + "en": "Communication Division" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.16.0.0" + } + }, + "labels": { + "nb": "Organisasjonsdirektør", + "en": "Director, Organization" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.65.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-IHS", + "labels": { + "nb": "Institutt for historiske studier", + "en": "Department of Historical Studies" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.70.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-IFR", + "labels": { + "nb": "Institutt for filosofi og religionsvitenskap", + "en": "Department of Philosophy and Religious Studies" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.40.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-KULT", + "labels": { + "nb": "Institutt for tverrfaglige kulturstudier", + "en": "Department of Interdisciplinary Studies of Culture" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.45.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-IMU", + "labels": { + "nb": "Institutt for musikk", + "en": "Department of Music" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.1.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-ADM", + "labels": { + "nb": "HF fakultetsadministrasjon", + "en": "HF faculty administration" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.35.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-IKM", + "labels": { + "nb": "Institutt for kunst- og medievitenskap", + "en": "Department of Art and Media Studies" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.60.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-ISL", + "labels": { + "nb": "Institutt for språk og litteratur", + "en": "Department of Language and Literature" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" + } + } + ], + "labels": { + "en": "Faculty of Humanities", + "nb": "Det humanistiske fakultet" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE", + "countryCode": "NO", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.15.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IMF", + "labels": { + "nb": "Institutt for matematiske fag", + "en": "Department of Mathematical Sciences" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.1.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-ADM", + "https://nva.sikt.no/ontology/publication#hasPart": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.1.20", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-ADM-NSR", + "labels": { + "nb": "Nasjonalt senter for realfagsrekruttering", + "en": "The National Centre for Science Recruitment" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.1.0" + } + }, + "labels": { + "nb": "IE fakultetsadministrasjon", + "en": "IE Faculty Administration" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.30.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IIK", + "labels": { + "nb": "Institutt for informasjonssikkerhet og kommunikasjonsteknologi", + "en": "Department of Information Security and Communication Technology" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.20.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IEL", + "labels": { + "nb": "Institutt for elkraftteknikk", + "en": "Department of Electric Power Engineering" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.25.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-ITK", + "labels": { + "nb": "Institutt for teknisk kybernetikk", + "en": "Department of Engineering Cybernetics" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.35.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IES", + "labels": { + "nb": "Institutt for elektroniske systemer", + "en": "Department of Electronic Systems" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.10.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IDI", + "labels": { + "nb": "Institutt for datateknologi og informatikk", + "en": "Department of Computer Science" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.55.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IIR", + "countryCode": "NO", + "labels": { + "nb": "Institutt for IKT og realfag", + "en": "Department of ICT and Natural Sciences" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" + } + } + ], + "labels": { + "en": "Faculty of Information Technology and Electrical Engineering", + "nb": "Fakultet for informasjonsteknologi og elektroteknikk" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.17.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NY", + "labels": { + "nb": "Prorektor for nyskaping", + "en": "Pro-Rector for Innovation" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.14.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "UTD", + "https://nva.sikt.no/ontology/publication#hasPart": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.14.30.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "UTD-UB", + "labels": { + "nb": "NTNU Universitetsbiblioteket", + "en": "NTNU University Library" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.14.0.0" + } + }, + "labels": { + "nb": "Prorektor for utdanning", + "en": "Pro-Rector for Education" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.25.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IKJ", + "labels": { + "nb": "Institutt for kjemi", + "en": "Department of Chemistry" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.50.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-FELLES", + "labels": { + "nb": "Felles forskningsinfrastruktur", + "en": "Research Infrastructure" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.45.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IBA", + "labels": { + "nb": "Institutt for biologiske fag Ålesund", + "en": "Department of Biological Sciences Ålesund" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.30.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IKP", + "labels": { + "nb": "Institutt for kjemisk prosessteknologi", + "en": "Department of Chemical Engineering" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.10.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IBI", + "labels": { + "nb": "Institutt for biologi", + "en": "Department of Biology" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.40.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IBF", + "labels": { + "nb": "Institutt for bioingeniørfag", + "en": "Department of Biomedical Laboratory Science" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.20.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IFY", + "labels": { + "nb": "Institutt for fysikk", + "en": "Department of Physics" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.1.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-ADM", + "labels": { + "nb": "NV fakultetsadministrasjon", + "en": "NV Faculty Administration" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.35.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IMA", + "labels": { + "nb": "Institutt for materialteknologi", + "en": "Department of Materials Science and Engineering" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.15.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IBT", + "labels": { + "nb": "Institutt for bioteknologi og matvitenskap", + "en": "Department of Biotechnology and Food Science" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" + } + } + ], + "labels": { + "nb": "Fakultet for naturvitenskap", + "en": "Faculty of Natural Sciences" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.1.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK-ADM", + "labels": { + "nb": "ØK fakultetsadministrasjon", + "en": "Economics and Management Faculty Administration" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.10.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK-HHS", + "labels": { + "nb": "NTNU Handelshøyskolen", + "en": "NTNU Business School" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.20.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK-ISO", + "labels": { + "nb": "Institutt for samfunnsøkonomi", + "en": "Department of Economics" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.25.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK-IOT", + "labels": { + "nb": "Institutt for industriell økonomi og teknologiledelse", + "en": "Department of Industrial Economics and Technology Management" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.15.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK-IIF", + "labels": { + "nb": "Institutt for internasjonal forretningsdrift", + "en": "Department of International Business" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0" + } + } + ], + "labels": { + "en": "Faculty of Economics and Management", + "nb": "Fakultet for økonomi" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.12.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "RE", + "https://nva.sikt.no/ontology/publication#hasPart": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.12.1.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "RE-REK", + "labels": { + "nb": "Rektor og styre", + "en": "Rector and Board" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.12.0.0" + } + }, + "labels": { + "nb": "Rektor", + "en": "Rector" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.13.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FO", + "labels": { + "nb": "Prorektor for forskning", + "en": "Pro-Rector for Research" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.15.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OE", + "labels": { + "nb": "Økonomi- og eiendomsdirektør", + "en": "Director of Finance and Property" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.80.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ILU", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.80.40", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ILU-NSS", + "labels": { + "nb": "Nasjonalt senter for skriveopplæring og skriveforsking", + "en": "The Norwegian Centre for Writing Education and Research (The Writing Centre)" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.80.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.80.30", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ILU-NSM", + "labels": { + "nb": "Nasjonalt senter for matematikk i opplæringen", + "en": "Norwegian Centre for Mathematics Education" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.80.0" + } + } + ], + "labels": { + "nb": "Institutt for lærerutdanning", + "en": "Department of Teacher Education" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.45.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-SA", + "labels": { + "nb": "Institutt for sosialantropologi", + "en": "Department of Social Anthropology" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.40.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-IPS", + "labels": { + "nb": "Institutt for psykologi", + "en": "Department of Psychology" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.1.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ADM", + "labels": { + "nb": "SU fakultetsadministrasjon", + "en": "SU Faculty Administration" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.90.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ISA", + "labels": { + "nb": "Institutt for sosialt arbeid", + "en": "Department of Social Work" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.25.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ISS", + "labels": { + "nb": "Institutt for sosiologi og statsvitenskap", + "en": "Department of Sociology and Political Science" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.70.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-IPL", + "labels": { + "nb": "Institutt for pedagogikk og livslang læring", + "en": "Department of Education and Lifelong Learning" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.10.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-IGE", + "labels": { + "nb": "Institutt for geografi", + "en": "Department of Geography" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" + } + } + ], + "labels": { + "nb": "Fakultet for samfunns- og utdanningsvitenskap", + "en": "Faculty of Social and Educational Sciences" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" + } + } + ], "labels": { - "nb": "Institutt for IKT og realfag", - "en": "Department of ICT and Natural Sciences" + "en": "Norwegian University of Science and Technology", + "nb": "Norges teknisk-naturvitenskapelige universitet", + "nn": "Noregs teknisk-naturvitskaplege universitet" } - }, { + }, + { "id": "https://api.dev.nva.aws.unit.no/cristin/organization/45220004.0.0.0", "type": "Organization", "countryCode": "IQ", "labels": { - "nn": "Al-Iraqia University", - "nb": "Al-Iraqia University", - "en": "Al-Iraqia University" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0", - "type": "Organization", - "countryCode": "NO", - "labels": { - "nb": "Sikt – Kunnskapssektorens tjenesteleverandør", - "en": "Sikt - Norwegian Agency for Shared Services in Education and Research" + "nn": "Al-Iraqia University1", + "nb": "Al-Iraqia University2", + "en": "Al-Iraqia University3" } - }, { + }, + { "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0", "type": "Organization", "countryCode": "NO", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.4.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "KS", + "labels": { + "nb": "Krigsskolen (KS)" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.7.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IFF", + "labels": { + "nb": "Institutt for forsvarsstudier" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.5.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FIH", + "labels": { + "nb": "Cyberingeniørskolen" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.2.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "LKSK", + "labels": { + "nb": "Luftkrigsskolen (LKSK)" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.8.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FSK", + "labels": { + "nb": "Institutt for militær ledelse og operasjoner" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.9.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "BEFAL", + "labels": { + "nb": "Befalsskolen", + "en": "Officer Candidate School" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.3.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SKSK", + "labels": { + "nb": "Sjøkrigsskolen (SKSK)" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" + } + } + ], "labels": { "en": "Norwegian Defence University College", "nb": "Forsvarets høgskole" } - } - ], - "correspondingAuthor": false, - "identity": { - "id": "https://api.dev.nva.aws.unit.no/cristin/person/1136254", - "type": "Identity", - "name": "Kjetil Møkkelgjerd", - "orcId": "https://sandbox.orcid.org/0000-0003-4147-3499", - "verificationStatus": "Verified" }, - "role": { - "type": "Creator" - }, - "sequence": 1 - } - ], - "description": "Min beskrivelse", - "mainTitle": "Kjetils kapittel", - "publicationDate": { - "type": "PublicationDate", - "day": "3", - "month": "10", - "year": "2023" - }, - "reference": { - "type": "Reference", - "publicationContext": { - "id": "https://api.dev.nva.aws.unit.no/publication/018b80c90f4a-75942f6d-544e-4d5b-8129-7b81b957678c", - "type": "Anthology", - "entityDescription": { - "type": "EntityDescription", - "contributors": [{ - "type": "Contributor", - "identity": { - "id": "https://api.dev.nva.aws.unit.no/cristin/person/1136254", - "type": "Identity", - "name": "Kjetil Møkkelgjerd", - "orcId": "https://sandbox.orcid.org/0000-0003-4147-3499", - "verificationStatus": "Verified" + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0", + "type": "Organization", + "countryCode": "NO", + "https://nva.sikt.no/ontology/publication#hasPart": [ + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.1.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "UA", + "labels": { + "nn": "Divisjon for utdanning og administrasjon", + "nb": "Divisjon utdanning og administrasjon", + "en": "The Education and Administration Division" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" } - } - ], - "mainTitle": "Kjetils Antologi", - "reference": { - "type": "Reference", - "publicationContext": { - "type": "Book", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/publication-channels-v2/publisher/f20577b8-0947-481b-96d4-f5de9ecf7c5f/2023", - "type": "Publisher", - "valid": true - }, - "series": { - "type": "UnconfirmedSeries" - } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.2.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FK", + "labels": { + "nn": "Divisjon for forskings- og kunnskapsressursar", + "nb": "Divisjon forsknings- og kunnskapsressurser", + "en": "The Research and Education Resources Division" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.4.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "ORG", + "labels": { + "nn": "Avdeling for organisasjonsutvikling", + "nb": "Avdeling for organisasjonsutvikling", + "en": "The Organisational Development Department" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.6.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "KUNDE", + "labels": { + "nn": "Avdeling for kunde og kommunikasjon", + "nb": "Avdeling for kunde og kommunikasjon", + "en": "The Customer and Communication Department" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.5.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VIRK", + "labels": { + "nn": "Avdeling for verksemdstyring", + "nb": "Avdeling for virksomhetsstyring", + "en": "The Corporate Governance Department" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" + } + }, + { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.3.0.0", + "type": "Organization", + "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "DI", + "labels": { + "nn": "Divisjon for data og infrastruktur", + "nb": "Divisjon data og infrastruktur", + "en": "The Organisational Development Department" + }, + "partOf": { + "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" } } - } - }, - "publicationInstance": { - "type": "AcademicChapter", - "pages": { - "type": "Range" - } - } - } - }, - "fundings": [{ - "id": "https://api.dev.nva.aws.unit.no/verified-funding/nfr/296896", - "type": "ConfirmedFunding", - "activeFrom": "2018-12-31T23:00:00Z", - "activeTo": "2019-12-31T23:00:00Z", - "identifier": "296896", - "labels": { - "nb": "Tap av natur som finansiell risiko" - }, - "source": { - "id": "https://api.dev.nva.aws.unit.no/cristin/funding-sources/NFR", - "type": "FundingSource", - "identifier": "NFR", - "labels": { - "nb": "Norges forskningsråd", - "en": "Research Council of Norway (RCN)" - } - } - } - ], - "identifier": "018b80d05df6-7ea5527d-6bf6-47fc-ae66-fc9515b568d4", - "modelVersion": "0.20.54", - "modifiedDate": "2023-11-01T14:03:13.959722824Z", - "nviType": "NonNviCandidate", - "projects": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/project/14334813", - "type": "ResearchProject", - "name": "Utvikling av osteloffen" - } - ], - "publishedDate": "2023-10-30T14:08:09.167891227Z", - "publisher": { - "id": "https://api.dev.nva.aws.unit.no/customer/bb3d0c0c-5065-4623-9b98-5810983c2478", - "type": "Organization" - }, - "resourceOwner": { - "owner": "1136254@20754.0.0.0", - "ownerAffiliation": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - }, - "status": "PUBLISHED", - "topLevelOrganizations": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0", - "type": "Organization", - "countryCode": "NO", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.35.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "KD-ENHETER", - "labels": { - "nb": "Enheter under Kunnskapdepartementet og Utdanningdirektoratet" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.45.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD-ID", - "labels": { - "nb": "Institutt for design", - "en": "Department of Design" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.50.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD-IAP", - "labels": { - "nb": "Institutt for arkitektur og planlegging", - "en": "Department of Architecture and Planning" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.30.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD-KIT", - "labels": { - "nb": "Kunstakademiet i Trondheim", - "en": "Trondheim Academy of Fine Art" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.1.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD-ADM", - "labels": { - "nb": "AD fakultetsadministrasjon", - "en": "AD Faculty Administration" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.55.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AD-IAT", + ], "labels": { - "nb": "Institutt for arkitektur og teknologi", - "en": "Department of Architecture and Technology" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.61.0.0" + "nb": "Sikt – Kunnskapssektorens tjenesteleverandør", + "en": "Sikt - Norwegian Agency for Shared Services in Education and Research" } } - ], - "labels": { - "nb": "Fakultet for arkitektur og design", - "en": "Faculty of Architecture and Design" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.1.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM-ADM", - "labels": { - "nb": "Vitenskapsmuseet administrasjon", - "en": "Museum administration" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.15.15", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM-ND", - "labels": { - "nb": "Nasjonallaboratoriene for datering", - "en": "National Laboratory for Age Determination" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.10.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM-INH", - "labels": { - "nb": "Institutt for naturhistorie", - "en": "Department of Natural History" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.15.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM-SF", - "labels": { - "nb": "Seksjon for formidling", - "en": "Department of Public Outreach and Exhibitions" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.5.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VM-IAK", - "labels": { - "nb": "Institutt for arkeologi og kulturhistorie", - "en": "Department of Archaeology and Cultural History" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.31.0.0" - } - } - ], - "labels": { - "en": "NTNU University Museum", - "nb": "NTNU Vitenskapsmuseet" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.35.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IPH", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.35.5", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IPH-RKB", - "labels": { - "nb": "RKBU Midt-Norge - Regionalt kunnskapssenter for barn og unge - psykisk helse og barnevern", - "en": "Regional Centre for Child and Youth Mental Health and Child Welfare" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.35.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.35.20", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IPH-NAK", - "labels": { - "nb": "Nasjonalt kompetansemiljø om utviklingshemming (NAKU)", - "en": "The National Institute on Intellectual Disability and Community" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.35.0" - } - } - ], - "labels": { - "nb": "Institutt for psykisk helse", - "en": "Department of Mental Health" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.80.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IHA", - "labels": { - "nb": "Institutt for helsevitenskap Ålesund", - "en": "Department of Health Sciences Ålesund" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.1.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-ADM", - "labels": { - "nb": "MH fakultetsadministrasjon", - "en": "MH Faculty Administration" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.15.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IKOM", - "labels": { - "nb": "Institutt for klinisk og molekylær medisin", - "en": "Department of Clinical and Molecular Medicine" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.30.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-INB", - "labels": { - "nb": "Institutt for nevromedisin og bevegelsesvitenskap", - "en": "Department of Neuromedicine and Movement Science" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.60.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-KIN", - "labels": { - "nb": "Kavliinstitutt for nevrovitenskap", - "en": "Kavli Institute for Systems Neuroscience" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.70.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IHG", - "https://nva.sikt.no/ontology/publication#hasPart": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.70.20", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-IHG-OMS", - "labels": { - "nb": "Senter for omsorgsforskning", - "en": "Center for Care Research" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.70.0" - } - }, - "labels": { - "nb": "Institutt for helsevitenskap Gjøvik", - "en": "Department of Health Sciences Gjøvik" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.20.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-ISM", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.20.15", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-ISM-HUN", - "labels": { - "nb": "Helseundersøkelsen i Nord-Trøndelag", - "en": "The Nord-Trøndelag Health Study" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.20.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.20.10", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AFE", - "labels": { - "nb": "Allmennmedisinsk forskningsenhet i Trondheim" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.20.0" - } - } - ], - "labels": { - "nb": "Institutt for samfunnsmedisin og sykepleie", - "en": "Department of Public Health and Nursing" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.25.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "MH-ISB", - "labels": { - "nb": "Institutt for sirkulasjon og bildediagnostikk", - "en": "Department of Circulation and Medical Imaging" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.65.0.0" - } - } - ], - "labels": { - "nb": "Fakultet for medisin og helsevitenskap", - "en": "Faculty of Medicine and Health Sciences" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.94.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-IVB", - "labels": { - "nb": "Institutt for vareproduksjon og byggteknikk", - "en": "Department of Manufacturing and Civil Engineering" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.45.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-KT", - "labels": { - "nb": "Institutt for konstruksjonsteknikk", - "en": "Department of Structural Engineering" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.90.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-IGP", - "labels": { - "nb": "Institutt for geovitenskap og petroleum", - "en": "Department of Geoscience and Petroleum" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.25.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-EPT", - "labels": { - "nb": "Institutt for energi- og prosessteknikk", - "en": "Department of Energy and Process Engineering" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.80.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "AMOS", - "labels": { - "nb": "Senter for autonome marine operasjoner og systemer", - "en": "Centre for autonomous marine operations and systems" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.1.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-ADM", - "labels": { - "nb": "IV fakultetsadministrasjon", - "en": "IV Faculty Administration" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.92.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-MTP", - "labels": { - "nb": "Institutt for maskinteknikk og produksjon", - "en": "Department of Mechanical and Industrial Engineering" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.20.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-IMT", - "labels": { - "nb": "Institutt for marin teknikk", - "en": "Department of Marine Technology" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.91.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-IBM", - "labels": { - "nb": "Institutt for bygg- og miljøteknikk", - "en": "Department of Civil and Environmental Engineering" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.93.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IV-IHB", - "labels": { - "nb": "Institutt for havromsoperasjoner og byggteknikk", - "en": "Department of Ocean Operations and Civil Engineering" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.64.0.0" - } - } - ], - "labels": { - "en": "Faculty of Engineering", - "nb": "Fakultet for ingeniørvitenskap" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.16.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OD", - "https://nva.sikt.no/ontology/publication#hasPart": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.16.90.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OD-KOMM", - "labels": { - "nb": "Kommunikasjonsavdelingen", - "en": "Communication Division" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.16.0.0" - } - }, - "labels": { - "nb": "Organisasjonsdirektør", - "en": "Director, Organization" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.65.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-IHS", - "labels": { - "nb": "Institutt for historiske studier", - "en": "Department of Historical Studies" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.70.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-IFR", - "labels": { - "nb": "Institutt for filosofi og religionsvitenskap", - "en": "Department of Philosophy and Religious Studies" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.40.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-KULT", - "labels": { - "nb": "Institutt for tverrfaglige kulturstudier", - "en": "Department of Interdisciplinary Studies of Culture" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.45.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-IMU", - "labels": { - "nb": "Institutt for musikk", - "en": "Department of Music" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.1.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-ADM", - "labels": { - "nb": "HF fakultetsadministrasjon", - "en": "HF faculty administration" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.35.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-IKM", - "labels": { - "nb": "Institutt for kunst- og medievitenskap", - "en": "Department of Art and Media Studies" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.60.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "HF-ISL", - "labels": { - "nb": "Institutt for språk og litteratur", - "en": "Department of Language and Literature" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.62.0.0" - } - } - ], - "labels": { - "en": "Faculty of Humanities", - "nb": "Det humanistiske fakultet" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE", - "countryCode": "NO", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.15.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IMF", - "labels": { - "nb": "Institutt for matematiske fag", - "en": "Department of Mathematical Sciences" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.1.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-ADM", - "https://nva.sikt.no/ontology/publication#hasPart": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.1.20", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-ADM-NSR", - "labels": { - "nb": "Nasjonalt senter for realfagsrekruttering", - "en": "The National Centre for Science Recruitment" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.1.0" - } - }, - "labels": { - "nb": "IE fakultetsadministrasjon", - "en": "IE Faculty Administration" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.30.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IIK", - "labels": { - "nb": "Institutt for informasjonssikkerhet og kommunikasjonsteknologi", - "en": "Department of Information Security and Communication Technology" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.20.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IEL", - "labels": { - "nb": "Institutt for elkraftteknikk", - "en": "Department of Electric Power Engineering" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.25.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-ITK", - "labels": { - "nb": "Institutt for teknisk kybernetikk", - "en": "Department of Engineering Cybernetics" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.35.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IES", - "labels": { - "nb": "Institutt for elektroniske systemer", - "en": "Department of Electronic Systems" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.10.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IDI", - "labels": { - "nb": "Institutt for datateknologi og informatikk", - "en": "Department of Computer Science" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.55.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IE-IIR", - "countryCode": "NO", - "labels": { - "nb": "Institutt for IKT og realfag", - "en": "Department of ICT and Natural Sciences" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.63.0.0" - } - } - ], - "labels": { - "en": "Faculty of Information Technology and Electrical Engineering", - "nb": "Fakultet for informasjonsteknologi og elektroteknikk" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.17.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NY", - "labels": { - "nb": "Prorektor for nyskaping", - "en": "Pro-Rector for Innovation" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.14.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "UTD", - "https://nva.sikt.no/ontology/publication#hasPart": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.14.30.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "UTD-UB", - "labels": { - "nb": "NTNU Universitetsbiblioteket", - "en": "NTNU University Library" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.14.0.0" - } - }, - "labels": { - "nb": "Prorektor for utdanning", - "en": "Pro-Rector for Education" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.25.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IKJ", - "labels": { - "nb": "Institutt for kjemi", - "en": "Department of Chemistry" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.50.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-FELLES", - "labels": { - "nb": "Felles forskningsinfrastruktur", - "en": "Research Infrastructure" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.45.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IBA", - "labels": { - "nb": "Institutt for biologiske fag Ålesund", - "en": "Department of Biological Sciences Ålesund" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.30.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IKP", - "labels": { - "nb": "Institutt for kjemisk prosessteknologi", - "en": "Department of Chemical Engineering" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.10.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IBI", - "labels": { - "nb": "Institutt for biologi", - "en": "Department of Biology" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.40.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IBF", - "labels": { - "nb": "Institutt for bioingeniørfag", - "en": "Department of Biomedical Laboratory Science" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.20.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IFY", - "labels": { - "nb": "Institutt for fysikk", - "en": "Department of Physics" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.1.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-ADM", - "labels": { - "nb": "NV fakultetsadministrasjon", - "en": "NV Faculty Administration" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.35.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IMA", - "labels": { - "nb": "Institutt for materialteknologi", - "en": "Department of Materials Science and Engineering" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.15.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "NV-IBT", - "labels": { - "nb": "Institutt for bioteknologi og matvitenskap", - "en": "Department of Biotechnology and Food Science" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.66.0.0" - } - } - ], - "labels": { - "nb": "Fakultet for naturvitenskap", - "en": "Faculty of Natural Sciences" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.1.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK-ADM", - "labels": { - "nb": "ØK fakultetsadministrasjon", - "en": "Economics and Management Faculty Administration" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.10.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK-HHS", - "labels": { - "nb": "NTNU Handelshøyskolen", - "en": "NTNU Business School" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.20.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK-ISO", - "labels": { - "nb": "Institutt for samfunnsøkonomi", - "en": "Department of Economics" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.25.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK-IOT", - "labels": { - "nb": "Institutt for industriell økonomi og teknologiledelse", - "en": "Department of Industrial Economics and Technology Management" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.15.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OK-IIF", - "labels": { - "nb": "Institutt for internasjonal forretningsdrift", - "en": "Department of International Business" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.60.0.0" - } - } - ], - "labels": { - "en": "Faculty of Economics and Management", - "nb": "Fakultet for økonomi" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.12.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "RE", - "https://nva.sikt.no/ontology/publication#hasPart": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.12.1.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "RE-REK", - "labels": { - "nb": "Rektor og styre", - "en": "Rector and Board" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.12.0.0" - } - }, - "labels": { - "nb": "Rektor", - "en": "Rector" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.13.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FO", - "labels": { - "nb": "Prorektor for forskning", - "en": "Pro-Rector for Research" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.15.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "OE", - "labels": { - "nb": "Økonomi- og eiendomsdirektør", - "en": "Director of Finance and Property" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.80.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ILU", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.80.40", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ILU-NSS", - "labels": { - "nb": "Nasjonalt senter for skriveopplæring og skriveforsking", - "en": "The Norwegian Centre for Writing Education and Research (The Writing Centre)" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.80.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.80.30", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ILU-NSM", - "labels": { - "nb": "Nasjonalt senter for matematikk i opplæringen", - "en": "Norwegian Centre for Mathematics Education" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.80.0" - } - } - ], - "labels": { - "nb": "Institutt for lærerutdanning", - "en": "Department of Teacher Education" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.45.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-SA", - "labels": { - "nb": "Institutt for sosialantropologi", - "en": "Department of Social Anthropology" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.40.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-IPS", - "labels": { - "nb": "Institutt for psykologi", - "en": "Department of Psychology" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.1.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ADM", - "labels": { - "nb": "SU fakultetsadministrasjon", - "en": "SU Faculty Administration" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.90.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ISA", - "labels": { - "nb": "Institutt for sosialt arbeid", - "en": "Department of Social Work" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.25.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-ISS", - "labels": { - "nb": "Institutt for sosiologi og statsvitenskap", - "en": "Department of Sociology and Political Science" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.70.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-IPL", - "labels": { - "nb": "Institutt for pedagogikk og livslang læring", - "en": "Department of Education and Lifelong Learning" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.10.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SU-IGE", - "labels": { - "nb": "Institutt for geografi", - "en": "Department of Geography" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.67.0.0" - } - } - ], - "labels": { - "nb": "Fakultet for samfunns- og utdanningsvitenskap", - "en": "Faculty of Social and Educational Sciences" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/194.0.0.0" - } - } - ], - "labels": { - "en": "Norwegian University of Science and Technology", - "nb": "Norges teknisk-naturvitenskapelige universitet", - "nn": "Noregs teknisk-naturvitskaplege universitet" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/45220004.0.0.0", - "type": "Organization", - "countryCode": "IQ", - "labels": { - "nn": "Al-Iraqia University", - "nb": "Al-Iraqia University", - "en": "Al-Iraqia University" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0", - "type": "Organization", - "countryCode": "NO", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.4.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "KS", - "labels": { - "nb": "Krigsskolen (KS)" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.7.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "IFF", - "labels": { - "nb": "Institutt for forsvarsstudier" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.5.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FIH", - "labels": { - "nb": "Cyberingeniørskolen" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.2.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "LKSK", - "labels": { - "nb": "Luftkrigsskolen (LKSK)" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.8.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FSK", - "labels": { - "nb": "Institutt for militær ledelse og operasjoner" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.9.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "BEFAL", - "labels": { - "nb": "Befalsskolen", - "en": "Officer Candidate School" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.3.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "SKSK", - "labels": { - "nb": "Sjøkrigsskolen (SKSK)" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/1627.0.0.0" - } - } - ], - "labels": { - "en": "Norwegian Defence University College", - "nb": "Forsvarets høgskole" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0", - "type": "Organization", - "countryCode": "NO", - "https://nva.sikt.no/ontology/publication#hasPart": [{ - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.1.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "UA", - "labels": { - "nn": "Divisjon for utdanning og administrasjon", - "nb": "Divisjon utdanning og administrasjon", - "en": "The Education and Administration Division" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.2.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "FK", - "labels": { - "nn": "Divisjon for forskings- og kunnskapsressursar", - "nb": "Divisjon forsknings- og kunnskapsressurser", - "en": "The Research and Education Resources Division" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.4.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "ORG", - "labels": { - "nn": "Avdeling for organisasjonsutvikling", - "nb": "Avdeling for organisasjonsutvikling", - "en": "The Organisational Development Department" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.6.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "KUNDE", - "labels": { - "nn": "Avdeling for kunde og kommunikasjon", - "nb": "Avdeling for kunde og kommunikasjon", - "en": "The Customer and Communication Department" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.5.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "VIRK", - "labels": { - "nn": "Avdeling for verksemdstyring", - "nb": "Avdeling for virksomhetsstyring", - "en": "The Corporate Governance Department" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - } - }, { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.3.0.0", - "type": "Organization", - "https://bibsysdev.github.io/src/organization-ontology.ttl#acronym": "DI", - "labels": { - "nn": "Divisjon for data og infrastruktur", - "nb": "Divisjon data og infrastruktur", - "en": "The Organisational Development Department" - }, - "partOf": { - "id": "https://api.dev.nva.aws.unit.no/cristin/organization/20754.0.0.0" - } - } - ], - "labels": { - "nb": "Sikt – Kunnskapssektorens tjenesteleverandør", - "en": "Sikt - Norwegian Agency for Shared Services in Education and Research" - } + ] } - ] -} ] diff --git a/search-commons/src/test/resources/test_import_candidates_mappings.json b/search-commons/src/test/resources/test_import_candidates_mappings.json index c740cf3e7..7ccbf1cac 100644 --- a/search-commons/src/test/resources/test_import_candidates_mappings.json +++ b/search-commons/src/test/resources/test_import_candidates_mappings.json @@ -36,4 +36,3 @@ } } - diff --git a/search-commons/src/test/resources/test_resources_mappings.json b/search-commons/src/test/resources/test_resources_mappings.json index 793929905..05bc6d313 100644 --- a/search-commons/src/test/resources/test_resources_mappings.json +++ b/search-commons/src/test/resources/test_resources_mappings.json @@ -4,8 +4,10 @@ "type": "nested", "include_in_parent": true, "properties": { + "id": { + "type": "keyword" + }, "labels": { - "include_in_parent": true, "type": "nested" } } @@ -19,16 +21,11 @@ "include_in_parent": true, "properties": { "identity": { - "type": "nested", - "include_in_parent": true - }, - "affiliations": { "type": "nested", "include_in_parent": true, "properties": { - "labels": { - "type": "nested", - "include_in_parent": true + "id": { + "type": "keyword" } } } @@ -42,9 +39,8 @@ "type": "nested", "include_in_parent": true, "properties": { - "pages": { - "type": "nested", - "include_in_parent": true + "type": { + "type": "keyword" } } }, @@ -52,9 +48,29 @@ "type": "nested", "include_in_parent": true, "properties": { + "id": { + "type": "keyword" + }, + "identifier": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, "publisher": { "type": "nested", - "include_in_parent": true + "include_in_parent": true, + "properties": { + "id": { + "type": "keyword" + }, + "identifier": { + "type": "keyword" + }, + "name": { + "type": "keyword" + } + } } } } @@ -70,6 +86,9 @@ "type": "nested", "include_in_parent": true, "properties": { + "identifier": { + "type": "keyword" + }, "labels": { "type": "nested", "include_in_parent": true @@ -92,7 +111,15 @@ }, "associatedArtifacts": { "type": "nested", - "include_in_parent": true + "include_in_parent": true, + "properties": { + "identifier": { + "type": "keyword" + }, + "name": { + "type": "keyword" + } + } } } } diff --git a/search-resources-api/src/main/java/no/unit/nva/search2/ImportCandidatePagedSearchHandlerAws.java b/search-resources-api/src/main/java/no/unit/nva/search2/ImportCandidatePagedSearchHandlerAws.java index 0026830f3..526ff3c84 100644 --- a/search-resources-api/src/main/java/no/unit/nva/search2/ImportCandidatePagedSearchHandlerAws.java +++ b/search-resources-api/src/main/java/no/unit/nva/search2/ImportCandidatePagedSearchHandlerAws.java @@ -2,9 +2,9 @@ import static no.unit.nva.search2.ImportCandidateClient.defaultClient; import static no.unit.nva.search2.constant.Defaults.DEFAULT_RESPONSE_MEDIA_TYPES; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.FROM; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.SIZE; -import static no.unit.nva.search2.model.ParameterKeyImportCandidate.SORT; +import static no.unit.nva.search2.enums.ImportCandidateParameter.FROM; +import static no.unit.nva.search2.enums.ImportCandidateParameter.SIZE; +import static no.unit.nva.search2.enums.ImportCandidateParameter.SORT; import com.amazonaws.services.lambda.runtime.Context; import com.google.common.net.MediaType; import java.net.HttpURLConnection; diff --git a/search-resources-api/src/main/java/no/unit/nva/search2/ResourcePagedSearchHandlerAws.java b/search-resources-api/src/main/java/no/unit/nva/search2/ResourcePagedSearchHandlerAws.java index 6ef1fde5a..19071519e 100644 --- a/search-resources-api/src/main/java/no/unit/nva/search2/ResourcePagedSearchHandlerAws.java +++ b/search-resources-api/src/main/java/no/unit/nva/search2/ResourcePagedSearchHandlerAws.java @@ -2,9 +2,9 @@ import static no.unit.nva.search2.ResourceClient.defaultClient; import static no.unit.nva.search2.constant.Defaults.DEFAULT_RESPONSE_MEDIA_TYPES; -import static no.unit.nva.search2.model.ParameterKeyResource.FROM; -import static no.unit.nva.search2.model.ParameterKeyResource.SIZE; -import static no.unit.nva.search2.model.ParameterKeyResource.SORT; +import static no.unit.nva.search2.enums.ResourceParameter.FROM; +import static no.unit.nva.search2.enums.ResourceParameter.SIZE; +import static no.unit.nva.search2.enums.ResourceParameter.SORT; import com.amazonaws.services.lambda.runtime.Context; import com.google.common.net.MediaType; import java.net.HttpURLConnection; diff --git a/search-resources-api/src/test/java/no/unit/nva/search/SearchResourcesApiHandlerTest.java b/search-resources-api/src/test/java/no/unit/nva/search/SearchResourceParameterApiHandlerTest.java similarity index 99% rename from search-resources-api/src/test/java/no/unit/nva/search/SearchResourcesApiHandlerTest.java rename to search-resources-api/src/test/java/no/unit/nva/search/SearchResourceParameterApiHandlerTest.java index 94a3bf3a2..227cdc5b6 100644 --- a/search-resources-api/src/test/java/no/unit/nva/search/SearchResourcesApiHandlerTest.java +++ b/search-resources-api/src/test/java/no/unit/nva/search/SearchResourceParameterApiHandlerTest.java @@ -50,7 +50,7 @@ import org.opensearch.client.RestHighLevelClient; import org.zalando.problem.Problem; -public class SearchResourcesApiHandlerTest { +public class SearchResourceParameterApiHandlerTest { public static final String SAMPLE_SEARCH_TERM = "searchTerm"; public static final String SAMPLE_OPENSEARCH_RESPONSE_WITH_AGGREGATION_JSON = "sample_opensearch_response.json"; diff --git a/search-resources-api/src/test/java/no/unit/nva/search2/ImportCandidatePagedSearchHandlerAwsTest.java b/search-resources-api/src/test/java/no/unit/nva/search2/ImportCandidatePagedSearchHandlerAwsTest.java index 3c2d803c7..000ca9630 100644 --- a/search-resources-api/src/test/java/no/unit/nva/search2/ImportCandidatePagedSearchHandlerAwsTest.java +++ b/search-resources-api/src/test/java/no/unit/nva/search2/ImportCandidatePagedSearchHandlerAwsTest.java @@ -2,9 +2,9 @@ import static java.net.HttpURLConnection.HTTP_OK; import static java.util.Objects.nonNull; -import static no.unit.nva.search2.constant.ApplicationConstants.COMMA; import static no.unit.nva.search2.constant.Defaults.objectMapperWithEmpty; -import static no.unit.nva.search2.model.ParameterKeyResource.SEARCH_ALL; +import static no.unit.nva.search2.constant.Words.COMMA; +import static no.unit.nva.search2.enums.ImportCandidateParameter.SEARCH_ALL; import static no.unit.nva.testutils.RandomDataGenerator.randomString; import static no.unit.nva.testutils.RandomDataGenerator.randomUri; import static nva.commons.core.ioutils.IoUtils.stringFromResources; @@ -31,8 +31,8 @@ import no.unit.nva.indexing.testutils.FakeSearchResponse; import no.unit.nva.search.ExportCsv; import no.unit.nva.search.common.FakeGatewayResponse; -import no.unit.nva.search2.model.OpenSearchSwsResponse; -import no.unit.nva.search2.model.PagedSearchDto; +import no.unit.nva.search2.common.SwsResponse; +import no.unit.nva.search2.dto.PagedSearch; import no.unit.nva.testutils.HandlerRequestBuilder; import nva.commons.apigateway.GatewayResponse; import nva.commons.core.Environment; @@ -242,7 +242,7 @@ private ObjectNode getRequestContext() { private void prepareRestHighLevelClientOkResponse(List exportCsvs) throws IOException { var jsonResponse = FakeSearchResponse.generateSearchResponseString(exportCsvs); - var body = objectMapperWithEmpty.readValue(jsonResponse, OpenSearchSwsResponse.class); + var body = objectMapperWithEmpty.readValue(jsonResponse, SwsResponse.class); when(mockedSearchClient.doSearch(any())) .thenReturn(body); @@ -252,7 +252,7 @@ private void prepareRestHighLevelClientOkResponse(List exportCsvs) th private void prepareRestHighLevelClientOkResponse() throws IOException { var jsonResponse = stringFromResources(Path.of(SAMPLE_OPENSEARCH_RESPONSE_WITH_AGGREGATION_JSON)); - var body = objectMapperWithEmpty.readValue(jsonResponse, OpenSearchSwsResponse.class); + var body = objectMapperWithEmpty.readValue(jsonResponse, SwsResponse.class); when(mockedSearchClient.doSearch(any())) .thenReturn(body); @@ -260,7 +260,7 @@ private void prepareRestHighLevelClientOkResponse() throws IOException { private void prepareRestHighLevelClientEmptyResponse() throws IOException { var jsonResponse = stringFromResources(Path.of(EMPTY_OPENSEARCH_RESPONSE_JSON)); - var body = objectMapperWithEmpty.readValue(jsonResponse, OpenSearchSwsResponse.class); + var body = objectMapperWithEmpty.readValue(jsonResponse, SwsResponse.class); when(mockedSearchClient.doSearch(any())) .thenReturn(body); @@ -268,15 +268,15 @@ private void prepareRestHighLevelClientEmptyResponse() throws IOException { private void prepareRestHighLevelClientEmptyResponseForSortOrder() throws IOException { var jsonResponse = stringFromResources(Path.of(EMPTY_OPENSEARCH_RESPONSE_JSON)); - var body = objectMapperWithEmpty.readValue(jsonResponse, OpenSearchSwsResponse.class); + var body = objectMapperWithEmpty.readValue(jsonResponse, SwsResponse.class); when(mockedSearchClient.doSearch(any())) .thenReturn(body); } - private PagedSearchDto getSearchResourcesResponseFromFile(String filename) + private PagedSearch getSearchResourcesResponseFromFile(String filename) throws JsonProcessingException { - return objectMapperWithEmpty.readValue(stringFromResources(Path.of(filename)), PagedSearchDto.class); + return objectMapperWithEmpty.readValue(stringFromResources(Path.of(filename)), PagedSearch.class); } public static Stream acceptHeaderValuesProducingTextCsvProvider() { diff --git a/search-resources-api/src/test/java/no/unit/nva/search2/ResourcePagedSearchHandlerAwsTest.java b/search-resources-api/src/test/java/no/unit/nva/search2/ResourcePagedSearchHandlerAwsTest.java index b464ed2ab..c7724cee0 100644 --- a/search-resources-api/src/test/java/no/unit/nva/search2/ResourcePagedSearchHandlerAwsTest.java +++ b/search-resources-api/src/test/java/no/unit/nva/search2/ResourcePagedSearchHandlerAwsTest.java @@ -2,9 +2,9 @@ import static java.net.HttpURLConnection.HTTP_OK; import static java.util.Objects.nonNull; -import static no.unit.nva.search2.constant.ApplicationConstants.COMMA; import static no.unit.nva.search2.constant.Defaults.objectMapperWithEmpty; -import static no.unit.nva.search2.model.ParameterKeyResource.SEARCH_ALL; +import static no.unit.nva.search2.constant.Words.COMMA; +import static no.unit.nva.search2.enums.ResourceParameter.SEARCH_ALL; import static no.unit.nva.testutils.RandomDataGenerator.randomString; import static no.unit.nva.testutils.RandomDataGenerator.randomUri; import static nva.commons.core.ioutils.IoUtils.stringFromResources; @@ -31,8 +31,8 @@ import no.unit.nva.indexing.testutils.FakeSearchResponse; import no.unit.nva.search.ExportCsv; import no.unit.nva.search.common.FakeGatewayResponse; -import no.unit.nva.search2.model.OpenSearchSwsResponse; -import no.unit.nva.search2.model.PagedSearchDto; +import no.unit.nva.search2.common.SwsResponse; +import no.unit.nva.search2.dto.PagedSearch; import no.unit.nva.testutils.HandlerRequestBuilder; import nva.commons.apigateway.GatewayResponse; import nva.commons.core.Environment; @@ -245,7 +245,7 @@ private ObjectNode getRequestContext() { private void prepareRestHighLevelClientOkResponse(List exportCsvs) throws IOException { var jsonResponse = FakeSearchResponse.generateSearchResponseString(exportCsvs); - var body = objectMapperWithEmpty.readValue(jsonResponse, OpenSearchSwsResponse.class); + var body = objectMapperWithEmpty.readValue(jsonResponse, SwsResponse.class); when(mockedSearchClient.doSearch(any())) .thenReturn(body); @@ -256,7 +256,7 @@ private void prepareRestHighLevelClientOkResponse(List exportCsvs) th private void prepareRestHighLevelClientOkResponse() throws IOException { var jsonResponse = stringFromResources(Path.of(SAMPLE_OPENSEARCH_RESPONSE_WITH_AGGREGATION_JSON)); - var body = objectMapperWithEmpty.readValue(jsonResponse, OpenSearchSwsResponse.class); + var body = objectMapperWithEmpty.readValue(jsonResponse, SwsResponse.class); when(mockedSearchClient.doSearch(any())) .thenReturn(body); @@ -264,7 +264,7 @@ private void prepareRestHighLevelClientOkResponse() throws IOException { private void prepareRestHighLevelClientEmptyResponse() throws IOException { var jsonResponse = stringFromResources(Path.of(EMPTY_OPENSEARCH_RESPONSE_JSON)); - var body = objectMapperWithEmpty.readValue(jsonResponse, OpenSearchSwsResponse.class); + var body = objectMapperWithEmpty.readValue(jsonResponse, SwsResponse.class); when(mockedSearchClient.doSearch(any())) .thenReturn(body); @@ -272,15 +272,15 @@ private void prepareRestHighLevelClientEmptyResponse() throws IOException { private void prepareRestHighLevelClientEmptyResponseForSortOrder() throws IOException { var jsonResponse = stringFromResources(Path.of(EMPTY_OPENSEARCH_RESPONSE_JSON)); - var body = objectMapperWithEmpty.readValue(jsonResponse, OpenSearchSwsResponse.class); + var body = objectMapperWithEmpty.readValue(jsonResponse, SwsResponse.class); when(mockedSearchClient.doSearch(any())) .thenReturn(body); } - private PagedSearchDto getSearchResourcesResponseFromFile(String filename) + private PagedSearch getSearchResourcesResponseFromFile(String filename) throws JsonProcessingException { - return objectMapperWithEmpty.readValue(stringFromResources(Path.of(filename)), PagedSearchDto.class); + return objectMapperWithEmpty.readValue(stringFromResources(Path.of(filename)), PagedSearch.class); } public static Stream acceptHeaderValuesProducingTextCsvProvider() { diff --git a/search-testing/src/main/java/no/unit/nva/search/common/FakeGatewayResponse.java b/search-testing/src/main/java/no/unit/nva/search/common/FakeGatewayResponse.java index e189fb4de..2337561be 100644 --- a/search-testing/src/main/java/no/unit/nva/search/common/FakeGatewayResponse.java +++ b/search-testing/src/main/java/no/unit/nva/search/common/FakeGatewayResponse.java @@ -7,8 +7,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.Map; -import no.unit.nva.search2.model.OpenSearchSwsResponse; -import no.unit.nva.search2.model.PagedSearchDto; +import no.unit.nva.search2.common.SwsResponse; +import no.unit.nva.search2.dto.PagedSearch; @SuppressWarnings("PMD.ShortMethodName") public record FakeGatewayResponse( @@ -16,16 +16,16 @@ public record FakeGatewayResponse( int statusCode, Map headers) { - public static FakeGatewayResponse ofSwsGatewayResponse(InputStream inputStream) + public static FakeGatewayResponse ofSwsGatewayResponse(InputStream inputStream) throws IOException { - var typeReference = new TypeReference>() { + var typeReference = new TypeReference>() { }; return dtoObjectMapper.readValue(inputStream, typeReference); } - public static FakeGatewayResponse of(OutputStream outputStream) throws IOException { + public static FakeGatewayResponse of(OutputStream outputStream) throws IOException { var response = ofString(outputStream); - var typeReference2 = new TypeReference() { + var typeReference2 = new TypeReference() { }; var body = dtoObjectMapper.readValue(response.body(), typeReference2); return new FakeGatewayResponse<>(