Added the possibility to customize facets sort type and direction

Previously search navigators/facets elements were sorted only by counts.
Now from the ConfigSearchPage_p.html admin page, sort direction
(ascending/descending) and type (on counts or labels) can be customized
independently for each navigator.
pull/278/head
luccioman 6 years ago
parent d3a114c7a9
commit 9782a98a9c

@ -932,10 +932,12 @@ search.result.show.ranking = false
# search navigators: comma-separated list of default values for search navigation.
# can be temporary different if search string is given with differen navigation values
# By default navigators keys are sorted by descending counts. To sort by ascending displayed labels, add the :label suffix (example : hosts:label).
# The sort direction can also be specified with the :asc or :desc suffixes (example : hosts:label:desc)
# can be temporary different if search string is given with different navigation values
# assigning no value(s) means that no navigation is shown
search.navigation=location,hosts,authors,namespace,topics,filetype,protocol,language
#search.navigation=location,hosts,authors,namespace,topics,filetype,protocol,language,collections,date,year,year:dates_in_content_dts:Event
#search.navigation=location,hosts:label,authors,namespace,topics,filetype,protocol,language,collections,date,year,year:dates_in_content_dts:Event
# max number of items displayed in search navigators
search.navigation.maxcount=100

@ -139,16 +139,36 @@
#{search.navigation.plugin}#
<tr>
<td><button class="btn btn-xs" title="Delete navigator" aria-label="Delete navigator" aria-describedby="title-#[name]#" name="del.nav" value="#[name]#"><span class="glyphicon glyphicon-remove" style="color: red"></span></button></td>
<td><ul class="nav nav-sidebar menugroup" style="padding-left:15px; padding-right:10px;">
<li><h3 id="title-#[name]#">#[displayname]#</h3></li>
</ul><input type="hidden" name="search.navigation.active" value="#[name]#" />
<td>
<ul class="nav nav-sidebar menugroup" style="padding-left:15px; padding-right:10px;">
<li>
<h3 id="title-#[name]#">#[displayname]#
#(navSort)#<span class="glyphicon glyphicon-sort-by-attributes-alt" title="Sorted by descending counts"></span>
::<span class="glyphicon glyphicon-sort-by-attributes" title="Sorted by ascending counts"></span>
::<span class="glyphicon glyphicon glyphicon-sort-by-alphabet-alt" title="Sorted by descending labels"></span>
::<span class="glyphicon glyphicon-sort-by-alphabet" title="Sorted by ascending labels"></span>
#(/navSort)#
</h3>
</li>
<li>
<label>Sort by
<select name="search.navigation.#[name]#.navSort">
<option value="count:desc" #(navSort)#selected="selected"::#(/navSort)#>Descending counts</option>
<option value="count:asc" #(navSort)#::selected="selected"#(/navSort)#>Ascending counts</option>
<option value="label:desc" #(navSort)#::::selected="selected"#(/navSort)#>Descending labels</option>
<option value="label:asc" #(navSort)#::::::selected="selected"#(/navSort)#>Ascending labels</option>
</select>
</label>
</li>
</ul>
<input type="hidden" name="search.navigation.active" value="#[name]#" />
</td>
</tr>
#{/search.navigation.plugin}#
<tr>
<td></td>
<td><ul class="nav nav-sidebar menugroup" id="vocabulary" style="padding-left:15px; padding-right:10px;">
<li><h3>Vocabulary</h3></li>
<li><h3>Vocabulary <span class="glyphicon glyphicon-sort-by-attributes-alt" title="Sorted by descending counts"></span></h3></li>
</ul></td>
</tr>
<tr>

