Solr Search Builders - samvera/hyrax GitHub Wiki
Search Builders
Building searches is core to any Blacklight app, and Hyrax is no exception. The app/search_builders/hyrax directory contains our Search Builders, originally so-named because the class design followed a Builder pattern. Builder setter methods return the object itself when invoked, so that invocations can be chained, like:
builder = Blacklight::SearchBuilder.new(processor_chain, scope)
.rows(20)
.page(3)
.with(q: 'Abraham Lincoln')
However, at this level, many if not most of the additional methods do not follow this pattern. So these builders create searches in the general sense of the name, not by strictly following the Builder pattern. Refer to the Blacklight::SearchBuilder
class if you want to be certain of whether a method can be chained. That leads to the next topic...
Ancestry
Most of the SearchBuilders have ::SearchBuilder
as a parent or ancestor. ::SearchBuilder
does not exist in any repo: it is generated by Blacklight and modified by Hyrax. Others descend from Blacklight::SearchBuilder
, or various other relatives.
::SearchBuilder
The generated parent class SearchBuilder
descends from Blacklight::SearchBuilder
.
As modified by Hyrax's installer, it includes additional modules and overrides. So if your SearchBuilder has ::SearchBuilder
as a parent class, you are getting:
- Blacklight::SearchBuilder grandparent class
- Blacklight::Solr::SearchBuilderBehavior associated methods
- Hydra::AccessControlsEnforcement module
- Blacklight::AccessControls::Enforcement ancestor of
Hydra::AccessControlsEnforcement
- Blacklight::AccessControls::Enforcement ancestor of
- Hyrax::SearchFilters module that itself includes:
- BlacklightAdvancedSearch::AdvancedSearchBuilder more magic for compound Boolean queries
- Hyrax::FilterByType Collection vs. Work filtering, specifically the
filter_models
method
This is not a comprehensive list, but it is sufficient to trace some of the complexity of interaction between various layers.
Development: AKA Doing Something Useful
Important note: the default_processor_chain
defined by Blacklight::Solr::SearchBuilderBehavior
provides a way to extend functionality, but also many possible points of override (namely method names). When you need to do something novel and additional, adding to the chain is completely reasonable. For example:
module MySearchBuilder
extend ActiveSupport::Concern
included do
self.default_processor_chain += [:special_filter]
end
def special_filter(solr_parameters)
solr_parameters[:fq] << "{!field f=some_field_ssim}#{...}"
end
end
But to the extent that you are overriding (or undoing) something already done, Hyrax::FileSetSearchBuilder
is a better example:
module Hyrax
class FileSetSearchBuilder < ::SearchBuilder
include Hyrax::SingleResult
# This overrides the filter_models in FilterByType
def filter_models(solr_parameters)
solr_parameters[:fq] << ActiveFedora::SolrQueryBuilder.construct_query_for_rel(has_model: ::FileSet.to_class_uri)
end
end
end
There is no point having the other filter_models
methods apply :fq
s that we then try to undo or overwrite. In general, directly overwriting the whole default_processor_chain
or solr parameters like :fq
is less flexible than appending constraints sufficient for your use case. In particular, you might find that you have overwritten components that implement access controls, thereby making your SearchBuilder less useful and less secure. When in doubt, examine the actual solr queries produced.