Drupal 7 tip: Concurrent indexeren met search api. Concurrent queues met gebruik van de concurrency mogelijkheden van drush.

Posted by: 
Dominique De Cooman

We maakten gebruik van search api bij de bouw van onze zoekpagina’s. Terwijl deze module geweldig is voor het maken van zoekpagina’s, heeft het enkele problemen met indexering van veel nodes. Er is een patch beschikbaar http://drupal.org/node/1137734 om het geheugenbeperking probleem te voorkomen. Maar indexering terwijl search api het gebruikt is nog steeds erg traag.

De oplossing?
We willen onze nodes natuurlijk gelijktijdig indexeren. Dit zal volledige gebruik maken van uw machine en indexering snel laten verlopen.

Twee jaar ervoor was dit zelfde probleem van gelijktijdig indexeren opgelost met een truc beschreven in dit artikel.
http://dominiquedecooman.com/blog/doing-big-imports-and-apache-solr-inde... In het artikel was het concurrency probleem opgelost door het gebruik van een cron run die processen voortbracht afhankelijk van hoe hoog de belasting van de machine was. Dit werkte heel goed, maar nu is er een erg gemakkelijke manier om hetzelfde te bereiken. Twee jaar geleden drush was nog niet zo geavanceerd en drupal 7 bestond nog niet, dus geen queues in core

Hoe indexeren we onze nodes gelijktijdig?

De search api implementeert een cron queue (http://dominiquedecooman.com/blog/drupal-7-tip-cron-queues) Dit kunnen we uitvoeren om onze nodes gelijktijdig te indexeren. Het enige wat we moeten doen is het vullen van een queue met items die geïndexeerd moeten worden en vervolgens een speciale opdrachtregel te schrijven die "drush_backend_invoke_concurrent()" functie gebruikt om die queue gelijktijdig te verwerken. De functie zal een aantal items pakken in de queue, afhankelijk van hoe hoog je het concurrency-niveau instelt en verwerkt ze dan. Drush zorgt voor alles, het zal het proces stippen als het klaar is en zal indien aanwezig output leveren aan console.

In de code hebben we twee opdrachtregels. Een om de queue te vullen en een op deze te verwerken.

<?php
/**
 * Implements hook_drush_command()
 */
function dfc_drush_command() {
  
$items = array();

  
$items['search-api-add-to-queue'] = array(
    
'description' => 'Fetch all items to be indexed, and add them to the queue.',
    
'bootstrap' => 'DRUSH_BOOTSTRAP_DRUPAL_FULL',
    
'callback' => 'search_api_cron',
    
'aliases' => array('sapi-aq'),
  );

  
$items['queue-run-concurrent'] = array(
    
'description' => 'Run a specific queue by name',
    
'arguments' => array(
      
'queue_name' => 'The name of the queue to run, as defined in either hook_queue_info or hook_cron_queue_info.',
      
'concurrency level' => 'The amount of background processes to spin-off'
    
),
    
'required-arguments' => TRUE,
  );
  return 
$items;
}

/**
 * Command callback for drush queue-run-concurrent.
 *
 * Queue runner that is compatible with queues declared using both
 * hook_queue_info() and hook_cron_queue_info().
 *
 * @param $queue_name
 *   Arbitrary string. The name of the queue to work with.
 * @param $concurrency_level
 *   Amount of background
 */
function drush_dfc_queue_run_concurrent($queue_name$concurrency_level) {
  
// Get all queues.
  
$queues drush_queue_get_queues();
  if (isset(
$queues[$queue_name])) {
    
$queue DrupalQueue::get($queue_name);
    for (
$i 0$queue->numberOfItems() > $i$i++) {
      
$invocations[] = array('command' => 'queue-run ' $queue_name'site' => '@self');
    }
    
$common_options = array(
      
'concurrency' => $concurrency_level,
    );
    
drush_backend_invoke_concurrent($invocations, array(), $common_options);
  }
}
?>

Om het gemakkelijk te maken hebben we een opdrachtregel gemaakt die alle items toevoegt aan queue door het oproepen van de search_api_cron functie die alle items zal toevoegen die geïndexeerd moeten worden naar de queue.

#In terminal
drush sapi-aq

Vervolgens roepen we onze andere opdrachtregel op die als volgt zal functioneren "drush_dfc_queue_run_concurrent()":

#In terminal
drush queue-run-concurrent search_api_indexing_queue 8

Bekijk nu hoe de queue naast zichzelf nog 8 andere processen voortbrengt door de shell waar je in zit te volgen en in een andere shell te typen:

watch ps -s[id]. 

Om uit te vinden in welke shell je zit typ:

ps -ef|grep $$|grep -v grep 

(het is het derde nummer in de tweede regel) Voor meer info (http://stackoverflow.com/questions/3327013/how-to-determine-the-current-...)

Indexeren gaat nu 8 keer zo snel. Als je een grote machine hebt kun je de concurrency-niveau verhogen en zal het nog sneller gaan. Volg wel je search backend. In ons geval apachesolr zodat het de belasting aankan.

Conclusie
Deze functie/trick is herbruikbaar om elke queue in het systeem op te roepen. Het proces is altijd hetzelfde. Vul een queue met items en laat de queue gelijktijdig verwerken. Je kunt het voor elke taak doen, van het invoeren van content, feeds, indexeren.

Vermelding
Deze kleine functie is samen met Sander Van Dooren ontwikkeld. Bekijk zijn blog, hij plaatst regelmatig goede tips. http://www.sandervandooren.be/

Reactie toevoegen