isearch/commit

Merge facet values that point to a single result

authorJan Wielemaker
Tue Dec 14 16:32:02 2010 +0100
committerJan Wielemaker
Tue Dec 14 16:32:02 2010 +0100
commit17165610466e347432aea825da73efa0c1390b5e
treec089ea8f7ffea03f00515b34f3a8b0ed17729dde
parent0c1cacf8b523d4bcf022eff50b8cc27d9654af01
Diff style: patch stat
diff --git a/applications/isearch.pl b/applications/isearch.pl
index ecc51a6..74202ab 100644
--- a/applications/isearch.pl
+++ b/applications/isearch.pl
@@ -81,8 +81,6 @@
 	   'Show relations by which search results are found').
 :- setting(search:show_facets, boolean, true,
 	   'Show faceted filters in the search result page').
-:- setting(search:show_single_value_facet, boolean, false,
-	   'Show facets with a single value').
 
 % limits
 :- setting(search:result_limit, integer, 10,
@@ -187,16 +185,23 @@ isearch_page2(Options, Request) :-
   	).
 
 compute_facets(Results, AllResults, Filter, Facets) :-
-	facets(Results, AllResults, Filter, Facets0),
-	maplist(facet_merge_sameas, Facets0, Facets1),
+	facets(Results, AllResults, Filter, ActiveFacets0, InactiveFacets0),
+	maplist(cleanup_facet, ActiveFacets0, ActiveFacets1),
+	maplist(cleanup_facet, InactiveFacets0, InactiveFacets1),
 	length(AllResults, Total),
-	map_list_to_pairs(facet_quality(Total), Facets1, Keyed),
+	map_list_to_pairs(facet_quality(Total), InactiveFacets1, Keyed),
 	keysort(Keyed, Sorted),
-	pairs_values(Sorted, Facets).
+	pairs_values(Sorted, InactiveFacets),
+	append(ActiveFacets1, InactiveFacets, Facets).
+
+cleanup_facet(Facet0, Facet) :-
+	facet_merge_sameas(Facet0, Facet1),
+	facet_join_single(Facet1, Facet).
+
 
 %%	facet_quality(+Total, +Facet, -Quality)
 %
-%	Rate the facet. We use 1/Q  to   avoid  the  need to reverse the
+%	Rate the facet. We use 1-Q to avoid the need to reverse the
 %	search results.
 
 facet_quality(Total, Facet, Quality) :-
@@ -212,7 +217,7 @@ facet_quality(Total, Facet, Quality) :-
 		  [Label, Quality0, Balance, Card, Freq, Weight])
 	;   true
 	),
-	Quality is 1/(Quality0 + 0.00000000000001).
+	Quality is 1-Quality0.
 
 
 % conversion of json parameters.
@@ -562,7 +567,7 @@ equivalent_property(skos:exactMatch).
 
 filter_results_by_facet(AllResults, [], AllResults) :- !.
 filter_results_by_facet(AllResults, Filter, Results) :-
-	facet_condition(Filter, R, Goal),
+	facet_condition(Filter, AllResults, R, Goal),
 	findall(R, (member(R, AllResults), Goal), Results).
 
 
@@ -653,16 +658,8 @@ html_term_list(Terms, RelatedTerms, SelectedTerms) -->
 		       ])
 		 ])).
 
+html_facet_list([]) --> !.
 html_facet_list(Facets) -->
