Re-work the facet API so that modules can interact with individual facets as opposed to the entire batch. This will pave the way for the "Search Lucene Facetabs" module allowing developers to implement facets as separate search tabs. It will also pave the way for contributed UI modules to add a usability layer to Search Lucene API.

Comments

cpliakas’s picture

The internal facet API has been stripped from the core module and is now a separate module in the contrib.

shunting’s picture

Maybe I'm not grokking the modules yet, but this in luceneapi_node seems confusing:

// appends facet queries for facets that are enabled
if (luceneapi_facet_enabled($module, $module, 'Content type')) {
_luceneapi_node_append_type_query($query);
}
if (luceneapi_facet_enabled($module, $module, 'Taxonomy')) {
_luceneapi_node_append_taxonomy_query($query);
}
if (luceneapi_facet_enabled($module, $module, 'Author')) {
_luceneapi_node_append_user_query($query);
}
if (luceneapi_facet_enabled($module, $module, 'Changed after')) {
_luceneapi_node_append_changed_query($query);
}
if (luceneapi_facet_enabled($module, $module, 'Created after')) {
_luceneapi_node_append_created_query($query);
}

I don't get why these facet functions are hard-coded. It feels more "Drupal-esque" to start with an array like array('Content type,' 'Taxonomy','Author','Changed after','Created after') and then loop through the array with a function call like '_luceneapi_node_append_' . $name . '_query' and as a bonus you could merge CCK fields in to the array, too (assuming the query naming convention was adhered to). Then again, I don't know where the facet names like "Content type" come from (they look like field labels instead of field names).

cpliakas’s picture

This is very confusing, and I will be the first to admit is sucks. Luckily, I blew up the facet API this week as if proved to be inflexible. I will commit the new one this weekend. It is more intuitive, requires less coding for the programmer, and you will be able to render facets as a fieldset like the core search or like a drill down list in the style of the "Faceted Search" module.

shunting’s picture

OMFG.... Sounds like what I'm looking for. As soon as it's up, I'll install and start testing it.

(

It feels to me, BTW, that CCK fields are really trying to be part of the node_content module.

If the idea is that every contrib module is going to create its own index via hook_luceneapi_index (as I understand the README to say) then it's not clear to me why there needs to be one index for "content" and a second index for "CCK content" -- though maybe this is a Lucene thing, and in fact this is exactly the right way to do things.

OTOH, does it makes sense to have contrib modules ONLY for facets, and to somehow leverage the existing node index with hook_luceneapi_query_alter or hook_luceneapi_document_alter ????

In any case, maybe this is all off base. I had just decided that CCK and content were trying to be one thing, not two, and so I was about to hack the node_content module. Now I don't need to do that, so thanks in advance. Let me know if there is any help I can give...

)

shunting’s picture

[dupe]

cpliakas’s picture

Just in response to the quote above, modules do not have to create separate indexes if they want to add CCK data. Module can simply append CCK data as Lucene fields to the luceneapi_node index via hook_luceneapi_document_alter() and then create their own facets by implementing hook_luceneapi_facet().

cpliakas’s picture

Status: Active » Fixed

The 1.0 Facet API has been thrown out because it proved to be less flexible than intended. The new Facet API allows for easier facet definitions in the hook, and more control over where and how the facet is displayed. Instead of being integrated into Search Lucene API, the facets are broken out into a separate module called "Search Lucene Facets" that lives in the contrib directory. You may want to enable the "Search Lucene Facets" block in Admin -> Blocks after installing the module.

The 2.0 Facet API implements the idea of facet "realms". Simply put, a realm displays facets in a similar fashion on some part of the page. For example, the "fieldset" realm displays facets as form elements similar to the core content search, whereas the "block" realm displays them as links so you can have drill-down functionality similar to the Faceted Search module. The Search Lucene Facets admin page lets you enable and disable facets for the different realms.

Realms are defined in hook_luceneapi_facet_realm() implementations as arrays such as the following:

/**
 * Implementation of hook_luceneapi_facet_realm().
 */
function luceneapi_facet_luceneapi_facet_realm() {
  $realms = array();

  // adds a faceted search block similar to the Faceted Search module
  $realms['block'] = array(
    'title' => 'Block',
    'callback' => 'luceneapi_facet_block_facet_render',
    'callback arguments' => array(),
  );

  return $realms;
}

In the above instance, the array key is the machine readable name of the realm. The callback is what converts the facet arrays (see below) to something that can be passed to a theme function or drupal_get_form().

Facets are defined in hook_luceneapi_facet() implementations.

/**
 * Implementation of hook_luceneapi_facet().
 */
function luceneapi_node_luceneapi_facet($module, $type) {
  if ($type != 'node') {
    return;
  }
  $facets = array();

  // gets node types, defines content type facet
  $facets['type'] = array(
    'title' => t('Content type'),
    'element' => 'type',
    'field' => 'type',
    'type' => 'checkboxes',
    'weight' => 10,
    'callback' => 'luceneapi_facet_multiterm_callback',
    'callback arguments' => array(
      luceneapi_facet_value_get('type', array()), 'type'
    ),
    'values' => array_map('check_plain', node_get_types('names')),
    'description' => t('Filter by content type.'),
  );

  return $facets
}

Similar to realms, the machine readable name is the array key. The callback function is what is used to add the subquery to the query passed by the user. I won't go into building queries programatically here, as that is a big discussion that is currently being documented. The "type" key is used for realms that convert facets to form elements.

The internal flow is as follows:

  • The code adds facets to the page. For the "block" realm, it does this in luceneapi_facet_block(). For the "fieldset" relam, it does this in luceneapi_facet_form_alter(). The function used to get the facets is luceneapi_facet_realm_render(). This function ultimately calls the callbacks defined in hook_luceneapi_facet_realm(). The above hook_luceneapi_facet_realm() example uses luceneapi_facet_block_facet_render() as the rendering function.
  • The facet rendering function then gets the facets defined in hook_luceneapi_facet() implementations that are enabled for the realm.
  • It then invokes hook_luceneapi_facet_alter() so developers can modify the facet array before it is rendered.
  • The facet array is then rendered, or transformed into some normal structure i.e. FAPI form elements.
  • After the array is processed, the rendering function calls hook_luceneapi_facet_postrender_alter() so you can have one final crack at the processed array. This hook is very useful for decorating and manipulating the form elements in the fieldset realm (see luceneapi_node_luceneapi_facet_postrender_alter()).
  • The normalized array is then passed to a theming function or appended to a FAPI array.
  • When the form is submitted, the subqueries that filter the results by the facets are appended via hook_luceneapi_query_alter() using the query objects returned by the facet callback functions. For example, the subquery that filters by content type is added by luceneapi_facet_multiterm_callback() in the hook_luceneapi_facet() implementation above.

The benefit of this system is that you can easily define your own realm and rendering function so you can display facets where and how you want. The realms bundled with Search Lucene Facet will be useful to most people, but the point is that contributed modules can build on top of this API to provide some really complex filtering mechanisms.

Note that the admin interface still has bugs and needs to be tweaked, and there are options that are still being added. The API is done, though, so I am marking this issue as "fixed". All feature requests should go as separate issues.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.