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; } }