Hi,

I would like to create an Alphabetical view (7.x-3.0-rc3) which shows an indexed list of my products using the 'Default node index'. I'm not willing to use regular nodes because I'm using some Search API extensions like Sort, Ranges, ...

Actually, the idea with regular nodes has been described here: http://groups.drupal.org/node/94299

So, I create a view of 'Default node index' and add a contextual filter of 'Indexed Node: Title' but I'm not able to use the 'Glossary mode' in here. Is there another way of doing this use views?

Comments

marcoka’s picture

you know that views has a sample glossary view? just use that as a starting point

jeff.maes’s picture

Status: Active » Closed (fixed)

When I build a view of 'nodes' (like the sample), there is no issue and I can use the regular 'Glossary mode' that is build-in into views.

The problem occurs when I build a view of 'Search API node index'. There is no Glossary option available for this...

I've fixed it by invoking hook_search_api_alter_callback_info() and creating a new 'field' that includes the first letter of the title. Now I can use that for filtering my results on the first letter...

rjacobs’s picture

Status: Closed (fixed) » Active

Hi Jeff,

I'm wondering if you would be willing to share your specific implementation of hook_search_api_alter_callback_info() and the related controller(s)? This could also be a nice case example of this hook's usage for reference.

I discovered that adding a glossary filter can also be accomplished with cck computed fields and facet API (so long as you index your custom field in the database), but I believe that the use of hook_search_api_alter_callback_info() would be preferred to cck computed fields.

scottsperry’s picture


/**
 * hook_search_api_alter_callback_info()
 *
 * Add first letter of last name to search index for glossary mode. Enable
 * in Workflow tab of search index.
 */
function bwm_search_api_alter_callback_info() {
  $callbacks['bwm_alter_add_first_letter_last_name'] = array(
    'name' => t('BWM first letter of last name'),
    'description' => t("BWM adds first letter of last name to indexed data."),
    'class' => 'BwmAlterAddFirstLetter',
  );

  return $callbacks;
}


/**
 * Search API data alteration callback that adds the first letter of field_last_name  for glossary mode
 */
class BwmAlterAddFirstLetter extends SearchApiAbstractAlterCallback {

  public function alterItems(array &$items) {
    foreach ($items as $id => &$item) {
      if (!isset($item->field_last_name['und'][0]['value'])) {
        $item->search_api_last_name_first_letter = NULL;
        continue;
      }
      $item->search_api_last_name_first_letter = substr($item->field_last_name['und'][0]['value'],0,1);
    }
  }

  public function propertyInfo() {
    return array(
      'search_api_last_name_first_letter' => array(
        'label' => t('First Letter of last name'),
        'description' => t('For lawyer profile glossary mode.'),
        'type' => 'text',
      ),
    );
  }

}

rjacobs’s picture

Excellent, thanks much!

ssoulless’s picture

Issue summary: View changes

Can someone explain me how to use the code above?

drunken monkey’s picture

Status: Active » Fixed

Can someone explain me how to use the code above?

Create a custom module called bwm.module (if you call it something else, you have to rename the function and class accordingly), put the function into bwm.module and the class into a separate file which you include in bwm.info. When you then enable the module, you'll get a new data alteration on your search index's "Filters" tab; and when you then enable that, you'll get a new field which only contains the first letter of the field_last_name field. (If you want to use a different field, you have to change that, too – and probably also the properties of the added field, to avoid confusion.)

If you aren't a developer, you should probably get one to do that for you. Or go through the tutorials in the handbook – this is mostly copy-paste anyways.

Status: Fixed » Closed (fixed)

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

drupak’s picture

StatusFileSize
new624 bytes

I did it a bit differently and works great. I got idea from https://www.drupal.org/project/search_api_title2 Search API Title 2 module. I changed it to my version of BWM module...module file attached...What it does is adds an extra field to the index containing only first letter of the node title. You can then use its facets as well like any other facets and can work as your glossary block.