@ -30,8 +30,10 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import net.yacy.cora.date.GenericFormatter;
import net.yacy.cora.protocol.RequestHeader;
@ -42,7 +44,11 @@ import net.yacy.search.Switchboard;
import net.yacy.search.SwitchboardConstants;
import net.yacy.search.navigator.Navigator;
import net.yacy.search.navigator.NavigatorPlugins;
import net.yacy.search.navigator.NavigatorSort;
import net.yacy.search.navigator.NavigatorSortDirection;
import net.yacy.search.navigator.NavigatorSortType;
import net.yacy.search.query.QueryParams;
import net.yacy.search.query.SearchEventCache;
import net.yacy.server.serverObjects;
import net.yacy.server.serverSwitch;
@ -56,6 +62,10 @@ public class ConfigSearchPage_p {
/* Check this is a valid transaction */
TransactionManager.checkPostTransaction(header, post);
final int initialNavMaxCOunt = sb.getConfigInt(
SwitchboardConstants.SEARCH_NAVIGATION_MAXCOUNT, QueryParams.FACETS_STANDARD_MAXCOUNT_DEFAULT);
final String initialNavConf = sb.getConfig("search.navigation", "");
if (post.containsKey("searchpage_set")) {
final String newGreeting = post.get(SwitchboardConstants.GREETING, "");
// store this call as api call
@ -96,24 +106,33 @@ public class ConfigSearchPage_p {
sb.setConfig("search.result.show.snapshots", post.getBoolean("search.result.show.snapshots"));
// construct navigation String
String nav = "";
if (post.getBoolean("search.navigation.location")) nav += "location,";
// if (post.getBoolean("search.navigation.filetype")) nav += "filetype,";
if (post.getBoolean("search.navigation.protocol")) nav += "protocol,";
// if (post.getBoolean("search.navigation.hosts")) nav += "hosts,";
// if (post.getBoolean("search.navigation.language")) nav += "language,";
// if (post.getBoolean("search.navigation.authors")) nav += "authors,";
// if (post.getBoolean("search.navigation.collections")) nav += "collections,";
// if (post.getBoolean("search.navigation.namespace")) nav += "namespace,";
if (post.getBoolean("search.navigation.topics")) nav += "topics,";
if (post.getBoolean("search.navigation.date")) nav += "date,";
Set<String> navConfigs = new HashSet<>();
if (post.getBoolean("search.navigation.location")) {
navConfigs.add("location");
}
if (post.getBoolean("search.navigation.protocol")) {
navConfigs.add("protocol");
}
if (post.getBoolean("search.navigation.topics")) {
navConfigs.add("topics");
}
if (post.getBoolean("search.navigation.date")) {
navConfigs.add("date");
}
// append active navigator plugins
String[] navplugins = post.getAll("search.navigation.active");
for (String navname:navplugins) {
nav += navname + ",";
String[] activeNavNames = post.getAll("search.navigation.active");
for (final String navName : activeNavNames) {
String navConfig = navName;
final String navSortConfig = post.get("search.navigation." + navName + ".navSort");
final NavigatorSort defaultSort = NavigatorPlugins.getDefaultSort(navName);
if (NavigatorPlugins.parseNavSortConfig(
navName + NavigatorPlugins.NAV_PROPS_CONFIG_SEPARATOR + navSortConfig,
defaultSort) != defaultSort) {
navConfig += NavigatorPlugins.NAV_PROPS_CONFIG_SEPARATOR + navSortConfig;
}
navConfigs.add(navConfig);
}
if (nav.endsWith(",")) nav = nav.substring(0, nav.length() - 1);
sb.setConfig("search.navigation", nav);
sb.setConfig("search.navigation", navConfigs);
// maxcount nav entries, default
int navmaxcnt = post.getInt(SwitchboardConstants.SEARCH_NAVIGATION_MAXCOUNT, QueryParams.FACETS_STANDARD_MAXCOUNT_DEFAULT);
if (navmaxcnt > 5) {
@ -131,16 +150,15 @@ public class ConfigSearchPage_p {
if (post.containsKey("add.nav")) { // button: add navigator plugin to ative list
String navname = post.get("search.navigation.navname");
if (navname != null && !navname.isEmpty()) {
String naviconf = sb.getConfig("search.navigation", "");
naviconf += "," + navname;
sb.setConfig("search.navigation", naviconf);
final Set<String> navConfigs = sb.getConfigSet("search.navigation");
navConfigs.add(navname);
sb.setConfig("search.navigation", navConfigs);
}
} else if (post.containsKey("del.nav")) { // button: delete navigator plugin from active list
String navname = post.get("del.nav");
String naviconf = sb.getConfig("search.navigation", "");
naviconf = naviconf.replace(navname, "");
naviconf = naviconf.replace(",,", ",");
sb.setConfig("search.navigation", naviconf);
final String navToDelete = post.get("del.nav");
final Set<String> navConfigs = sb.getConfigSet("search.navigation");
navConfigs.removeIf(navConfig -> NavigatorPlugins.getNavName(navConfig).equals(navToDelete));
sb.setConfig("search.navigation", navConfigs);
}
if (post.containsKey("searchpage_default")) {
@ -203,6 +221,12 @@ public class ConfigSearchPage_p {
config.getProperty(SwitchboardConstants.SEARCH_NAVIGATION_DATES_MAXCOUNT,
String.valueOf(QueryParams.FACETS_DATE_MAXCOUNT_DEFAULT)));
}
if(!initialNavConf.equals(sb.getConfig("search.navigation", "")) || initialNavMaxCOunt != sb.getConfigInt(
SwitchboardConstants.SEARCH_NAVIGATION_MAXCOUNT, QueryParams.FACETS_STANDARD_MAXCOUNT_DEFAULT)) {
/* Clean up search events cache when necessary */
SearchEventCache.cleanupEvents(true);
}
}
/* Acquire a transaction token for the next POST form submission */
@ -252,24 +276,54 @@ public class ConfigSearchPage_p {
prop.put("search.result.show.snapshots", sb.getConfigBool("search.result.show.snapshots", false) ? 1 : 0);
prop.put("search.result.show.ranking", sb.getConfigBool(SwitchboardConstants.SEARCH_RESULT_SHOW_RANKING, SwitchboardConstants.SEARCH_RESULT_SHOW_RANKING_DEFAULT) ? 1 : 0);
prop.put("search.navigation.location", sb.getConfig("search.navigation", "").indexOf("location",0) >= 0 ? 1 : 0);
// prop.put("search.navigation.filetype", sb.getConfig("search.navigation", "").indexOf("filetype",0) >= 0 ? 1 : 0);
prop.put("search.navigation.protocol", sb.getConfig("search.navigation", "").indexOf("protocol",0) >= 0 ? 1 : 0);
// prop.put("search.navigation.hosts", sb.getConfig("search.navigation", "").indexOf("hosts",0) >= 0 ? 1 : 0);
// prop.put("search.navigation.language", sb.getConfig("search.navigation", "").indexOf("language",0) >= 0 ? 1 : 0);
// prop.put("search.navigation.authors", sb.getConfig("search.navigation", "").indexOf("authors",0) >= 0 ? 1 : 0);
// prop.put("search.navigation.collections", sb.getConfig("search.navigation", "").indexOf("collections",0) >= 0 ? 1 : 0);
// prop.put("search.navigation.namespace", sb.getConfig("search.navigation", "").indexOf("namespace",0) >= 0 ? 1 : 0);
prop.put("search.navigation.topics", sb.getConfig("search.navigation", "").indexOf("topics",0) >= 0 ? 1 : 0);
prop.put("search.navigation.date", sb.getConfig("search.navigation", "").indexOf("date",0) >= 0 ? 1 : 0);
final Set<String> navConfigs = sb.getConfigSet("search.navigation");
boolean locationNavEnabled = false;
boolean protocolNavEnabled = false;
boolean topicsNavEnabled = false;
boolean dateNavEnabled = false;
for(final String navConfig : navConfigs) {
final String navName = NavigatorPlugins.getNavName(navConfig);
if("location".equals(navName)) {
locationNavEnabled = true;
} else if("protocol".equals(navName)) {
protocolNavEnabled = true;
} else if("topics".equals(navName)) {
topicsNavEnabled = true;
} else if("date".equals(navName)) {
dateNavEnabled = true;
}
}
prop.put("search.navigation.location", locationNavEnabled);
prop.put("search.navigation.protocol", protocolNavEnabled);
prop.put("search.navigation.topics", topicsNavEnabled);
prop.put("search.navigation.date", dateNavEnabled);
// list active navigator plugins
String naviconf = sb.getConfig("search.navigation", "");
Map<String, Navigator> navplugins = NavigatorPlugins.initFromCfgString(naviconf);
Map<String, Navigator> navplugins = NavigatorPlugins.initFromCfgStrings(navConfigs);
int i = 0;
for (String navname:navplugins.keySet()) {
for (final String navname : navplugins.keySet()) {
Navigator nav = navplugins.get(navname);
prop.put("search.navigation.plugin_" + i + "_name", navname);
prop.put("search.navigation.plugin_" + i + "_displayname", nav.getDisplayName());
final int navSort;
if(nav.getSort() == null) {
navSort = 0;
} else {
if(nav.getSort().getSortType() == NavigatorSortType.COUNT) {
if(nav.getSort().getSortDir() == NavigatorSortDirection.DESC) {
navSort = 0;
} else {
navSort = 1;
}
} else {
if(nav.getSort().getSortDir() == NavigatorSortDirection.DESC) {
navSort = 2;
} else {
navSort = 3;
}
}
}
prop.put("search.navigation.plugin_" + i + "_navSort", navSort);
i++;
}
prop.put("search.navigation.plugin", i);

@ -30,6 +30,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.regex.PatternSyntaxException;
@ -63,8 +64,8 @@ import net.yacy.peers.DHTSelection;
import net.yacy.peers.Protocol;
import net.yacy.peers.Seed;
import net.yacy.repository.Blacklist;
import net.yacy.repository.BlacklistHostAndPath;
import net.yacy.repository.Blacklist.BlacklistType;
import net.yacy.repository.BlacklistHostAndPath;
import net.yacy.search.Switchboard;
import net.yacy.search.SwitchboardConstants;
import net.yacy.search.index.Segment;
@ -680,7 +681,7 @@ public class IndexControlRWIs_p {
sb.getRanking(),
"",//userAgent
0.0d, 0.0d, 0.0d,
new String[0]);
new HashSet<>());
final SearchEvent theSearch = SearchEventCache.getEvent(query, sb.peers, sb.tables, null, false, sb.loader, Integer.MAX_VALUE, Long.MAX_VALUE);
if (theSearch.rwiProcess != null && theSearch.rwiProcess.isAlive()) try {theSearch.rwiProcess.join();} catch (final InterruptedException e) {}
if (theSearch.local_rwi_available.get() == 0) {

@ -254,7 +254,7 @@ public final class search {
0.0d,
0.0d,
0.0d,
new String[0]
new HashSet<>()
);
theQuery.setStrictContentDom(strictContentDom);
Network.log.info("INIT HASH SEARCH (abstracts only): " + QueryParams.anonymizedQueryHashes(theQuery.getQueryGoal().getIncludeHashes()) + " - " + theQuery.itemsPerPage() + " links");
@ -319,7 +319,7 @@ public final class search {
0.0d,
0.0d,
0.0d,
new String[0]
new HashSet<>()
);
theQuery.setStrictContentDom(strictContentDom);
Network.log.info("INIT HASH SEARCH (query-" + abstracts + "): " + QueryParams.anonymizedQueryHashes(theQuery.getQueryGoal().getIncludeHashes()) + " - " + theQuery.itemsPerPage() + " links");

@ -700,7 +700,7 @@ public class yacysearch {
ranking,
header.get(HeaderFramework.USER_AGENT, ""),
lat, lon, rad,
sb.getConfigArray("search.navigation", ""));
sb.getConfigSet("search.navigation"));
theQuery.setStrictContentDom(strictContentDom);
theQuery.setMaxSuggestions(meanMax);
theQuery.setStandardFacetsMaxCount(sb.getConfigInt(SwitchboardConstants.SEARCH_NAVIGATION_MAXCOUNT,

@ -189,7 +189,15 @@ function toggleVisibility(name, count) {
#{navs}#
<ul id="nav-#[name]#" class="nav nav-sidebar menugroup">
<li style="cursor: pointer; cursor: hand;"><h3 onclick="toggleVisibility('#[name]#', #[count]#);">#[displayname]# [#[count]#] <span style="float:right" id="chevron-#[name]#" class="glyphicon glyphicon-chevron-down" title="click to expand facet"></span></h3></li>
<li style="cursor: pointer; cursor: hand;">
<h3 onclick="toggleVisibility('#[name]#', #[count]#);">#[displayname]# [#[count]#]
#(navSort)#<span class="glyphicon glyphicon-sort-by-attributes-alt" title="Sorted by descending counts"></span>
::<span class="glyphicon glyphicon-sort-by-attributes" title="Sorted by ascending counts"></span>
::<span class="glyphicon glyphicon glyphicon-sort-by-alphabet-alt" title="Sorted by descending labels"></span>
::<span class="glyphicon glyphicon-sort-by-alphabet" title="Sorted by ascending labels"></span>#(/navSort)#
<span style="float:right" id="chevron-#[name]#" class="glyphicon glyphicon-chevron-down" title="click to expand facet"></span>
</h3>
</li>
#{element}#
<li style="display:none" id="#[id]#"><a href="#[url]#" class="MenuItemLink"><input type="checkbox" onchange="window.location.href='#[url]#'"#(on)# checked="checked"::#(/on)#/> #[name]# (#[count]#)</a></li>
#{/element}#</ul>
@ -198,7 +206,12 @@ function toggleVisibility(name, count) {
#{nav-vocabulary}#
<ul id="nav-vocabulary" class="nav nav-sidebar menugroup">
<li style="cursor: pointer; cursor: hand;"><h3 onclick="toggleVisibility('vocabulary_#[navname]#', #[count]#);">#[navname]# [#[count]#] <span style="float:right" id="chevron-vocabulary_#[navname]#" class="glyphicon glyphicon-chevron-down" title="click to expand facet"></span></h3></li>
<li style="cursor: pointer; cursor: hand;">
<h3 onclick="toggleVisibility('vocabulary_#[navname]#', #[count]#);">#[navname]# [#[count]#]
<span class="glyphicon glyphicon-sort-by-attributes-alt" title="Sorted by descending counts"></span>
<span style="float:right" id="chevron-vocabulary_#[navname]#" class="glyphicon glyphicon-chevron-down" title="click to expand facet"></span>
</h3>
</li>
#{element}#
<li style="display:none" id="#[id]#"><a href="#[url]#" class="MenuItemLink"><input type="checkbox" onchange="window.location.href='#[url]#'"#(on)# checked="checked"::#(/on)#/> #[name]# (#[count]#)</a></li>
#{/element}#</ul>

@ -44,6 +44,8 @@ import net.yacy.search.EventTracker;
import net.yacy.search.Switchboard;
import net.yacy.search.SwitchboardConstants;
import net.yacy.search.navigator.Navigator;
import net.yacy.search.navigator.NavigatorSortDirection;
import net.yacy.search.navigator.NavigatorSortType;
import net.yacy.search.query.QueryParams;
import net.yacy.search.query.SearchEvent;
import net.yacy.search.query.SearchEventCache;
@ -343,8 +345,28 @@ public class yacysearchtrailer {
prop.put("navs_" + ni + "_displayname", navi.getDisplayName());
prop.put("navs_" + ni + "_name", naviname);
prop.put("navs_" + ni + "_count", navi.size());
final int navSort;
if(navi.getSort() == null) {
navSort = 0;
} else {
if(navi.getSort().getSortType() == NavigatorSortType.COUNT) {
if(navi.getSort().getSortDir() == NavigatorSortDirection.DESC) {
navSort = 0;
} else {
navSort = 1;
}
} else {
if(navi.getSort().getSortDir() == NavigatorSortDirection.DESC) {
navSort = 2;
} else {
navSort = 3;
}
}
}
prop.put("navs_" + ni + "_navSort", navSort);
navigatorIterator = navi.keys(false);
navigatorIterator = navi.navigatorKeys();
int i = 0, pos = 0, neg = 0;
String nav, rawNav;
while (i < theSearch.getQuery().getStandardFacetsMaxCount() && navigatorIterator.hasNext()) {

@ -222,7 +222,7 @@ public class FederateSearchManager {
this.switchboard.getRanking(),
"",//userAgent
0.0d, 0.0d, 0.0d,
new String[0]);
new HashSet<>());
return query(query);
}

@ -1296,7 +1296,7 @@ public final class Protocol {
// evaluate facets
if(useSolrFacets) {
for (String field: event.query.facetfields) {
for (String field: event.query.facetfields.keySet()) {
FacetField facet = rsp[0].getFacetField(field);
ReversibleScoreMap<String> result = new ClusteredScoreMap<String>(UTF8.insensitiveUTF8Comparator);
List<Count> values = facet == null ? null : facet.getValues();

@ -38,8 +38,8 @@ import net.yacy.search.schema.CollectionSchema;
*/
public class FileTypeNavigator extends StringNavigator implements Navigator {
public FileTypeNavigator(String title, CollectionSchema field) {
super(title, field);
public FileTypeNavigator(final String title, final CollectionSchema field, final NavigatorSort sort) {
super(title, field, sort);
}
@Override

@ -34,9 +34,9 @@ import net.yacy.search.schema.CollectionSchema;
* www.host.org and host.org as same url
*/
public class HostNavigator extends StringNavigator implements Navigator {
public HostNavigator(String title, CollectionSchema field) {
super(title, field);
public HostNavigator(final String title, final CollectionSchema field, final NavigatorSort sort) {
super(title, field, sort);
}
@Override

@ -39,13 +39,11 @@ public class LanguageNavigator extends StringNavigator implements Navigator {
* Default constructor, using the default YaCy Solr field language_s.
*
* @param title the navigator display name
* @param sort the sort properties to apply when iterating over keys with the
* {@link #navigatorKeys()} function
*/
public LanguageNavigator(String title) {
super(title, CollectionSchema.language_s);
}
public LanguageNavigator(String title, CollectionSchema field) {
super(title, field);
public LanguageNavigator(final String title, final NavigatorSort sort) {
super(title, CollectionSchema.language_s, sort);
}
/**

@ -32,8 +32,8 @@ import net.yacy.kelondro.data.meta.URIMetadataNode;
*/
public class NameSpaceNavigator extends StringNavigator implements Navigator {
public NameSpaceNavigator(String title) {
super(title, null);
public NameSpaceNavigator(final String title, final NavigatorSort sort) {
super(title, null, sort);
}
@Override

@ -22,6 +22,7 @@
*/
package net.yacy.search.navigator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@ -105,4 +106,16 @@ public interface Navigator extends ScoreMap<String> {
* @param listener an eventual object which wants to listen to successful updates on this navigator score map
*/
public void setUpdatesListener(final ScoreMapUpdatesListener listener);
/**
* Creates and returns a sorted view of this navigator keys, sorted by the navigator order (for example by descending counts, or by ascending display names)
*
* @return an iterator accessing the navigator keys
*/
public Iterator<String> navigatorKeys();
/**
* @return the sort properties of the navigator
*/
public NavigatorSort getSort();
}

@ -22,18 +22,30 @@
*/
package net.yacy.search.navigator;
import static net.yacy.search.query.SearchEvent.log;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import net.yacy.crawler.CrawlSwitchboard;
import static net.yacy.search.query.SearchEvent.log;
import net.yacy.search.schema.CollectionSchema;
/**
* Class to create and manipulate search navigator plugin list
*/
public class NavigatorPlugins {
/**
* Separator for specific properties in each navigator configuration
*/
public static final String NAV_PROPS_CONFIG_SEPARATOR = ":";
/**
* List of available navigators
* @return Map key=navigatorCfgname, value=std.DisplayName
@ -51,24 +63,120 @@ public class NavigatorPlugins {
defaultnavplugins.put("keywords", "Keywords");
return defaultnavplugins;
}
/**
* @param navConfig a navigator configuration String
* @return the name identifying the navigator, or null when navConfig is null
*/
public static final String getNavName(final String navConfig) {
String name = navConfig;
if(navConfig != null) {
final int navConfigPopsIndex = navConfig.indexOf(NAV_PROPS_CONFIG_SEPARATOR);
if(navConfigPopsIndex >= 0) {
name = navConfig.substring(0, navConfigPopsIndex);
}
}
return name;
}
/**
* @param navName a navigator name
* @return the default sort properties to apply for the given navigator
*/
public static final NavigatorSort getDefaultSort(final String navName) {
if("year".equals(navName)) {
return NavigatorSort.LABEL_DESC;
}
return NavigatorSort.COUNT_DESC;
}
/**
* <p>
* Parse a navigator configuration entry and return the sort properties to
* apply.
* </p>
* <p>
* Supported formats :
* <ul>
* <li>"navName" : descending sort by count values (except for the year navigator, where the default is by descending displayed labels)</li>
* <li>"navName:count" : descending sort by count values</li>
* <li>"navName:label" : ascending sort by displayed labels</li>
* <li>"navName:count:asc" : ascending sort by count values</li>
* <li>"navName:count:desc" : descending sort by count values</li>
* <li>"navName:label:asc" : ascending sort by displayed labels</li>
* <li>"navName:label:desc" : descending sort by displayed labels</li>
* </ul>
* </p>
*
* @param navConfig a navigator configuration String
* @return return the sort properties of the navigator
*/
public static final NavigatorSort parseNavSortConfig(final String navConfig) {
return parseNavSortConfig(navConfig, getDefaultSort(getNavName(navConfig)));
}
/**
* <p>
* Parse a navigator configuration entry and return the sort properties to
* apply.
* </p>
* <p>
* Supported formats :
* <ul>
* <li>"navName" : apply provided default sort/li>
* <li>"navName:count" : descending sort by count values</li>
* <li>"navName:label" : ascending sort by displayed labels</li>
* <li>"navName:count:asc" : ascending sort by count values</li>
* <li>"navName:count:desc" : descending sort by count values</li>
* <li>"navName:label:asc" : ascending sort by displayed labels</li>
* <li>"navName:label:desc" : descending sort by displayed labels</li>
* </ul>
* </p>
*
* @param navConfig a navigator configuration String
* @param defaultSort the default sort properties to apply when the
* configuration String does not specify sort properties
* @return return the sort properties of the navigator
*/
public static final NavigatorSort parseNavSortConfig(final String navConfig, final NavigatorSort defaultSort) {
if (navConfig == null) {
return defaultSort;
}
final Set<String> navProperties = new HashSet<>();
Collections.addAll(navProperties, navConfig.split(NAV_PROPS_CONFIG_SEPARATOR));
NavigatorSort sort = defaultSort;
if (navProperties.contains(NavigatorSortType.LABEL.toString().toLowerCase(Locale.ROOT))) {
sort = NavigatorSort.LABEL_ASC; // default label sort
if (navProperties.contains(NavigatorSortDirection.DESC.toString().toLowerCase(Locale.ROOT))) {
sort = NavigatorSort.LABEL_DESC;
}
} if (navProperties.contains(NavigatorSortType.COUNT.toString().toLowerCase(Locale.ROOT))) {
sort = NavigatorSort.COUNT_DESC; // default count sort
if (navProperties.contains(NavigatorSortDirection.ASC.toString().toLowerCase(Locale.ROOT))) {
sort = NavigatorSort.COUNT_ASC;
}
}
return sort;
}
/**
* Creates map of active search navigators from comma separated config string
* @param navcfg comma separated string of navigator names
* Creates map of active search navigators from navigator config strings
* @param navConfigs navigator configuration strings
* @return map key=navigatorname, value=navigator.plugin reference
*/
static public Map<String, Navigator> initFromCfgString(final String navcfg) {
public static Map<String, Navigator> initFromCfgStrings(final Set<String> navConfigs) {
LinkedHashMap<String, Navigator> navigatorPlugins = new LinkedHashMap<String, Navigator>();
if (navcfg == null || navcfg.isEmpty()) return navigatorPlugins;
String[] navnames = navcfg.split(",");
for (String navname : navnames) {
if (navname.contains("authors")) {
navigatorPlugins.put("authors", new StringNavigator("Authors", CollectionSchema.author_sxt));
}
if (navname.contains("collections")) {
RestrictedStringNavigator tmpnav = new RestrictedStringNavigator("Collection", CollectionSchema.collection_sxt);
final LinkedHashMap<String, Navigator> navigatorPlugins = new LinkedHashMap<>();
if(navConfigs == null) {
return navigatorPlugins;
}
for (final String navConfig : navConfigs) {
final String navName = getNavName(navConfig);
if ("authors".equals(navName)) {
navigatorPlugins.put("authors", new StringNavigator("Authors", CollectionSchema.author_sxt, parseNavSortConfig(navConfig)));
} else if ("collections".equals(navName)) {
RestrictedStringNavigator tmpnav = new RestrictedStringNavigator("Collection", CollectionSchema.collection_sxt, parseNavSortConfig(navConfig));
// exclude default internal collection names
tmpnav.addForbidden("dht");
tmpnav.addForbidden("robot_" + CrawlSwitchboard.CRAWL_PROFILE_AUTOCRAWL_DEEP);
@ -82,46 +190,47 @@ public class NavigatorPlugins {
tmpnav.addForbidden("robot_" + CrawlSwitchboard.CRAWL_PROFILE_SNIPPET_GLOBAL_MEDIA);
tmpnav.addForbidden("robot_" + CrawlSwitchboard.CRAWL_PROFILE_SURROGATE);
navigatorPlugins.put("collections", tmpnav);
}
if (navname.contains("filetype")) {
navigatorPlugins.put("filetype", new FileTypeNavigator("Filetype", CollectionSchema.url_file_ext_s));
}
if (navname.contains("hosts")) {
navigatorPlugins.put("hosts", new HostNavigator("Provider", CollectionSchema.host_s));
}
if (navname.contains("language")) {
navigatorPlugins.put("language", new LanguageNavigator("Language"));
}
if (navname.contains("namespace")) {
navigatorPlugins.put("namespace", new NameSpaceNavigator("Wiki Name Space"));
}
// YearNavigator with possible def of :fieldname:title in configstring
if (navname.contains("year")) {
if ((navname.indexOf(':')) > 0) { // example "year:dates_in_content_dts:Events"
String[] navfielddef = navname.split(":");
try {
// year:fieldname:title
CollectionSchema field = CollectionSchema.valueOf(navfielddef[1]);
if (navfielddef.length > 2) {
navigatorPlugins.put(navfielddef[1], new YearNavigator(navfielddef[2], field));
} else {
navigatorPlugins.put(navfielddef[1], new YearNavigator("Year-" + navfielddef[1], field));
}
} catch (java.lang.IllegalArgumentException ex) {
log.severe("wrong navigator name in config: \"" + navname + "\" " + ex.getMessage());
}
} else { // "year" only use default last_modified
navigatorPlugins.put("year", new YearNavigator("Year", CollectionSchema.last_modified));
} else if ("filetype".equals(navName)) {
navigatorPlugins.put("filetype", new FileTypeNavigator("Filetype", CollectionSchema.url_file_ext_s,
parseNavSortConfig(navConfig)));
} else if("hosts".equals(navName)) {
navigatorPlugins.put("hosts",
new HostNavigator("Provider", CollectionSchema.host_s, parseNavSortConfig(navConfig)));
} else if ("language".equals(navName)) {
navigatorPlugins.put("language", new LanguageNavigator("Language", parseNavSortConfig(navConfig)));
} else if ("namespace".equals(navName)) {
navigatorPlugins.put("namespace", new NameSpaceNavigator("Wiki Name Space", parseNavSortConfig(navConfig)));
} else if ("year".equals(navName)) {
// YearNavigator with possible def of :fieldname:title in configstring
final LinkedHashSet<String> navProperties = new LinkedHashSet<>();
Collections.addAll(navProperties, navConfig.split(NAV_PROPS_CONFIG_SEPARATOR));
/* Remove sort related properties */
for(final NavigatorSortType sortType : NavigatorSortType.values()) {
navProperties.remove(sortType.toString().toLowerCase(Locale.ROOT));
}
for(final NavigatorSortDirection sortDir : NavigatorSortDirection.values()) {
navProperties.remove(sortDir.toString().toLowerCase(Locale.ROOT));
}
final String[] navfielddef = navProperties.toArray(new String[navProperties.size()]);
if (navfielddef.length > 1) {
try {
// year:fieldname:title
CollectionSchema field = CollectionSchema.valueOf(navfielddef[1]);
if (navfielddef.length > 2) {
navigatorPlugins.put(navfielddef[1], new YearNavigator(navfielddef[2], field, parseNavSortConfig(navConfig)));
} else {
navigatorPlugins.put(navfielddef[1], new YearNavigator("Year-" + navfielddef[1], field, parseNavSortConfig(navConfig)));
}
} catch (final java.lang.IllegalArgumentException ex) {
log.severe("wrong navigator name in config: \"" + navConfig + "\" " + ex.getMessage());
}
} else { // "year" only use default last_modified
navigatorPlugins.put("year", new YearNavigator("Year", CollectionSchema.last_modified, parseNavSortConfig(navConfig)));
}
}
if (navname.contains("keywords")) {
navigatorPlugins.put("keywords", new TokenizedStringNavigator("Keywords", CollectionSchema.keywords));
} else if ("keywords".equals(navName)) {
navigatorPlugins.put("keywords", new TokenizedStringNavigator("Keywords", CollectionSchema.keywords, parseNavSortConfig(navConfig)));
}
}
return navigatorPlugins;

@ -0,0 +1,98 @@
// NavigatorSort.java
// ---------------------------
// Copyright 2019 by luccioman; https://github.com/luccioman
//
// This is a part of YaCy, a peer-to-peer based web search engine
//
// LICENSE
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package net.yacy.search.navigator;
/**
* Enumeration of navigator sort properties.
*/
public enum NavigatorSort {
/**
* Descending sort on count values.
*/
COUNT_DESC(NavigatorSortType.COUNT, NavigatorSortDirection.DESC),
/**
* Ascending sort on count values.
*/
COUNT_ASC(NavigatorSortType.COUNT, NavigatorSortDirection.ASC),
/**
* Descending sort on displayed labels.
*/
LABEL_DESC(NavigatorSortType.LABEL, NavigatorSortDirection.DESC),
/**
* Ascending sort on displayed labels.
*/
LABEL_ASC(NavigatorSortType.LABEL, NavigatorSortDirection.ASC);
/**
* The type of sort to apply when iterating over a navigator keys with the
* {@link Navigator#navigatorKeys()} function
*/
private final NavigatorSortType sortType;
/**
* The direction of the sort to apply when iterating over a navigator keys with
* the {@link Navigator#navigatorKeys()} function
*/
private final NavigatorSortDirection sortDir;
/**
* @param sortType The type of sort to apply when iterating over a navigator
* keys with the {@link Navigator#navigatorKeys(boolean)}
* function
* @param sortDir The direction of the sort to apply when iterating over a
* navigator keys with the
* {@link Navigator#navigatorKeys(boolean)} function
*/
private NavigatorSort(final NavigatorSortType sortType, final NavigatorSortDirection sortDir) {
if (sortType == null) {
this.sortType = NavigatorSortType.COUNT;
} else {
this.sortType = sortType;
}
if (sortDir == null) {
this.sortDir = NavigatorSortDirection.DESC;
} else {
this.sortDir = sortDir;
}
}
/**
* @return The type of sort to apply when iterating over a navigator keys with
* the {@link Navigator#navigatorKeys(boolean)} function
*/
public NavigatorSortType getSortType() {
return this.sortType;
}
/**
* @return The direction of the sort to apply when iterating over a navigator
* keys with the {@link Navigator#navigatorKeys(boolean)} function
*/
public NavigatorSortDirection getSortDir() {
return this.sortDir;
}
}

@ -0,0 +1,33 @@
// NavigatorSortDirection.java
// ---------------------------
// Copyright 2019 by luccioman; https://github.com/luccioman
//
// This is a part of YaCy, a peer-to-peer based web search engine
//
// LICENSE
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package net.yacy.search.navigator;
/**
* Enumeration of sort directions for navigators.
*/
public enum NavigatorSortDirection {
/** Ascending order */
ASC,
/** Descending order */
DESC
}

@ -0,0 +1,33 @@
// NavigatorSortType.java
// ---------------------------
// Copyright 2019 by luccioman; https://github.com/luccioman
//
// This is a part of YaCy, a peer-to-peer based web search engine
//
// LICENSE
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package net.yacy.search.navigator;
/**
* Enumeration of types of sort for navigators.
*/
public enum NavigatorSortType {
/** Sort by navigator displayed labels */
LABEL,
/** Sort by navigator counts */
COUNT
}

@ -37,8 +37,8 @@ public class RestrictedStringNavigator extends StringNavigator implements Naviga
Set<String> allowed; // complete list of keys, if empty all keys are allowed
Set<String> forbidden; // keys to exclude
public RestrictedStringNavigator(String title, CollectionSchema field) {
super(title, field);
public RestrictedStringNavigator(final String title, final CollectionSchema field, final NavigatorSort sort) {
super(title, field, sort);
this.allowed = new HashSet<String>();
this.forbidden = new HashSet<String>();
}

@ -22,9 +22,14 @@
*/
package net.yacy.search.navigator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.yacy.cora.sorting.ConcurrentScoreMap;
import net.yacy.cora.sorting.ReversibleScoreMap;
import net.yacy.kelondro.data.meta.URIMetadataNode;
@ -35,16 +40,41 @@ import net.yacy.search.schema.CollectionSchema;
* Search navigator for simple string entries based on ScoreMap to count and
* order the result list by counted occurence
*/
public class StringNavigator extends ConcurrentScoreMap<String> implements Navigator {
public class StringNavigator extends ConcurrentScoreMap<String> implements Navigator {
public String title;
protected final CollectionSchema field;
/**
* The sort properties to apply when iterating over keys with the
* {@link #navigatorKeys()} function
*/
private final NavigatorSort sort;
/**
* Constructor applying a descending sort by counts as defaut.
* @param title the navigator title
* @param field the indexed field to count
*/
public StringNavigator(final String title, final CollectionSchema field) {
this(title, field, NavigatorSort.COUNT_DESC);
}
public StringNavigator(String title, CollectionSchema field) {
super();
this.title = title;
this.field = field;
}
/**
* @param title the navigator title
* @param field the indexed field to count
* @param sort the sort properties to apply when iterating over keys with the
* {@link #navigatorKeys()} function
*/
public StringNavigator(final String title, final CollectionSchema field, final NavigatorSort sort) {
this.title = title;
this.field = field;
if(sort == null) {
this.sort = NavigatorSort.COUNT_DESC;
} else {
this.sort = sort;
}
}
@Override
public String getDisplayName() {
@ -153,4 +183,26 @@ public class StringNavigator extends ConcurrentScoreMap<String> implements Navi
}
return "";
}
@Override
public Iterator<String> navigatorKeys() {
if(this.sort.getSortType() == NavigatorSortType.LABEL) {
final ArrayList<String> keys = new ArrayList<>(this.map.keySet());
Comparator<String> keyComparator = Comparator.comparing(this::getElementDisplayName);
if(this.sort.getSortDir() == NavigatorSortDirection.DESC) {
keyComparator = keyComparator.reversed();
}
Collections.sort(keys, keyComparator);
return keys.iterator();
}
return keys(this.sort.getSortDir() == NavigatorSortDirection.ASC);
}
@Override
public NavigatorSort getSort() {
return this.sort;
}
}

@ -36,8 +36,8 @@ import net.yacy.search.schema.CollectionSchema;
*/
public class TokenizedStringNavigator extends StringNavigator implements Navigator {
public TokenizedStringNavigator(String title, CollectionSchema field) {
super(title, field);
public TokenizedStringNavigator(String title, CollectionSchema field, final NavigatorSort sort) {
super(title, field, sort);
}
/**

@ -24,11 +24,9 @@ package net.yacy.search.navigator;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;
import net.yacy.cora.federate.solr.SolrType;
import net.yacy.cora.sorting.ReversibleScoreMap;
import net.yacy.kelondro.data.meta.URIMetadataNode;
@ -54,8 +52,8 @@ import net.yacy.search.schema.CollectionSchema;
*/
public class YearNavigator extends StringNavigator implements Navigator {
public YearNavigator(String title, CollectionSchema field) {
super(title, field);
public YearNavigator(final String title, final CollectionSchema field, final NavigatorSort sort) {
super(title, field, sort == null ? NavigatorSort.LABEL_DESC : sort);
if (field.getType() != SolrType.date) throw new IllegalArgumentException("field is not of type Date");
}
@ -119,32 +117,6 @@ public class YearNavigator extends StringNavigator implements Navigator {
}
}
/**
* YearNavigator returns keys in asc or desc order instead of ordered by
* score
*
* @param up true = asc
* @return key alphabetically ordered
*/
@Override
public Iterator<String> keys(boolean up) {
TreeSet<String> years;
if (up) {
years = new TreeSet<String>();
} else {
years = new TreeSet<String>(Collections.reverseOrder());
}
// make sure keys with high score are included (display may be limited in size)
// Iterator<String> it = this.iterator();
Iterator<String> it = super.keys(false);
while (it.hasNext()) {
years.add(it.next());
}
return years.iterator();
}
/**
* For date_in_content_dts it return true if form:YEAR and to:YEAR is part

@ -34,10 +34,10 @@ import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.regex.Matcher;
@ -77,6 +77,8 @@ import net.yacy.kelondro.util.Bitfield;
import net.yacy.kelondro.util.SetTools;
import net.yacy.peers.Seed;
import net.yacy.search.index.Segment;
import net.yacy.search.navigator.NavigatorPlugins;
import net.yacy.search.navigator.NavigatorSort;
import net.yacy.search.ranking.RankingProfile;
import net.yacy.search.schema.CollectionConfiguration;
import net.yacy.search.schema.CollectionSchema;
@ -89,6 +91,18 @@ public final class QueryParams {
/** The default maximum number of date elements in the date navigator */
public static final int FACETS_DATE_MAXCOUNT_DEFAULT = 640;
/**
* The Solr facet limit to apply when resorting or filtering is done in a YaCy
* search navigator. For example sort by ascending counts or by descending
* indexed terms are not supported with Solr 6.6 (but should be on Solr 7 JSON
* Facet API - see
* https://lucene.apache.org/solr/guide/7_6/json-facet-api.html). The limit
* defined here is set large enough so that resorting can be done by the YaCy
* Navigator itself. We don't set the facet to unlimited to prevent a too high
* memory usage.
*/
private static final int FACETS_MAXCOUNT_FOR_RESORT_ON_SEARCH_NAV = 100000;
public enum Searchdom {
LOCAL, CLUSTER, GLOBAL;
@ -188,7 +202,9 @@ public final class QueryParams {
public long searchtime, urlretrievaltime, snippetcomputationtime; // time to perform the search, to get all the urls, and to compute the snippets
public final String userAgent;
protected double lat, lon, radius;
public LinkedHashSet<String> facetfields;
/** Map from facet/navigator name to sort properties */
public Map<String, NavigatorSort> facetfields;
private SolrQuery cachedQuery;
private CollectionConfiguration solrSchema;
public final int timezoneOffset;
@ -228,7 +244,7 @@ public final class QueryParams {
final double lat,
final double lon,
final double radius,
final String[] search_navigation
final Set<String> navConfigs
) {
this.queryGoal = queryGoal;
this.modifier = modifier;
@ -286,7 +302,7 @@ public final class QueryParams {
this.snippetCacheStrategy = snippetCacheStrategy;
this.clienthost = host;
this.remotepeer = null;
this.starttime = Long.valueOf(System.currentTimeMillis());
this.starttime = System.currentTimeMillis();
this.maxtime = 10000;
this.indexSegment = indexSegment;
this.userAgent = userAgent;
@ -296,23 +312,23 @@ public final class QueryParams {
this.lat = Math.floor(lat * this.kmNormal) / this.kmNormal;
this.lon = Math.floor(lon * this.kmNormal) / this.kmNormal;
this.radius = Math.floor(radius * this.kmNormal + 1) / this.kmNormal;
this.facetfields = new LinkedHashSet<String>();
this.facetfields = new HashMap<>();
this.solrSchema = indexSegment.fulltext().getDefaultConfiguration();
for (String navkey: search_navigation) {
CollectionSchema f = defaultfacetfields.get(navkey);
for (final String navConfig: navConfigs) {
CollectionSchema f = defaultfacetfields.get(NavigatorPlugins.getNavName(navConfig));
// handle special field, authors_sxt (add to facet w/o contains check, as authors_sxt is not enabled (is copyfield))
// dto. for coordinate_p_0_coordinate is not enabled but used for location facet (because coordinate_p not valid for facet field)
if (f != null && (solrSchema.contains(f) || f.name().equals("author_sxt") || f.name().equals("coordinate_p_0_coordinate") ))
this.facetfields.add(f.getSolrFieldName());
if (f != null && (solrSchema.contains(f) || f == CollectionSchema.author_sxt || f == CollectionSchema.coordinate_p_0_coordinate))
this.facetfields.put(f.getSolrFieldName(), NavigatorPlugins.parseNavSortConfig(navConfig));
}
if (LibraryProvider.autotagging != null) for (Tagging v: LibraryProvider.autotagging.getVocabularies()) {
if (v.isFacet()) {
this.facetfields.add(CollectionSchema.VOCABULARY_PREFIX + v.getName() + CollectionSchema.VOCABULARY_TERMS_SUFFIX);
this.facetfields.put(CollectionSchema.VOCABULARY_PREFIX + v.getName() + CollectionSchema.VOCABULARY_TERMS_SUFFIX, NavigatorSort.COUNT_DESC);
}
}
for (String context: ProbabilisticClassifier.getContextNames()) {
this.facetfields.add(CollectionSchema.VOCABULARY_PREFIX + context + CollectionSchema.VOCABULARY_TERMS_SUFFIX);
this.facetfields.put(CollectionSchema.VOCABULARY_PREFIX + context + CollectionSchema.VOCABULARY_TERMS_SUFFIX, NavigatorSort.COUNT_DESC);
}
this.cachedQuery = null;
this.standardFacetsMaxCount = FACETS_STANDARD_MAXCOUNT_DEFAULT;
@ -686,6 +702,61 @@ public final class QueryParams {
return params;
}
/**
* Fill the Solr parameters with the relevant values to apply the search
* navigator sort properties.
*
* @param params the Solr parameters to modify
* @param a Solr field name
* @param navSort navigator sort properties to apply
*/
private void fillSolrParamWithNavSort(final SolrQuery params, final String solrFieldName,
final NavigatorSort navSort) {
if (params != null && solrFieldName != null && navSort != null) {
switch (navSort) {
case COUNT_ASC:
params.setParam("f." + solrFieldName + ".facet.sort", FacetParams.FACET_SORT_COUNT);
/*
* Ascending count is not supported with Solr 6.6 (but should be on Solr 7 JSON
* Facet API https://lucene.apache.org/solr/guide/7_6/json-facet-api.html) So we
* use a here a high limit and ascending resorting will be done by YaCy
* Navigator
*/
params.setParam("f." + solrFieldName + ".facet.limit",
String.valueOf(FACETS_MAXCOUNT_FOR_RESORT_ON_SEARCH_NAV));
break;
case LABEL_DESC:
/*
* Descending index order is not supported with Solr 6.6 (but should be on Solr
* 7 JSON Facet API
* https://lucene.apache.org/solr/guide/7_6/json-facet-api.html) So we use a
* here a high limit and descending resorting will be done by YaCy Navigator
*/
params.setParam("f." + solrFieldName + ".facet.sort", FacetParams.FACET_SORT_INDEX);
params.setParam("f." + solrFieldName + ".facet.limit",
String.valueOf(FACETS_MAXCOUNT_FOR_RESORT_ON_SEARCH_NAV));
break;
case LABEL_ASC:
params.setParam("f." + solrFieldName + ".facet.sort", FacetParams.FACET_SORT_INDEX);
break;
default:
/* Nothing to add for COUNT_DESC which is the default for Solr */
break;
}
if (CollectionSchema.language_s.getSolrFieldName().equals(solrFieldName)
|| CollectionSchema.url_file_ext_s.getSolrFieldName().equals(solrFieldName)
|| CollectionSchema.collection_sxt.getSolrFieldName().equals(solrFieldName)) {
/*
* For these search navigators additional filtering or resorting is done in the navigator itself.
* So we use a here a high limit so that the navigator apply its rules without missing elements.
*/
params.setParam("f." + solrFieldName + ".facet.limit",
String.valueOf(FACETS_MAXCOUNT_FOR_RESORT_ON_SEARCH_NAV));
}
}
}
private SolrQuery getBasicParams(final boolean getFacets, final List<String> fqs) {
final SolrQuery params = new SolrQuery();
params.setParam("defType", "edismax");
@ -713,15 +784,19 @@ public final class QueryParams {
params.setFacetLimit(this.standardFacetsMaxCount);
params.setFacetSort(FacetParams.FACET_SORT_COUNT);
params.setParam(FacetParams.FACET_METHOD, FacetParams.FACET_METHOD_enum); // fight the fieldcache
for (String field: this.facetfields) params.addFacetField("{!ex=" + field + "}" + field); // params.addFacetField("{!ex=" + field + "}" + field);
if (this.facetfields.contains(CollectionSchema.dates_in_content_dts.name())) {
for (final Entry<String, NavigatorSort> entry : this.facetfields.entrySet()) {
params.addFacetField("{!ex=" + entry.getKey() + "}" + entry.getKey()); // params.addFacetField("{!ex=" + field + "}" + field);
fillSolrParamWithNavSort(params, entry.getKey(), entry.getValue());
}
final NavigatorSort datesInContentSort = this.facetfields.get(CollectionSchema.dates_in_content_dts.name());
if (datesInContentSort != null) {
params.setParam(FacetParams.FACET_RANGE, CollectionSchema.dates_in_content_dts.name());
String start = new Date(System.currentTimeMillis() - 1000L * 60L * 60L * 24L * 3).toInstant().toString();
String end = new Date(System.currentTimeMillis() + 1000L * 60L * 60L * 24L * 3).toInstant().toString();
params.setParam("f." + CollectionSchema.dates_in_content_dts.getSolrFieldName() + ".facet.range.start", start);
params.setParam("f." + CollectionSchema.dates_in_content_dts.getSolrFieldName() + ".facet.range.end", end);
params.setParam("f." + CollectionSchema.dates_in_content_dts.getSolrFieldName() + ".facet.range.gap", "+1DAY");
params.setParam("f." + CollectionSchema.dates_in_content_dts.getSolrFieldName() + ".facet.sort", "index");
fillSolrParamWithNavSort(params, CollectionSchema.dates_in_content_dts.getSolrFieldName(), datesInContentSort);
params.setParam("f." + CollectionSchema.dates_in_content_dts.getSolrFieldName() + ".facet.limit", Integer.toString(this.dateFacetMaxCount)); // the year constraint should cause that limitation already
}
//for (String k: params.getParameterNames()) {ArrayList<String> al = new ArrayList<>(); for (String s: params.getParams(k)) al.add(s); System.out.println("Parameter: " + k + "=" + al.toString());}

@ -352,15 +352,34 @@ public final class SearchEvent implements ScoreMapUpdatesListener {
this.maxExpectedRemoteReferences = new AtomicInteger(0);
this.expectedRemoteReferences = new AtomicInteger(0);
this.excludeintext_image = Switchboard.getSwitchboard().getConfigBool("search.excludeintext.image", true);
// prepare configured search navigation
final String navcfg = Switchboard.getSwitchboard().getConfig("search.navigation", "");
this.locationNavigator = navcfg.contains("location") ? new ConcurrentScoreMap<String>(this) : null;
this.protocolNavigator = navcfg.contains("protocol") ? new ConcurrentScoreMap<String>(this) : null;
this.dateNavigator = navcfg.contains("date") ? new ConcurrentScoreMap<String>(this) : null;
this.topicNavigatorCount = navcfg.contains("topics") ? MAX_TOPWORDS : 0;
final Set<String> navConfigs = Switchboard.getSwitchboard().getConfigSet("search.navigation");
boolean locationNavEnabled = false;
boolean protocolNavEnabled = false;
boolean topicsNavEnabled = false;
boolean dateNavEnabled = false;
for(final String navConfig : navConfigs) {
final String navName = NavigatorPlugins.getNavName(navConfig);
if("location".equals(navName)) {
locationNavEnabled = true;
} else if("protocol".equals(navName)) {
protocolNavEnabled = true;
} else if("topics".equals(navName)) {
topicsNavEnabled = true;
} else if("date".equals(navName)) {
dateNavEnabled = true;
}
}
this.locationNavigator = locationNavEnabled ? new ConcurrentScoreMap<>(this) : null;
this.protocolNavigator = protocolNavEnabled ? new ConcurrentScoreMap<>(this) : null;
this.dateNavigator = dateNavEnabled ? new ConcurrentScoreMap<>(this) : null;
this.topicNavigatorCount = topicsNavEnabled ? MAX_TOPWORDS : 0;
this.vocabularyNavigator = new TreeMap<String, ScoreMap<String>>();
// prepare configured search navigation (plugins)
this.navigatorPlugins = NavigatorPlugins.initFromCfgString(navcfg);
this.navigatorPlugins = NavigatorPlugins.initFromCfgStrings(navConfigs);
if(this.navigatorPlugins != null) {
for(final Navigator nav : this.navigatorPlugins.values()) {
nav.setUpdatesListener(this);

@ -446,8 +446,7 @@ public class serverSwitch {
/**
* get a configuration parameter set
* @param key
* @param dflt a default list
* @param key name of the configuration parameter
* @return a set of strings which had been separated by comma in the setting
*/
public Set<String> getConfigSet(final String key) {

Loading…
Cancel
Save