Skip to content

Commit

Permalink
+ facets API changed for 4.5.12, see history.textile
Browse files Browse the repository at this point in the history
  • Loading branch information
floere committed Jul 24, 2012
1 parent 611e24d commit 5d21d4a
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 65 deletions.
6 changes: 6 additions & 0 deletions history.textile
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
h2. Upcoming Version

h2. Version 4.5.12 "counts count more than weights"

* hanke: (server) Facets API now returns counts rather than weights.
* hanke: (server) Facets API changed option @more_than@ into @at_least@ – give if you need facets with at least a certain count.
* hanke: (server) Facets API added option @counts@ (@true@/@false@) – @facets@ methods will return a hash with counts if @true@ or not given, ie. @nil@, and an array if @false@.

h2. Version 4.5.11 "partial to facets"

* hanke: (server) @Search#facets@ now does access the partial index, but always the exact index.
Expand Down
25 changes: 19 additions & 6 deletions server/lib/picky/index_facets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,27 @@ module Picky
class Index

# Return facets for a category in the form:
# { text => weight } # or ids.size?
# { text => count }
#
# Options
# counts: Whether you want counts or not.
# at_least: A minimum count a facet needs to have (inclusive).
#
# TODO Think about having a separate index for counts to reduce the complexity of this.
#
def facets category_identifier, options = {}
weights = self[category_identifier].exact.weights
if minimal_weight = options[:more_than]
weights.select { |_, weight| weight > minimal_weight }
else
weights
text_ids = self[category_identifier].exact.inverted
no_counts = options[:counts] == false
minimal_counts = options[:at_least]
text_ids.inject(no_counts ? [] : {}) do |result, text_ids|
text, ids = text_ids
size = ids.size
next result if minimal_counts && size < minimal_counts
if no_counts
result << text
else
result[text] = size; result
end
end
end

Expand Down
32 changes: 24 additions & 8 deletions server/lib/picky/search_facets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ module Picky

class Search

# Returns a list of filtered facets.
# Returns a list/hash of filtered facets.
#
# Params
# category: The category whose facets to return.
#
# Options
# more_than: A minimum weight a facet needs to have (exclusive).
# counts: Whether you want counts (returns a Hash) or not (returns an Array).
# at_least: A minimum count a facet needs to have (inclusive).
# filter: A query to filter the facets with.
#
# Usage:
Expand All @@ -18,23 +19,38 @@ def facets category_identifier, options = {}
raise "#{__method__} cannot be used on searches with more than 1 index yet. Sorry!" if indexes.size > 1
index = indexes.first

# Get index-specific facet weights.
# Get index-specific facet counts.
#
weights = index.facets category_identifier, options
counts = index.facets category_identifier, options

# We're done if there is no filter.
#
return weights unless filter_query = options[:filter]
return counts unless filter_query = options[:filter]

# Pre-tokenize filter for reuse.
#
tokenized_filter = tokenized filter_query, false

# Filter out impossible facets.
# Extract options.
#
weights.select do |key, weight|
no_counts = options[:counts] == false
minimal_counts = options[:at_least] || 1 # Default needs at least one.

# Get actual counts.
#
# TODO Rewrite.
#
counts.inject(no_counts ? [] : {}) do |result, key_count|
key, _ = key_count
tokenized_query = tokenized "#{category_identifier}:#{key}", false
search_with(tokenized_filter + tokenized_query, 0, 0).total > 0
total = search_with(tokenized_filter + tokenized_query, 0, 0).total
next result unless total >= minimal_counts
if no_counts
result << key
else
result[key] = total; result
end
result
end
end

Expand Down
133 changes: 83 additions & 50 deletions server/spec/functional/facets_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,47 +22,47 @@
}
let(:finder) { Picky::Search.new index }

describe 'facets' do
describe 'Index#facets' do
it 'is correct' do
# Picky has 2 facets with different weights for surname.
# Picky has 2 facets with different counts for surname.
#
index.facets(:surname).should == {
'hanke' => 0.693,
'schiess' => 0
'hanke' => 2,
'schiess' => 1
}

# It has 3 facets with the same weight for name.
# It has 3 facets with the same count for name.
#
index.facets(:name).should == {
'fritz' => 0,
'kaspar' => 0,
'florian' => 0
'fritz' => 1,
'kaspar' => 1,
'florian' => 1
}