/**
 * @file
 *   Provides first letter of titles for nodes which can be used as glossay facets
 */

/**
 * Implements hook_entity_property_info_alter().
 */
function bwm_entity_property_info_alter(&$info) {
  $info['node']['properties']['glossary'] = array(
    'type'            => 'text',
    'label'           => t('Glossary'),
    'sanitized'       => TRUE,
    'getter callback' => 'bwm_getter_callback',
  );
}

/**
 * Getter callback for Glossary property.
 *
 * @param object $item
 *   Node.
 *
 * @return string
 *   Title.
 */
function bwm_getter_callback($item) {

  return substr($item->title,0,1);
}
drupak’s picture

StatusFileSize
new624 bytes
ludo.r’s picture

In my current project I'm not allowed to use custom code.
Is it possible to do that without any custom module and without an additional module (cck computed fields) ?

To summarize, is it possible to do that with Search API + Facet API only?

ludo.r’s picture

Status: Closed (fixed) » Active
ludo.r’s picture

Subsidiary question: has #9 code any chance to be included in Search API module (or related)?

drunken monkey’s picture

Version: 7.x-1.0 » 7.x-1.x-dev
Component: Views integration » Plugins
Category: Support request » Feature request
Status: Active » Needs review
StatusFileSize
new2.03 KB

Subsidiary question: has #9 code any chance to be included in Search API module (or related)?

In this or a similiar form, no – but we could add this as a mode to the "Aggregated fields" data alteration, which should work just as well.
Patch attached, please see if this would work for you and makes sense in your opinion!

drunken monkey’s picture

So? Anybody in favor of adding this, and able to do a quick test whether it works as intended?

fengtan’s picture

Tested #14 and it works like a charm - many thanks !
Maybe someone else can confirm ?

fengtan’s picture

StatusFileSize
new2.05 KB
new79 bytes

Actually, maybe we could also make the facets case insensitive -- like, instead of having 2 facets for each letter ('a' and 'A'), we could have a single one ('A').
Patch attached. Though maybe there is a better way to do that ?

fengtan’s picture

If anyone wishes to use this functionality without patching search_api, this sandbox module may help: http://drupal.org/node/2428963

drunken monkey’s picture

Status: Needs review » Fixed

Actually, maybe we could also make the facets case insensitive -- like, instead of having 2 facets for each letter ('a' and 'A'), we could have a single one ('A').
Patch attached. Though maybe there is a better way to do that ?

If people want that, they can just use the "Ignore case" processor. No need to hardcode that into this data alteration.
But, in any case, thanks a lot for testing, good to hear it works!
Committed.

  • drunken monkey committed fee782c on 7.x-1.x
    Issue #1396222 by drunken monkey: Added a "First letter" aggregation...

Status: Fixed » Closed (fixed)

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

drunken monkey’s picture

Version: 7.x-1.x-dev » 8.x-1.x-dev
Status: Closed (fixed) » Patch (to be ported)
Issue tags: +Novice

