Currently, even though the "Filter by Taxonomy: XXX" blocks have the option to select "Include a facet for missing: Yes", apachesolr_search_taxonomy_facet_block() can't handle them yet:
foreach ($response->facet_counts->facet_fields->$delta as $tid => $count) {
// TODO - for now we don't handle facet missing.
if ($tid != '_empty_') {
So, step 1 would be to remove the option from the blocks so as not to mislead admins (like it did me) =)
I think handling this will be tricky. A simple way could be to just offer a non-clickable item in the facet blocks that says "Other" with the count of items that do not have a term for this vocabulary (OR, if a term with child terms is already active, show "Other" and the count of nodes which do not have any child terms).
With the current API, is it even possible to say "filter by im_vid_XX=[Fruit] and im_vid_XX != (bananas | oranges | grapes)" to get stuff that's just tagged "Fruit" on the search URL?
| Comment | File | Size | Author |
|---|---|---|---|
| #31 | 912758-facetapi-30.patch | 8.57 KB | pwolanin |
| #31 | 912758-apachesolr-31.patch | 6.65 KB | pwolanin |
| #29 | 912758-apachesolr-28.patch | 6.65 KB | pwolanin |
| #29 | 912758-facetapi-28.patch | 8.51 KB | pwolanin |
| #21 | facetapi-912758-21.patch | 9.38 KB | pwolanin |
Comments
Comment #1
janusman commentedClearer title (I think).
Comment #2
pwolanin commentedDo we still not handle missing in 7.x?
Comment #3
jpmckinney commentedWith facetapi, we've cut the "Include a facet for missing" functionality.
Comment #4
pwolanin commentedSo, seems like we need to add this in to to Facet API I'm not sure if this is something every back-end would support, or whether this is something apachesolr would need to enable for certain facets.
Comment #5
cpliakas commentedI'm not clear on the functionality. Is this for cases where a term has been deleted, yet it remains in the list of available facets? Let me know if I am way of here.
Comment #6
pwolanin commentedNo, the common use cases I had to far:
find all nodes not in any OG group.
find all nodes of a given type not in any book.
So it is for finding documents where a certain property (e.g. gid or bid) is not present.
Comment #7
cpliakas commentedAh, I see. Thanks for the explanation. How was this represented in the old faceted interface?
Comment #8
pwolanin commentedhttp://drupalcode.org/project/apachesolr.git/blob/refs/heads/6.x-1.x:/ap...
~line 862:
The '_empty_' string I think actually comes from the json_decode(), not Solr. It's because the KEY in the facet response is an empty string for the "missing" facet (the value is the number of matches).
So there would be a few little pieces:
theme('placeholder', t('Missing this field'));above.Comment #9
pwolanin commentedAs a side note, I had to fake up this behavior by patching the Zend Decoder.php we ship with apachesolr:
see also: http://us2.php.net/manual/en/function.json-decode.php#95935
Comment #10
cpliakas commentedOK interesting, and thanks for the code. I am trying to figure out whether this is a per-facet settings. I am also trying to figure out whether this functionality is backend agnostic enough to be included in Facet API. If it is not, then Facet API obviously it needs to provide the mechanism for Apache Solr to add this functionality as a perk of using that backend. Would be curious to hear your opinions on this, because I am still wrapping my head around it.
Comment #11
pwolanin commentedWell, I'm pretty sure Lucene would be able to support it too, but not sure about e.g. the Elastic search front end to Lucene (not seeing any explicit support in the term facet docs), and a quick look at Sphinx I don't see it.
In term of UI, see also discussion at: https://issues.apache.org/jira/browse/SOLR-2168
For the velocity engine, Erik decided on a UI of
<em><no ${field.name}></em>Comment #12
pwolanin commentedMarc points out this example which I didn't read closely enough which indecates that Elastic search does have this - note "missing"
http://www.elasticsearch.org/guide/reference/api/search/facets/
Comment #13
pwolanin commentedrelated: #784282: OR faceting with facet.missing won't work
Apparently a Solr issue that you can't to facet missing filters as part of an OR facet. Just confirmed on Solr 3.1 also that it fails.
So, at least for the Solr backend, can we add validation to prevent this combination?
Comment #14
pwolanin commentedHere are paired patches for facetapi and apachsolr.
This make a variety of changes, including having the map callback return an array with possible #markup and #html keys.
Comment #15
pwolanin commentedoops - there was some cruft left in the apachesolr patch from when I was figuring out the html bit.
Comment #16
pwolanin commentedOne more minor fix - check that 'facet missing allowed' is TRUE in apachesolr.
Comment #17
cpliakas commentedThe patch does not apply to HEAD, will spend a little time re-rolling the patch. I think that the overall direction is good though.
Comment #18
cpliakas commentedFacet API patch re-rolled, changing to a task.
Comment #19
cpliakas commentedI tested the patch and it does seem to work. I do have a coupe of thoughts on it, though.
First, I'm not a big fan of the FacetapiAdapter::supportsFacetMissing() method. I would rather see that as an "allow missing" key in the hook_facetapi_searcher_info() definition for the adapter and then have an allowMissing() method as a wrapper around that setting so the adapter doesn't have to override it. That way the backend settings are set in one location and it reduces the amount of code in the implementing adapter.
Second, I see the need for the FacetapiAdapter::getFacetFormValidators() functionality. There is actually parallel work going on at #1158254: Allow plugins to add settings to the facet configuration forms and provide default values that would eliminate the need for this method while allowing the adapter to add a validation handlers like you would in any hook_form_alter(). The plugins are using a paradigm where they have a settingsFrom() method, so I think keeping that consistency will keep things more transparent. See the FacetapiDependencyBundle::settingsForm() for a working example.
Overall I really like the direction of the patch and (finally) see the use case and the need. Marking as postponed because I want to complete the issue posted above, and I also want to complete #1158386: Rework the UI of the facet display settings form to imrpove the site builder exprience because to me it is a bigger priority and it works in the same areas of the patch for this issue.
Comment #20
cpliakas commentedThe other issues are resolved. Marking the task as "needs work" so we can finish this off.
Comment #21
pwolanin commentedrefreshed patches.
Comment #22
cpliakas commentedCreated feature branch for each project and committed these patches for further iteration.
Apache Solr: 912758-missing
Facet API: 912758-missing
Comment #23
cpliakas commentedJust to get the conversation back in the public, I am concerned that the map callback has to determine whether the field is #markup or #html and has to return the array depending on whether a value is empty. This is a tough issue that @pwolanin spent a lot of time on, so there may be no way around it.
Comment #24
pwolanin commentedI agree it's ugly, but fundamentally I think the map callback is the only place where sufficient information exists to know that a certain value is safe HTML, or is supposed to be plain text. This may vary per value, (e.g. we want to use an EM tag for the missing facet) so it's not something you can set overall per facet.
We also have to pass this information back via getMappedValue() so we can properly display the mapped value in the breadcrumb and current search block.
Comment #25
cpliakas commentedIt's not super ugly. I am trying out a solution that is very much based on yours but with some minor differences. Instead of the facet passing "facet missing allowed", what if we passed the actual "missing value"? That way we could leave the map callbacks as they are and then add the #html if FacetapiFacetProcessor::mapValues() after the array_walk() function invocation? So something like the following:
Comment #26
pwolanin commentedWell, no, I don't think that's right. Only in this particular case did the back-end decide the missing facet mapped values needs HTML. It's not generically a property of the missing facet.
Also, there is no reason that any given facet value might have similar markup depending on the map callback. e.g. imagine I alter the map callback for author name from uid and it returns something like:
Comment #27
pwolanin commentedAn alternative that's slightly uglier, but would allow the typical map callback to return scalar values would be to use an is_array() test in facetapi_replace_ids().
Comment #28
cpliakas commentedRegarding #27, I think you are right in that we would be adding more ugliness.
Regarding #26, regardless of whether the missing value returns HTML or not the sanitization / rendering should have been done in theme_facetapi_facet_missing(), so passing HTML as TRUE is fine in all instances as to not double encode anything.
I see the issue with the breadcrumbs, though. $this->map would have to contain #html and #markup, and getMappedValue() would have to return an array with the same keys as well, like you have.
Comment #29
pwolanin commentednote that apachesolr is doing
$map[$key]['#markup'] = field_filter_xss($key);for all values to pass through the same things as the filed module, hence all have to be marked with #html as TRUE.Here's a new patch that implements the is_array() check. Also replaces the facetapi_replace_ids() callback and array_walk() with a foreach().
Also, there's no requirement that the map callback use the theme function facetapi supplies - it can do something else to format the missing value. I just added that as a convenience.
Comment #30
cpliakas commentedI think what you proposed works, so let's commit. Good work, and commit to the 7.x-1.x branches of both modules when ready. Deleting the topic branches.
Comment #31
pwolanin commentedcommitted these patches per IRC discussion. Adds a isset() check to the admin form to avoid notices.