1
1
mirror of https://github.com/MarginaliaSearch/MarginaliaSearch.git synced 2025-10-06 07:32:38 +02:00
Files
MarginaliaSearch/code/services-application/api-service/java/nu/marginalia/api/ApiSearchOperator.java

108 lines
3.7 KiB
Java

package nu.marginalia.api;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import nu.marginalia.api.model.ApiSearchResult;
import nu.marginalia.api.model.ApiSearchResultQueryDetails;
import nu.marginalia.api.model.ApiSearchResults;
import nu.marginalia.api.searchquery.QueryClient;
import nu.marginalia.api.searchquery.RpcQueryLimits;
import nu.marginalia.api.searchquery.model.query.NsfwFilterTier;
import nu.marginalia.api.searchquery.model.query.QueryParams;
import nu.marginalia.api.searchquery.model.query.SearchSetIdentifier;
import nu.marginalia.api.searchquery.model.results.DecoratedSearchResultItem;
import nu.marginalia.model.idx.WordFlags;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Singleton
public class ApiSearchOperator {
private final QueryClient queryClient;
@Inject
public ApiSearchOperator(QueryClient queryClient) {
this.queryClient = queryClient;
}
public ApiSearchResults query(String query,
int count,
int index,
NsfwFilterTier filterTier)
{
var rsp = queryClient.search(createParams(query, count, index, filterTier));
return new ApiSearchResults("RESTRICTED", query,
rsp.results()
.stream()
.map(this::convert)
.sorted(Comparator.comparing(ApiSearchResult::getQuality))
.limit(count)
.collect(Collectors.toList()));
}
private QueryParams createParams(String query, int count, int index, NsfwFilterTier filterTirer) {
SearchSetIdentifier searchSet = selectSearchSet(index);
return new QueryParams(
query,
RpcQueryLimits.newBuilder()
.setResultsByDomain(2)
.setResultsTotal(Math.min(100, count))
.setTimeoutMs(150)
.setFetchSize(8192)
.build(),
searchSet.name(),
filterTirer);
}
private SearchSetIdentifier selectSearchSet(int index) {
return switch (index) {
case 0 -> SearchSetIdentifier.NONE;
case 1 -> SearchSetIdentifier.SMALLWEB;
case 2 -> SearchSetIdentifier.POPULAR;
case 3 -> SearchSetIdentifier.NONE;
case 5 -> SearchSetIdentifier.NONE;
default -> SearchSetIdentifier.NONE;
};
}
ApiSearchResult convert(DecoratedSearchResultItem url) {
List<List<ApiSearchResultQueryDetails>> details = new ArrayList<>();
// This list-of-list construction is to avoid breaking the API,
// we'll always have just a single outer list from now on...
if (url.rawIndexResult != null) {
List<ApiSearchResultQueryDetails> lst = new ArrayList<>();
for (var entry : url.rawIndexResult.keywordScores) {
Set<String> flags = WordFlags.decode(entry.flags).stream().map(Object::toString).collect(Collectors.toSet());
lst.add(new ApiSearchResultQueryDetails(entry.keyword, entry.positionCount, flags));
}
details.add(lst);
}
return new ApiSearchResult(
url.url.toString(),
url.getTitle(),
url.getDescription(),
sanitizeNaN(url.rankingScore, -100),
url.getShortFormat(),
details
);
}
private double sanitizeNaN(double value, double alternative) {
if (!Double.isFinite(value)) {
return alternative;
}
return value;
}
}