-	{ (   setting(search:show_single_value_facet, false)
-	  ->  remove_single_value_facet(Facets, Facets1)
-	  ;   Facets1 = Facets
-	  )
-	},
-	html_facet_list_(Facets1).
-
-html_facet_list_([]) --> !.
-html_facet_list_(Facets) -->
 	html(div([id(right), class(column)],
 		 [ div(class(toggle),
 		       \toggle_link(rtoggle, rbody, '<', '<', '>')),
@@ -877,12 +874,11 @@ html_related_terms([P-Terms|T], N) -->
 html_facets([], _) --> !.
 html_facets([facet(P, ResultsByValue, Selected)|Fs], N) -->
 	{ N1 is N+1,
-	  rdfs_label(P, Label),
 	  pairs_sort_by_result_count(ResultsByValue, AllValues),
 	  top_bottom(5, 5, AllValues, Values)
   	},
 	html(div(class(facet),
-		 [ div(class(header), Label),
+		 [ div(class(header), \rdf_link(P)),
 		   div([title(P), class(items)],
 		       \resource_list(Values, Selected))
 		 ])),
@@ -1211,7 +1207,10 @@ pairs_sort_by_result_count(Grouped, Sorted) :-
 
 pairs_result_count([], []).
 pairs_result_count([Key-Results|T], [Count-Key|Rest]) :-
-	length(Results, Count),
+	(   integer(Results)
+	->  Count = Results
+	;   length(Results, Count)
+	),
 	pairs_result_count(T, Rest).
 
 
diff --git a/lib/search/facet.pl b/lib/search/facet.pl
index 5be3aff..771f87e 100644
--- a/lib/search/facet.pl
+++ b/lib/search/facet.pl
@@ -29,9 +29,10 @@
 */
 
 :- module(search_facet,
-	  [ facets/4,			% +Results, +AllResults, +Filter, -Facets
+	  [ facets/5,			% +Res, +AllRes, +Filter, -AFacs, -IFacs
 	    facet_merge_sameas/2,	% +FacetIn, -FacetOut
-	    facet_condition/3,		% +Facets, ?Resource, -Goal
+	    facet_join_single/2,	% +FacetIn, -FacetOut
+	    facet_condition/4,		% +Facets, +ResultSet, ?Resource, -Goal
 	    facet_balance/2,		% +Facet, -Balance
 	    facet_object_cardinality/2,	% +Facet, -Card
 	    facet_frequency/3,		% +Facet, +TotalCount, -Freq
@@ -60,7 +61,8 @@ various operations on facets.  A facet is represented as
 	cliopatria:facet_weight/2.	% ?Resource, ?Weight
 
 
-%%	facets(+Results, +AllResults, +Filter, -Facets)
+%%	facets(+Results, +AllResults, +Filter,
+%%	       -ActiveFacets, -InactiveFacets) is det.
 %
 %	Collect faceted properties of Results.
 %
@@ -73,13 +75,12 @@ various operations on facets.  A facet is represented as
 %	@param	Facets is a list of
 %			facet(P, Value_Results_Pairs, SelectedValues)
 
-facets([], _, _, []) :- !.
-facets(_, _, _, []) :-
+facets([], _, _, [], []) :- !.
+facets(_, _, _, [], []) :-
 	setting(search:show_facets, false), !.
-facets(FilteredResults, AllResults, Filter, Facets) :-
+facets(FilteredResults, AllResults, Filter, ActiveFacets, InactiveFacets) :-
 	inactive_facets(FilteredResults, Filter, InactiveFacets),
-	active_facets(AllResults, Filter, ActiveFacets),
- 	append(ActiveFacets, InactiveFacets, Facets).
+	active_facets(AllResults, Filter, ActiveFacets).
 
 inactive_facets(Results, Filter, Facets) :-
 	findall(P-(V-R), inactive_facet_property(Results, Filter, R,P,V), Pairs),
@@ -125,7 +126,7 @@ make_active_facet(Results, Filter, P-V_R, facet(P, V_RL, Selected)) :-
 
 active_facet_property(Results, Filter, R, P, V) :-
 	select(prop(P, _), Filter, FilterRest),
-	facet_condition(FilterRest, R, Goal),
+	facet_condition(FilterRest, Results, R, Goal),
 	member(R, Results),
 	call(Goal),
 	rdf_has(R, P, V).
@@ -161,6 +162,22 @@ root_property_uncached(P0, Super) :-		% FIXME: can be cyclic?
 	sort(Ps0, Ps),
 	member(Super, Ps).
 
+%%	facet_join_single(Facet0, Facet) is det.
+%
+%	Join all facet values that  represent   only  one  result into a
+%	virtual facet __single
+
+facet_join_single(facet(P, VRPairs0, SelectedValues),
+		  facet(P, VRPairs,  SelectedValues)) :-
+	partition(single, VRPairs0, Singles, VRPairs1),
+	length(Singles, Count),
+	(   Count == 0
+	->  VRPairs = VRPairs1
+	;   VRPairs = ['__single'-Count|VRPairs1]
+	).
+
+single(_-[_]).				% facet pointing to exactly one result
+
 %%	facet_merge_sameas(Facet0, Facet) is det.
 %
 %	Merge different values for  a  facet   that  are  linked through
@@ -194,21 +211,28 @@ map_resource(Map, R0, R) :-
 	;   R = R0
 	).
 
-%%	facet_condition(+Facets, ?Resource, -Goal) is det.
+%%	facet_condition(+Facets, +ResultSet, ?Resource, -Goal) is det.
 %
 %	Goal is an executable representation of   the  current Facets on
 %	Resource.  Goal itself is semidet.
 %
-%	@param Facets is a list of prop(P,Values)
+%	@param	Facets is a list of prop(P,Values)
 
-facet_condition([], _, true).
-facet_condition([prop(P, Values)|T], R, (Goal->Rest)) :-
+facet_condition([], _, _, true).
+facet_condition([prop(P, Values)|T], Results, R, (Goal->Rest)) :-
 	(   Values == ['__null']
-	->  Goal = (\+ rdf(R,P,_))
+	->  Goal = (\+ rdf_has(R,P,_))
+	;   Values == ['__single']
+	->  Goal = ( rdf_has(R,P,V),
+	    	     \+ ( rdf_has(R2,P,V),
+			  memberchk(R2, Results),
+			  R\==R2
+			)
+		   )
 	;   findall(V, (member(V0, Values), owl_sameas(V0, V)), AllValues),
 	    pred_filter(AllValues, P, R, Goal)
 	),
-	facet_condition(T, R, Rest).
+	facet_condition(T, Results, R, Rest).
 
 pred_filter([Value], P, R, Goal) :- !,
 	Goal = rdf_has(R, P, Value).
@@ -241,10 +265,16 @@ pred_filter([Value|Vs], P, R, Goal) :-
 
 facet_balance(facet(_P, V_R, _Selected), Balance) :-
 	pairs_values(V_R, RLs),
-	maplist(length, RLs, Counts),
+	maplist(object_count, RLs, Counts),
 	list_variance(Counts, Var),
 	Balance is 1 - (Var/(1+Var)).
 
+object_count(Results, Count) :-
+	(   integer(Results)
+	->  Count = Results
+	;   length(Results, Count)
+	).
+
 facet_object_cardinality(facet(_P, V_R, _Selected), Card) :-
 	Mu = 10,
 	Sigma = 40,
@@ -256,10 +286,13 @@ facet_object_cardinality(facet(_P, V_R, _Selected), Card) :-
 
 facet_frequency(facet(_P, V_R, _Selected), Total, Freq) :-
 	pairs_values(V_R, RLs),
-	append(RLs, AllResults),
+	partition(integer, RLs, Counts, Lists),
+	append(Lists, AllResults),
 	sort(AllResults, Unique),
 	length(Unique, UniqueCount),
-	Freq is UniqueCount/Total.
+	sumlist(Counts, CountSum),	% May *not* be independent
+	Freq is (UniqueCount+CountSum)/Total.
+
 
 %%	facet_weight(?P, ?Weight)
 %