package com.cadrlife.devsearch.esplugin.service;
import com.cadrlife.devsearch.domain.*;
import com.cadrlife.devsearch.esplugin.domain.GroupedSearchResult;
import com.cadrlife.devsearch.esplugin.domain.SearchResultItem;
import com.cadrlife.devsearch.esplugin.domain.SearchResultItemGroup;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.base.*;
import org.elasticsearch.common.base.Objects;
import org.elasticsearch.common.collect.*;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.facet.terms.TermsFacet;
import java.util.*;
public class SearchResource {
private CodeSearchIndexService indexService;
private static final ESLogger LOG = ESLoggerFactory.getLogger(SearchResource.class.getName());
@Inject
public SearchResource(CodeSearchIndexService indexService) {
this.indexService = indexService;
}
public GroupedSearchResult getGrouped(String query, String groupBy, String limitParam, String repo, String extension) {
Preconditions.checkState(!Strings.isNullOrEmpty(query), "query parameter 'q' must be specified");
Preconditions.checkState("project".equals(groupBy), "Can only group by project");
// int page = Integer.parseInt(Objects.firstNonNull(request.param("page"),"0"));
// TODO: This data is in scope three different times here.
// Suboptimal if results are big.
SearchResponse searchResponse = indexService.search(query, 0, parseLimit(limitParam), repo, extension);
LOG.info("{} hits for query '{}'", searchResponse.getHits().getHits().length, query);
final ListMultimap<Project, SearchResultItem> resultsByProject = newArrayListMultimap(); ;
GroupedSearchResult searchResult = new GroupedSearchResult();
searchResult.setQuery(query);
searchResult.setFileTypeCounts(extractFacet(searchResponse.getFacets().facet(TermsFacet.class, "extension")));
searchResult.setRepoCounts(extractFacet(searchResponse.getFacets().facet(TermsFacet.class, "repo")));
for (SearchHit hit : searchResponse.getHits().getHits()) {
SearchResultItem resultItem = hitToResultItem(hit);
Project project = new Project().setName(resultItem.getProject()).setRepo(resultItem.getRepo());
resultsByProject.put(project, resultItem);
// searchResult.getItemsByProject().add(new SearchResultItemGroup().setProject(project).setItems(Lists.newArrayList(resultItem)));
}
searchResult.setItemsByProject(FluentIterable
.from(resultsByProject.keySet())
.transform(new Function<Project, SearchResultItemGroup>() {
public SearchResultItemGroup apply(Project project) {
return new SearchResultItemGroup()
.setProject(project)
.setItems(resultsByProject.get(project));
}
}).toList());
searchResult.setTotalHits(searchResponse.getHits().getTotalHits());
searchResult.setTotalProjectHits(searchResult.getItemsByProject().size());
// LOG.info("Results grouped");
return searchResult;
}
private Map<String,Long> extractFacet(TermsFacet extensionFacet) {
final Map<String,Long> countMap = new HashMap<>();
for (TermsFacet.Entry entry : extensionFacet.getEntries()) {
countMap.put(entry.getTerm().string(), (long) entry.getCount());
}
return countMap;
}
private ListMultimap<Project, SearchResultItem> newArrayListMultimap() {
return Multimaps
.newListMultimap(
new HashMap<Project, Collection<SearchResultItem>>(),
new Supplier<List<SearchResultItem>>() {
@Override
public List<SearchResultItem> get() {
return Lists.newArrayList();
}
});
}
public List<SearchResultItem> getUngrouped(String query, String searchField, String limitParam) {
Preconditions.checkState(!Strings.isNullOrEmpty(query), "query parameter 'q' must be specified");
SearchResponse searchResponse = Strings.isNullOrEmpty(searchField) ?
indexService.search(query, 0, parseLimit(limitParam), "", "") :
indexService.searchWithinField(query, searchField, 0, parseLimit(limitParam));
LOG.info("{} hits for query '{}'", searchResponse.getHits().getHits().length, query);
// final ListMultimap<Project, SearchResultItem> resultsByProject = newArrayListMultimap();
GroupedSearchResult searchResult = new GroupedSearchResult();
searchResult.setQuery(query);
List<SearchResultItem> items = new ArrayList<SearchResultItem>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
items.add(hitToResultItem(hit));
}
return items;
}
private int parseLimit(String limitParam) {
return Integer.parseInt(Objects.firstNonNull(limitParam, "10000"));
}
private SearchResultItem hitToResultItem(SearchHit hit) {
SearchResultItem item = new SearchResultItem();
String filePath = hit.getSource().get("filePath").toString();
String baseFilename = hit.getSource().get("baseFilename").toString();
String project = hit.getSource().get("project").toString();
String repo = hit.getSource().get("repo").toString();
item.setFilePath(filePath);
item.setBaseFilename(baseFilename);
item.setProject(project);
item.setRepo(repo);
try {
String contentFragment = hit.getHighlightFields().get("content").fragments()[0].string();
item.setPreview(contentFragment);
} catch (Exception e) {
}
return item;
}
}