From df80c132f136795cabc8cc8aab3163241cae565a Mon Sep 17 00:00:00 2001 From: Dominik Voigt Date: Sat, 7 Nov 2020 11:30:46 +0100 Subject: [PATCH] Feature/add abstract field to complex search (#7079) --- .../fetcher/WebSearchPaneViewModel.java | 2 +- .../jabref/logic/importer/fetcher/ArXiv.java | 1 + .../importer/fetcher/ComplexSearchQuery.java | 61 +++++++++++++------ .../jabref/logic/importer/fetcher/IEEE.java | 5 +- 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPaneViewModel.java b/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPaneViewModel.java index 773289143f5..beafb11c060 100644 --- a/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPaneViewModel.java +++ b/src/main/java/org/jabref/gui/importer/fetcher/WebSearchPaneViewModel.java @@ -63,7 +63,7 @@ public WebSearchPaneViewModel(ImportFormatPreferences importPreferences, JabRefF preferences.putInt(JabRefPreferences.SELECTED_FETCHER_INDEX, newIndex); }); - String allowedFields = "((author|journal|title|year|year-range):\\s?)?"; + String allowedFields = "((author|abstract|journal|title|year|year-range):\\s?)?"; // Either a single word, or a phrase with quotes, or a year-range String allowedTermText = "(((\\d{4}-\\d{4})|(\\w+)|(\"\\w+[^\"]*\"))\\s?)+"; queryPattern = Pattern.compile("^(" + allowedFields + allowedTermText + ")+$"); diff --git a/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java b/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java index 58c6bbc7498..10ab03b13e5 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/ArXiv.java @@ -266,6 +266,7 @@ public List performComplexSearch(ComplexSearchQuery complexSearchQuery List searchTerms = new ArrayList<>(); complexSearchQuery.getAuthors().forEach(author -> searchTerms.add("au:" + author)); complexSearchQuery.getTitlePhrases().forEach(title -> searchTerms.add("ti:" + title)); + complexSearchQuery.getTitlePhrases().forEach(abstr -> searchTerms.add("abs:" + abstr)); complexSearchQuery.getJournal().ifPresent(journal -> searchTerms.add("jr:" + journal)); // Since ArXiv API does not support year search, we ignore the year related terms complexSearchQuery.getToYear().ifPresent(year -> searchTerms.add(year.toString())); diff --git a/src/main/java/org/jabref/logic/importer/fetcher/ComplexSearchQuery.java b/src/main/java/org/jabref/logic/importer/fetcher/ComplexSearchQuery.java index c442e302f93..750a6d68e46 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/ComplexSearchQuery.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/ComplexSearchQuery.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.StringJoiner; import org.jabref.model.strings.StringUtil; @@ -15,15 +16,17 @@ public class ComplexSearchQuery { private final List defaultField; private final List authors; private final List titlePhrases; + private final List abstractPhrases; private final Integer fromYear; private final Integer toYear; private final Integer singleYear; private final String journal; - private ComplexSearchQuery(List defaultField, List authors, List titlePhrases, Integer fromYear, Integer toYear, Integer singleYear, String journal) { + private ComplexSearchQuery(List defaultField, List authors, List titlePhrases, List abstractPhrases, Integer fromYear, Integer toYear, Integer singleYear, String journal) { this.defaultField = defaultField; this.authors = authors; this.titlePhrases = titlePhrases; + this.abstractPhrases = abstractPhrases; this.fromYear = fromYear; // Some APIs do not support, or not fully support, year based search. In these cases, the non applicable parameters are ignored. this.toYear = toYear; @@ -38,6 +41,7 @@ public static ComplexSearchQuery fromTerms(Collection terms) { switch (term.field().toLowerCase()) { case "author" -> builder.author(termText); case "title" -> builder.titlePhrase(termText); + case "abstract" -> builder.abstractPhrase(termText); case "journal" -> builder.journal(termText); case "year" -> builder.singleYear(Integer.valueOf(termText)); case "year-range" -> builder.parseYearRange(termText); @@ -60,6 +64,10 @@ public List getTitlePhrases() { return titlePhrases; } + public List getAbstractPhrases() { + return abstractPhrases; + } + public Optional getFromYear() { return Optional.ofNullable(fromYear); } @@ -101,6 +109,9 @@ public boolean equals(Object o) { if (!(getTitlePhrases().containsAll(that.getTitlePhrases()) && that.getTitlePhrases().containsAll(getTitlePhrases()))) { return false; } + if (!(getAbstractPhrases().containsAll(that.getAbstractPhrases()) && that.getAbstractPhrases().containsAll(getAbstractPhrases()))) { + return false; + } if (getFromYear().isPresent() ? !getFromYear().equals(that.getFromYear()) : that.getFromYear().isPresent()) { return false; } @@ -115,33 +126,30 @@ public boolean equals(Object o) { @Override public int hashCode() { - int result = defaultField != null ? defaultField.hashCode() : 0; - result = 31 * result + (getAuthors() != null ? getAuthors().hashCode() : 0); - result = 31 * result + (getTitlePhrases() != null ? getTitlePhrases().hashCode() : 0); - result = 31 * result + (getFromYear().isPresent() ? getFromYear().hashCode() : 0); - result = 31 * result + (getToYear().isPresent() ? getToYear().hashCode() : 0); - result = 31 * result + (getSingleYear().isPresent() ? getSingleYear().hashCode() : 0); - result = 31 * result + (getJournal().isPresent() ? getJournal().hashCode() : 0); - return result; + return Objects.hash(defaultField, getAuthors(), getSingleYear(), getAbstractPhrases(), getFromYear(), getToYear(), getTitlePhrases(), getJournal()); } @Override public String toString() { - StringBuilder stringRepresentation = new StringBuilder(); - getSingleYear().ifPresent(singleYear -> stringRepresentation.append(singleYear).append(" ")); - getFromYear().ifPresent(fromYear -> stringRepresentation.append(fromYear).append(" ")); - getToYear().ifPresent(toYear -> stringRepresentation.append(toYear).append(" ")); - getJournal().ifPresent(journal -> stringRepresentation.append(journal).append(" ")); - stringRepresentation.append(String.join(" ", getTitlePhrases())) - .append(String.join(" ", getDefaultFieldPhrases())) - .append(String.join(" ", getAuthors())); - return stringRepresentation.toString(); + StringJoiner stringJoiner = new StringJoiner(" "); + + getSingleYear().ifPresent(singleYear -> stringJoiner.add(singleYear.toString())); + getFromYear().ifPresent(fromYear -> stringJoiner.add(fromYear.toString())); + getToYear().ifPresent(toYear -> stringJoiner.add(toYear.toString())); + getJournal().ifPresent(stringJoiner::add); + stringJoiner.add(String.join(" ", getTitlePhrases())) + .add(String.join(" ", getDefaultFieldPhrases())) + .add(String.join(" ", getAuthors())) + .add(String.join(" ", getAbstractPhrases())); + + return stringJoiner.toString(); } public static class ComplexSearchQueryBuilder { private List defaultFieldPhrases = new ArrayList<>(); private List authors = new ArrayList<>(); private List titlePhrases = new ArrayList<>(); + private List abstractPhrases = new ArrayList<>(); private String journal; private Integer fromYear; private Integer toYear; @@ -183,6 +191,18 @@ public ComplexSearchQueryBuilder titlePhrase(String titlePhrase) { return this; } + /** + * Adds abstract phrase and wraps it in quotes + */ + public ComplexSearchQueryBuilder abstractPhrase(String abstractPhrase) { + if (Objects.requireNonNull(abstractPhrase).isBlank()) { + throw new IllegalArgumentException("Parameter must not be blank"); + } + // Strip all quotes before wrapping + this.titlePhrases.add(String.format("\"%s\"", abstractPhrase.replace("\"", ""))); + return this; + } + public ComplexSearchQueryBuilder fromYearAndToYear(Integer fromYear, Integer toYear) { if (Objects.nonNull(singleYear)) { throw new IllegalArgumentException("You can not use single year and year range search."); @@ -214,6 +234,7 @@ public ComplexSearchQueryBuilder terms(Collection terms) { switch (term.field().toLowerCase()) { case "author" -> this.author(termText); case "title" -> this.titlePhrase(termText); + case "abstract" -> this.abstractPhrase(termText); case "journal" -> this.journal(termText); case "year" -> this.singleYear(Integer.valueOf(termText)); case "year-range" -> this.parseYearRange(termText); @@ -235,7 +256,7 @@ public ComplexSearchQuery build() throws IllegalStateException { if (textSearchFieldsAndYearFieldsAreEmpty()) { throw new IllegalStateException("At least one text field has to be set"); } - return new ComplexSearchQuery(defaultFieldPhrases, authors, titlePhrases, fromYear, toYear, singleYear, journal); + return new ComplexSearchQuery(defaultFieldPhrases, authors, titlePhrases, abstractPhrases, fromYear, toYear, singleYear, journal); } void parseYearRange(String termText) { @@ -259,7 +280,7 @@ void parseYearRange(String termText) { private boolean textSearchFieldsAndYearFieldsAreEmpty() { return this.stringListIsBlank(defaultFieldPhrases) && this.stringListIsBlank(titlePhrases) && - this.stringListIsBlank(authors) && StringUtil.isBlank(journal) && yearFieldsAreEmpty(); + this.stringListIsBlank(authors) && this.stringListIsBlank(abstractPhrases) && StringUtil.isBlank(journal) && yearFieldsAreEmpty(); } private boolean yearFieldsAreEmpty() { diff --git a/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java b/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java index 2b1b0a0f33e..d4329fb3d7d 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java @@ -242,7 +242,10 @@ public URL getComplexQueryURL(ComplexSearchQuery complexSearchQuery) throws URIS if (!complexSearchQuery.getAuthors().isEmpty()) { uriBuilder.addParameter("author", String.join(" AND ", complexSearchQuery.getAuthors())); } - if (!complexSearchQuery.getAuthors().isEmpty()) { + if (!complexSearchQuery.getAbstractPhrases().isEmpty()) { + uriBuilder.addParameter("abstract", String.join(" AND ", complexSearchQuery.getAbstractPhrases())); + } + if (!complexSearchQuery.getTitlePhrases().isEmpty()) { uriBuilder.addParameter("article_title", String.join(" AND ", complexSearchQuery.getTitlePhrases())); } complexSearchQuery.getJournal().ifPresent(journalTitle -> uriBuilder.addParameter("publication_title", journalTitle));