I have a Solr view i'd like to sort by popularity, i.e. by "Apache Solr Node statistics: Total views", but it's not offered as a sort criterion in the Views UI. So i followed a few leads and managed to add it into the sort criteria by adding this to my custom module:

/**
 * Implementation of hook_views_data_alter()
 *
 * Exposes new fields and sorts to views
 */
function mymodule_views_data_alter(&$data) {
	$data['apachesolr_node']['totalcount'] = array(
		'title' => t('Total views'),
		'help' => t('The total number of views for this node.'),
		'field' => array(
			'handler' => 'views_handler_field_node_type',
			'click sortable' => TRUE,
		),
		'sort' => array(
			'handler' => 'apachesolr_views_handler_sort',
		),
    );
}

That works perfectly: it's now offered as a search criterion in the Views UI, and it can be exposed like any other sort. But it doesn't have any effect on the search results. Checking the actual GET request made to the Solr server, i see: sort=sort_title+asc,created+desc (title and created were my other exposed sorts). No mention of the totalcount sort.

Doublechecking that the field actually exists in the solr index (localhost/solr/admin), i find that it's not! I suppose the Views UI offering it as an apachesolr field must have confused me.

Anyway, my question is: am i doing something stupid, or should i just get down to it and add the totalcount field to the index myself using hook_apachesolr_update_index()?

Comments

chichilatte’s picture

Ok, i added a new is_totalcount field to the index and made sure apachesolr_views was able to use it for sorting...

/*
   hook_apachesolr_update_index() modifies the $document object before
   indexing.
*/
function mymodule_apachesolr_update_index(&$document, $node) {
	// Record the node's number of page views, if available
	if (module_exists('statistics')) {
		$stats = statistics_get($node->nid);
		if ($stats['totalcount']) {
			$document->is_totalcount = $stats['totalcount'];
		}
	}
}


/*
   hook_apachesolr_prepare_query() runs before hook_apachesolr_modify_query(),
   before query is statically cached. New sorts must be added at this point.
*/
function mymodule_apachesolr_prepare_query(&$query) {
  $query->set_available_sort('is_totalcount', array(
    'title' => t('Total views count'),
    'default' => 'desc',
  ));
}


/**
 * Implementation of hook_views_data_alter()
 *
 * Make available new fields and sorts to views
 */
function mymodule_views_data_alter(&$data) {
	$data['apachesolr_node']['is_totalcount'] = array(
		'title' => t('Total views count'),
		'help' => t('The total views count for this node.'),
		'field' => array(
			'handler' => 'views_handler_field_numeric',
			'click sortable' => TRUE,
		),
		'sort' => array(
			'handler' => 'apachesolr_views_handler_sort',
		),
    );
}

Now when i sort by is_totalcount using the exposed form, the GET request to Solr contains: sort=sort_title+asc,created+desc,is_totalcount+desc. Brilliant!

But the is_totalcount is last in the list, rather than first, so it still has no effect. I've just noticed that this also happens for the the "created" sort field too. The sort ordering in the GET request never changes! I wonder if this is a bug, or is this a unicorny feature?

chichilatte’s picture

I made a quick patch to the apachesolr_views module to allow changing the priority of sorting. Very simple change in apachesolr_views/apachesolr_views_query.inc:

  function set_solrsort($field, $direction) {
	// Patch to force only one sort (since there isn't yet a way to set the priority of multiple sort fields)
	//$this->add_sort($field, $direction);
	$this->_sorts = array();
	$this->_sorts[$field] = strtolower($direction);
  }

Then in your custom module you'd have something like...

function mymodule_apachesolr_modify_query(&$query, &$params) {
	// This doesn't actually do anything yet, but it's recommended
	$query->set_available_sort('is_totalcount', array(
		'title' => t('Total views count'),
		'default' => 'desc',
	));

	
	// Use this for normal views exposed filters
	//if (isset($_GET['sort_by'])&& isset($_GET['sort_order']))
	//	$query->set_solrsort(check_plain($_GET['sort_by']), check_plain($_GET['sort_order']));

	// And this if you're using the Better Exposed Filters module
	if (isset($_GET['sort_bef_combine'])) {
		$befcombine = check_plain($_GET['sort_bef_combine']);
		$sort = explode(' ', $befcombine);
		if (count($sort)==2) {
			$query->set_solrsort($sort[0], $sort[1]);
		}
	}
}

I would have used mymodule_apachesolr_prepare_query() instead of mymodule_apachesolr_modify_query(), but the prepare query hook didn't seem to be working for me :( Anyway i hope this is of help to someone, since sorting is surely extremely popular when doing a search. Maybe the apachesolr_views module will one day allow this so we don't need the patch?

NOTE: tested with D6.22, Views 6.x-3.0+67-dev, Apache Solr Search 6.x-1.5, Apache Solr Views Integration 6.x-1.x-dev, Better Exposed Filters 6.x-3.x-dev.
++NOTE: If you don't want to patch the apachesolr_views module, i see these people have found a more elaborate route (which is a bit of a kludge).

kenorb’s picture

Status: Active » Closed (outdated)

Version 6.x is no longer supported as of Drupal 6 End of Life. For Drupal 8.x, use Search API Solr Search instead.