aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
commit72231250ed81e10d66bfe70701e64fa5fe50f712 (patch)
tree2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java
Publish
Diffstat (limited to 'container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java')
-rw-r--r--container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java177
1 files changed, 177 insertions, 0 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java b/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java
new file mode 100644
index 00000000000..00e154d460b
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java
@@ -0,0 +1,177 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.pagetemplates.engine;
+
+import com.yahoo.search.Result;
+import com.yahoo.search.pagetemplates.PageTemplate;
+import com.yahoo.search.pagetemplates.model.*;
+import com.yahoo.search.pagetemplates.result.SectionHitGroup;
+import com.yahoo.search.query.Sorting;
+import com.yahoo.search.result.*;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Reorganizes and prunes a result as prescribed by a resolved template.
+ * This class is multithread safe.
+ *
+ * @author <a href="mailto:bratseth@yahoo-inc.com">Jon Bratseth</a>
+ */
+public class Organizer {
+
+ /**
+ * Organizes the given result
+ *
+ * @param templateChoice a choice between singleton lists of PageTemplates
+ * @param resolution the resolution of (at least) the template choice and all choices contained in that template
+ * @param result the result to organize
+ */
+ public void organize(Choice templateChoice, Resolution resolution, Result result) {
+ PageTemplate template=(PageTemplate)templateChoice.get(resolution.getResolution(templateChoice)).get(0);
+ SectionHitGroup sectionGroup =toGroup(template.getSection(),resolution,result);
+ ErrorHit errors=result.hits().getErrorHit();
+
+ // transfer state from existing hit
+ sectionGroup.setQuery(result.hits().getQuery());
+ if (errors!=null && errors instanceof DefaultErrorHit)
+ sectionGroup.add((DefaultErrorHit)errors);
+ for (Iterator<Map.Entry<String, Object>> it = result.hits().fieldIterator(); it.hasNext(); ) {
+ Map.Entry<String, Object> field = it.next();
+ sectionGroup.setField(field.getKey(), field.getValue());
+ }
+
+ result.setHits(sectionGroup);
+ }
+
+ /** Creates the hit group corresponding to a section, drawing data from the given result */
+ private SectionHitGroup toGroup(Section section,Resolution resolution,Result result) {
+ SectionHitGroup sectionGroup=new SectionHitGroup("section:" + section.getId());
+ setField("id",section.getId(),sectionGroup);
+ sectionGroup.setLeaf(section.elements(Section.class).size()==0);
+ setField("layout",section.getLayout().getName(),sectionGroup);
+ setField("region",section.getRegion(),sectionGroup);
+
+ List<String> sourceList=new ArrayList<>();
+ renderElements(resolution, result, sectionGroup, sourceList, section.elements());
+
+ // Trim to max
+ if (section.getMax()>=0)
+ sectionGroup.trim(0,section.getMax());
+ if (sectionGroup.size()>1)
+ assignOrderer(section,resolution,sourceList,sectionGroup);
+
+ return sectionGroup;
+ }
+
+ private void renderElements(Resolution resolution, Result result, SectionHitGroup sectionGroup, List<String> sourceList, List<PageElement> elements) {
+ for (PageElement element : elements) {
+ if (element instanceof Section) {
+ sectionGroup.add(toGroup((Section)element,resolution,result));
+ }
+ else if (element instanceof Source) {
+ addSource(resolution,(Source)element,sectionGroup,result,sourceList);
+ }
+ else if (element instanceof Renderer) {
+ sectionGroup.renderers().add((Renderer)element);
+ }
+ else if (element instanceof Choice) {
+ Choice choice=(Choice)element;
+ if (choice.isEmpty()) continue; // Ignore
+ int chosen=resolution.getResolution(choice);
+ renderElements(resolution, result, sectionGroup, sourceList, choice.alternatives().get(chosen));
+ }
+ else if (element instanceof Placeholder) {
+ Placeholder placeholder =(Placeholder)element;
+ List<PageElement> mappedElements=
+ resolution.getResolution(placeholder.getValueContainer()).get(placeholder.getId());
+ renderElements(resolution,result,sectionGroup,sourceList,mappedElements);
+ }
+ }
+ }
+
+ private void setField(String fieldName,Object value,Hit to) {
+ if (value==null) return;
+ to.setField(fieldName,value);
+ }
+
+ private void addSource(Resolution resolution,Source source,SectionHitGroup sectionGroup,Result result,List<String> sourceList) {
+ renderElements(resolution,result,sectionGroup, sourceList, source.renderers());
+ /*
+ for (PageElement element : source.renderers()) {
+ if (element instanceof Renderer)
+ if (renderer.isEmpty()) continue;
+ sectionGroup.renderers().add(renderer.get(resolution.getResolution(renderer)));
+ }
+ */
+
+ if (source.getUrl()==null)
+ addHitsFromSource(source,sectionGroup,result,sourceList);
+ else
+ sectionGroup.sources().add(source); // source to be rendered by the frontend
+ }
+
+ private void addHitsFromSource(Source source,SectionHitGroup sectionGroup,Result result,List<String> sourceList) {
+ if (source==Source.any) { // Add any source not added yet
+ for (Hit hit : result.hits()) {
+ if ( ! (hit instanceof HitGroup)) continue;
+ String groupId=hit.getId().stringValue();
+ if ( ! groupId.startsWith("source:")) continue;
+ String sourceName=groupId.substring(7);
+ if (sourceList.contains(sourceName)) continue;
+ sectionGroup.addAll(((HitGroup)hit).asList());
+ sourceList.add(sourceName); // Add *'ed sources explicitly
+ }
+ }
+ else {
+ HitGroup sourceGroup=(HitGroup)result.hits().get("source:" + source.getName());
+ if (sourceGroup!=null)
+ sectionGroup.addAll(sourceGroup.asList());
+ sourceList.add(source.getName()); // Add even if not found - may be added later
+ }
+ }
+
+ private void assignOrderer(Section section,Resolution resolution,List<String> sourceList,HitGroup group) {
+ if (section.getOrder()==null) { // then sort by relevance, source
+ group.setOrderer(new HitSortOrderer(new RelevanceComparator(new SourceOrderComparator(sourceList))));
+ return;
+ }
+
+ // replace a source field comparison by one which knows the source list order
+ // and add default sorting at the end if necessary
+ Sorting sorting=section.getOrder();
+ int rankIndex=-1;
+ int sourceIndex=-1;
+ for (int i=0; i<sorting.fieldOrders().size(); i++) {
+ Sorting.FieldOrder order=sorting.fieldOrders().get(i);
+ if ("[relevance]".equals(order.getFieldName()) || "[rank]".equals(order.getFieldName()))
+ rankIndex=i;
+ else if (order.getFieldName().equals("[source]"))
+ sourceIndex=i;
+ }
+
+ ChainableComparator comparator;
+ Sorting beforeSource=null;
+ Sorting afterSource=null;
+ if (sourceIndex>=0) { // replace alphabetical sorting on source by sourceList order sorting
+ if (sourceIndex>0) // sort fields before the source
+ beforeSource=new Sorting(new ArrayList<>(sorting.fieldOrders().subList(0,sourceIndex)));
+ if (sorting.fieldOrders().size()>sourceIndex+1) // sort fields after the source
+ afterSource=new Sorting(new ArrayList<>(sorting.fieldOrders().subList(sourceIndex+1,sorting.fieldOrders().size()+1)));
+
+ comparator=new SourceOrderComparator(sourceList, FieldComparator.create(afterSource));
+ if (beforeSource!=null)
+ comparator=new FieldComparator(beforeSource,comparator);
+
+ }
+ else if (rankIndex>=0) { // add sort by source at the end
+ comparator=new FieldComparator(sorting,new SourceOrderComparator(sourceList));
+ }
+ else { // add sort by rank,source at the end
+ comparator=new FieldComparator(sorting,new RelevanceComparator(new SourceOrderComparator(sourceList)));
+ }
+ group.setOrderer(new HitSortOrderer(comparator));
+ }
+
+}