Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable users to simultaneously search all SearchBasedFetchers #6504

Merged
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
703d000
Add CompositeSearchBasedFetcher to offer the option to query all libr…
DominikVoigt May 19, 2020
3045da1
Add Test for CompositeSearchBasedFetcher.
DominikVoigt May 19, 2020
c6838a5
Reformat stream to increase readability.
DominikVoigt May 20, 2020
81c4d81
Add CHANGELOG entry under Added.
DominikVoigt May 20, 2020
a6cf33a
Add Linebreak to CHANGELOG.
DominikVoigt May 20, 2020
abf4701
Add Linebreak to CompositeSearchBasedFetcherTest to fix checkstyle is…
DominikVoigt May 21, 2020
51ec020
Update CHANGELOG.md
DominikVoigt May 22, 2020
55ac9be
Add parameterized tests for CompositeSearchBasedFetcher.
DominikVoigt May 23, 2020
c3c0b65
Add better parameterized test naming.
DominikVoigt May 23, 2020
7fa24e4
Implement requested change.
DominikVoigt May 24, 2020
1947b1f
Merge branch 'feature/add-option-to-fetch-from-all-sources' of https:…
DominikVoigt May 24, 2020
836fc31
Merge branch 'master' into feature/add-option-to-fetch-from-all-sources
DominikVoigt May 25, 2020
1acd5aa
Remove GrobidCitationFetcher from test set as it was removed from set…
DominikVoigt May 25, 2020
da09f97
Add null check for CompositeSearchBasedFetcher.
DominikVoigt May 25, 2020
f07fa33
Modify Stream of Arguments according to recommendation.
DominikVoigt May 27, 2020
2c70b3f
Change size of inkrement from 3 to 273 due to too many test arguments…
DominikVoigt May 27, 2020
7d2b006
Merge branch 'master' into feature/add-option-to-fetch-from-all-sources
DominikVoigt May 27, 2020
5f446c1
Reformat steam operators.
DominikVoigt May 27, 2020
d9454c5
Merge branch 'master' into feature/add-option-to-fetch-from-all-sources
koppor May 27, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
- We fixed the bug when strike the delete key in the text field. [#6421](https://github.com/JabRef/jabref/issues/6421)
- We added a BibTex key modifier for truncating strings. [#3915](https://github.com/JabRef/jabref/issues/3915)
- We added support for jumping to target entry when typing letter/digit after sorting a column in maintable [#6146](https://github.com/JabRef/jabref/issues/6146)
- We added a new fetcher to enable users to search all available E-Libraries simultaneously. [koppor#369](https://github.com/koppor/jabref/issues/369)

### Changed

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/jabref/logic/importer/WebFetchers.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.jabref.logic.importer.fetcher.ArXiv;
import org.jabref.logic.importer.fetcher.AstrophysicsDataSystem;
import org.jabref.logic.importer.fetcher.CiteSeer;
import org.jabref.logic.importer.fetcher.CompositeSearchBasedFetcher;
import org.jabref.logic.importer.fetcher.CrossRef;
import org.jabref.logic.importer.fetcher.DBLPFetcher;
import org.jabref.logic.importer.fetcher.DOAJFetcher;
Expand Down Expand Up @@ -99,6 +100,7 @@ public static SortedSet<SearchBasedFetcher> getSearchBasedFetchers(ImportFormatP
set.add(new CiteSeer());
set.add(new DOAJFetcher(importFormatPreferences));
set.add(new IEEE(importFormatPreferences));
set.add(new CompositeSearchBasedFetcher(set, 30));
return set;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.jabref.logic.importer.fetcher;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.jabref.logic.help.HelpFile;
import org.jabref.logic.importer.FetcherException;
import org.jabref.logic.importer.SearchBasedFetcher;
import org.jabref.model.entry.BibEntry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CompositeSearchBasedFetcher implements SearchBasedFetcher {

private static final Logger LOGGER = LoggerFactory.getLogger(CompositeSearchBasedFetcher.class);

private final Set<SearchBasedFetcher> fetchers;
private final int maximumNumberOfReturnedResults;

public CompositeSearchBasedFetcher(Set<SearchBasedFetcher> searchBasedFetchers, int maximumNumberOfReturnedResults)
throws IllegalArgumentException {
if (searchBasedFetchers == null) {
throw new IllegalArgumentException("The set of searchBasedFetchers must not be null!");
}
// Remove the Composite Fetcher instance from its own fetcher set to prevent a StackOverflow
this.fetchers = searchBasedFetchers.stream()
.filter(searchBasedFetcher -> searchBasedFetcher != this)
.collect(Collectors.toSet());
this.maximumNumberOfReturnedResults = maximumNumberOfReturnedResults;
}

@Override
public List<BibEntry> performSearch(String query) {
return fetchers.stream().flatMap(searchBasedFetcher -> {
try {
return searchBasedFetcher.performSearch(query).stream();
} catch (FetcherException e) {
LOGGER.warn(String.format("%s API request failed", searchBasedFetcher.getName()), e);
return Stream.empty();
}
}).parallel().limit(maximumNumberOfReturnedResults).collect(Collectors.toList());
}

@Override
public String getName() {
return "SearchAll";
}

@Override
public Optional<HelpFile> getHelpPage() {
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package org.jabref.logic.importer.fetcher;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

import org.jabref.logic.bibtex.FieldContentFormatterPreferences;
import org.jabref.logic.importer.FetcherException;
import org.jabref.logic.importer.ImportFormatPreferences;
import org.jabref.logic.importer.SearchBasedFetcher;
import org.jabref.model.entry.BibEntry;
import org.jabref.testutils.category.FetcherTest;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@FetcherTest
public class CompositeSearchBasedFetcherTest {

private static final Logger LOGGER = LoggerFactory.getLogger(CompositeSearchBasedFetcherTest.class);

@Test
public void createCompositeFetcherWithNullSet() {
Assertions.assertThrows(IllegalArgumentException.class,
() -> new CompositeSearchBasedFetcher(null, 0));
}

@Test
public void performSearchWithoutFetchers() {
Set<SearchBasedFetcher> empty = new HashSet<>();
CompositeSearchBasedFetcher fetcher = new CompositeSearchBasedFetcher(empty, Integer.MAX_VALUE);

List<BibEntry> result = fetcher.performSearch("quantum");

Assertions.assertEquals(result, Collections.EMPTY_LIST);
}

@ParameterizedTest(name = "Perform Search on empty query.")
@MethodSource("performSearchParameters")
public void performSearchOnEmptyQuery(Set<SearchBasedFetcher> fetchers) {
CompositeSearchBasedFetcher compositeFetcher = new CompositeSearchBasedFetcher(fetchers, Integer.MAX_VALUE);

List<BibEntry> queryResult = compositeFetcher.performSearch("");

Assertions.assertEquals(queryResult, Collections.EMPTY_LIST);
}

@ParameterizedTest(name = "Perform search on query \"quantum\". Using the CompositeFetcher of the following " +
"Fetchers: {arguments}")
@MethodSource("performSearchParameters")
public void performSearchOnNonEmptyQuery(Set<SearchBasedFetcher> fetchers) {
CompositeSearchBasedFetcher compositeFetcher = new CompositeSearchBasedFetcher(fetchers, Integer.MAX_VALUE);

List<BibEntry> compositeResult = compositeFetcher.performSearch("quantum");
for (SearchBasedFetcher fetcher : fetchers) {
try {
Assertions.assertTrue(compositeResult.containsAll(fetcher.performSearch("quantum")));
} catch (FetcherException e) {
/* We catch the Fetcher exception here, since the failing fetcher also fails in the CompositeFetcher
* and just leads to no additional results in the returned list. Therefore the test should not fail
* due to the fetcher exception
*/
LOGGER.debug(String.format("Fetcher %s failed ", fetcher.getName()), e);
}
}
}

/**
* This method provides other methods with different sized sets of search-based fetchers wrapped in arguments.
*
* @return A stream of Arguments wrapping set of fetchers.
*/
static Stream<Arguments> performSearchParameters() {
ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class);
when(importFormatPreferences.getFieldContentFormatterPreferences())
.thenReturn(mock(FieldContentFormatterPreferences.class));
List<Set<SearchBasedFetcher>> fetcherParameters = new ArrayList<>();
List<SearchBasedFetcher> list = new ArrayList<>();

list.add(new ArXiv(importFormatPreferences));
list.add(new INSPIREFetcher(importFormatPreferences));
list.add(new GvkFetcher());
list.add(new AstrophysicsDataSystem(importFormatPreferences));
list.add(new MathSciNet(importFormatPreferences));
list.add(new ZbMATH(importFormatPreferences));
list.add(new GoogleScholar(importFormatPreferences));
list.add(new DBLPFetcher(importFormatPreferences));
list.add(new SpringerFetcher());
list.add(new CrossRef());
list.add(new CiteSeer());
list.add(new DOAJFetcher(importFormatPreferences));
list.add(new IEEE(importFormatPreferences));
/* Disabled due to an issue regarding comparison: Title fields of the entries that otherwise are equivalent differ
* due to different JAXBElements.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you provide me the concreete example? Maybe, we need to fix the MedlineFetcher?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK:
When using the same instance of MedlineFetcher to fetch results directly or as part of the CompositeFetcher, certain BibEntries have differing titles due to something related to JAXBElements.
When searching for "Indistinguishable Photons from Deterministically" the direct use of the MedLine Fetcher returns a BibEntry with the title:

title = {Indistinguishable Photons from Deterministically Integrated Single Quantum Dots in Heterogeneous GaAs/Si, javax.xml.bind.JAXBElement@31b82e0f, N, javax.xml.bind.JAXBElement@27a09971, Quantum Photonic Circuits.}

The CompositeFetcher, on the other hand, returns a BibEntry with the title:

title = {Indistinguishable Photons from Deterministically Integrated Single Quantum Dots in Heterogeneous GaAs/Si, javax.xml.bind.JAXBElement@3289079a, N, javax.xml.bind.JAXBElement@32fa809f, Quantum Photonic Circuits.}

Both would be the same only differing by the JAXBElement Instance.

*/
// list.add(new MedlineFetcher());

// Create different sized sets of fetchers to use in the composite fetcher.
// Selected 273 to have differencing sets
for (int i = 1; i < Math.pow(2, list.size()); i += 273) {
Set<SearchBasedFetcher> fetchers = new HashSet<>();
// Only shift i at maximum to its MSB to the right
for (int j = 0; Math.pow(2, j) <= i; j++) {
// Add fetcher j to the list if the j-th bit of i is 1
if ((i >> j) % 2 == 1) {
fetchers.add(list.get(j));
}
}
fetcherParameters.add(fetchers);
}

return fetcherParameters.stream().map(Arguments::of);
}
}