# Picky only selects facets with a weight >= the given one.
# Picky only selects facets with a count >= the given one.
#
index.facets(:surname, more_than: 0.5).should == {
'hanke' => 0.693
index.facets(:surname, at_least: 2).should == {
'hanke' => 2
}
end
end

describe 'facets' do
describe 'Search#facets' do
it 'filters them correctly' do
# Passing in no filter query just returns the facets
#
finder.facets(:surname).should == {
'hanke' => 0.693,
'schiess' => 0.0
'hanke' => 2,
'schiess' => 1
}

# It has two facets.
#
# TODO Rewrite API.
#
finder.facets(:name, filter: 'surname:hanke').should == {
'fritz' => 0,
'florian' => 0
'fritz' => 1,
'florian' => 1
}
end
end
Expand All @@ -88,61 +88,94 @@
}
let(:finder) { Picky::Search.new index }

describe 'facets' do
it 'is correct' do
# Picky has 2 facets with different weights for surname.
#
describe 'Index#facets' do
it 'has 2 facets with different counts for surname' do
index.facets(:surname).should == {
'hanke' => 0.693,
'kunz' => 0.0,
'meier' => 1.099
'hanke' => 2,
'kunz' => 1,
'meier' => 3
}

# It has 3 facets with the same weight for name.
#
end
it 'has 4 facets for the name' do
index.facets(:name).should == {
'annabelle' => 0.0,
'hans' => 0.0,
'peter' => 1.099,
'ursula' => 0.0
'annabelle' => 1,
'hans' => 1,
'peter' => 3,
'ursula' => 1
}

# It has 1 facet with weight > 0.
#
index.facets(:name, more_than: 0).should == {
'peter' => 1.099
end
it 'has 3 facets with the same count for name' do
index.facets(:name).should == {
'annabelle' => 1,
'hans' => 1,
'peter' => 3,
'ursula' => 1
}
end
it 'has 1 facet with count >= 2' do
index.facets(:name, at_least: 2).should == {
'peter' => 3
}
end
end

describe 'facets' do
describe 'Search#facets' do
it 'is fast enough' do
performance_of {
10.times { finder.facets(:age_category, filter: 'surname:meier name:peter') }
}.should < 0.00275
end
it 'filters them correctly' do
# It has one facet.
#
it 'has one filtered facet' do
# TODO Fix problems with alternative qualifiers (like :age).
#
finder.facets(:age_category, filter: 'surname:meier name:peter').should == {
'45' => 0
'45' => 1
}

# It has two facets.
#
end
it 'has two filtered facets' do
finder.facets(:surname, filter: 'age_category:40 name:peter').should == {
'kunz' => 0.0,
'hanke' => 0.693
'kunz' => 1,
'hanke' => 1 # Not 2 since it is filtered.
}
# It has 1 facet > weight 0.
#
finder.facets(:surname, filter: 'age_category:40 name:peter', more_than: 0).should == {
'hanke' => 0.693
end
it 'has 2 facets >= count 0' do
finder.facets(:surname, filter: 'age_category:40 name:peter', at_least: 1).should == {
'kunz' => 1,
'hanke' => 1
}
end
it 'has 0 facets >= counts 2' do
finder.facets(:surname, filter: 'age_category:40 name:peter', at_least: 2).should == {}
end
end

describe 'Search#facets without counts' do
it 'is fast enough' do
performance_of {
10.times { finder.facets(:age_category, filter: 'surname:meier name:peter', counts: false) }
}.should < 0.00275
end
it 'has one filtered facet' do
# TODO Fix problems with alternative qualifiers (like :age).
#
finder.facets(:age_category, filter: 'surname:meier name:peter', counts: false).should == ['45']
end
it 'has two filtered facets' do
finder.facets(:surname, filter: 'age_category:40 name:peter', counts: false).should == [
'kunz',
'hanke'
]
end
it 'has 2 facets >= count 0' do
finder.facets(:surname, filter: 'age_category:40 name:peter', at_least: 1, counts: false).should == [
'kunz',
'hanke'
]
end
it 'has 0 facets >= counts 2' do
finder.facets(:surname, filter: 'age_category:40 name:peter', at_least: 2, counts: false).should == []
end
end

end
end
2 changes: 1 addition & 1 deletion version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Picky
VERSION = '4.5.11'
VERSION = '4.5.12'
end

0 comments on commit 5d21d4a

Please sign in to comment.