We forgot to port this to Drupal 8 (see #2765317-18: Aggregation Type - Last).

loziju’s picture

Status: Patch (to be ported) » Needs review
StatusFileSize
new1.91 KB

@drunken monkey, the patch was created against 8.x-1.17, but it should work with 1.x-dev. I'm not sure yet how to write the test for this though, somehow majority of the tests still fail even though I already configure simpletest. Rushing for using the patch now, so I just submit this first.

##Outstanding task
reviewing the patch and writing the test are the remaining outstanding tasks.

loziju’s picture

Alright, I just focus on adding the unit test for the new first_char aggregation function and assume that the other tests should work.

And this patch is now generated against 1.x-dev.

Kindly review. Thanks!

aaronpinero’s picture

I can verify that the patch in #24 works for me when applied to 8.x-1.17 in Drupal 8.9.3.

Thank you for this. I had been hunting around for something like this that would work with Search API.

drunken monkey’s picture

Huge thanks for picking this up, very much appreciated!
However, in D7 this always just returned a single value (so, just the first character of the first value) and also uppercased it. I think it makes sense to keep that consistent?
See attached patch and please test/review!

Anyways, thanks a lot again!

drunken monkey’s picture

Any feedback on this? Can this be committed in the current form (#26)?

loziju’s picture

Sorry, I didn't have time to check the patch in #26. The interdiff looks alright.

I agree with you to keep the previous behaviour for consistency / backward compatibility. However, can I suggest that we change the description to include this detail? I didn't interpret the term "first encountered field value" as the first delta. :)

How about something like this?
The "First letter" aggregation uses just the first letter of the first encountered field value as the aggregated value. For a multi-value field, only the first letter of the first field value is indexed. This can, for example, be used to build a Glossary view.

drunken monkey’s picture

StatusFileSize
new798 bytes
new2.9 KB

We already use the same phrasing for “First” and “Last”, so it would be confusing in all those cases. Maybe to clarify we should just add something to the general description for the aggregation type? For instance, how about this:

Apart from the Union type, all types will result in just a single value.

Added in the attached patch, please review!
Also, it would be great to get at least a single real-world test before committing this.

capysara’s picture

Not exactly "real-world", but it works on simplytest.me

Launch sandbox

  1. create some nodes of type: Basic page /node/add/page
  2. Install/enable Database Search & Database Search Defaults - /admin/modules
  3. Edit Default content index fields /admin/config/search/search-api/index/default_index/fields
  4. Add fields
  5. Add: General Aggregated field
  6. Aggregation type: First letter
  7. Contained fields: Content » Title
  8. Save
  9. Done
  10. Save Changes
  11. Index Now /admin/config/search/search-api/index/default_index
  12. Add view /admin/structure/views
  13. Show Index Default content index
  14. Enable: Create a page
  15. Page display settings: Display format: unformatted list of Rendered entity
  16. Disable Use a pager
  17. Save and edit
  18. Add contextual filter
  19. Aggregated field: A First letter aggregation of the following fields: Content » Title.
  20. Click Add and configure contextual filters
  21. Apply
  22. Save view
  23. Go to page url, e.g., /test-glossary
  24. Verified that contextual filter gives correct results based on the first letter of first word in the titles, e.g., /test-glossary/m
drunken monkey’s picture

Thanks a lot for that thorough description, looks good.
Any opinion on the added description line? Would you say the patch is RTBC?

capysara’s picture

Status: Needs review » Reviewed & tested by the community

Makes sense to me! Most of the types imply that they result in a single value, but the description makes it clearer. Very minor note: The "First letter" is the only type that puts the aggregation type in quotes. I don't think it's necessary, but it's also not really important either way.

RTBC as far as I'm concerned.

  • drunken monkey committed 8fa4fb2 on 8.x-1.x
    Issue #1396222 by drunken monkey, loziju, capysara: Added the "First...
drunken monkey’s picture

Status: Reviewed & tested by the community » Fixed

Great to hear, thanks a lot for your feedback.
(Fixed some code style issues and) Committed.
Thanks again, everyone!

Status: Fixed » Closed (fixed)

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

artusamak’s picture

If the feedback may help, i used this patch in an IRL situation and it helps indexing a value first letter.

Two warnings though: first, you won't be able to do it on every property of the index (eg: if you want to aggregate the first letter of a title of an entity referenced field, it won't be accessible). Second, you still won't have views glossary feature accessible for your exposed filter.
I built this by using the aggregated first letter as a grouping value and duplicated this logic in an attached display (similarly to the glossary example view) to generate the glossary header. I also had to override templates to build the anchors and removed extra output unwanted.

This said, it still would be interesting to have the bridge built to benefit from core Glossary (in \Drupal\views\Plugin\views\argument\StringArgument).
I didn't have time to dig into it but i'm wondering if it would be hard to let SAPI string properties exploit this handler.

My 2 cents.