Comments

rooby’s picture

Although it seems that resetting the apachesolr_get_solr() static after the first query doesn't change anything so it would appear I am off track on the cause of the issue.

rooby’s picture

It would appear that my problem is apachesolr_static_response_cache().

If I run my query and then unset the response for that searcher in &drupal_static('apachesolr_static_response_cache') then it seems to work.

Would you say this is the correct solution?

Are there any plans to have a function people can call to do secondary queries that don't affect the main page search/facets/etc?

rooby’s picture

Even just having another param that controls whether or not apachesolr_do_query() calls apachesolr_static_response_cache() and apachesolr_current_query() would be a start.

It does mean that apachesolr_search_preprocess_search_results() would not work for these types of searches, which doesn't matter for me and there isn't really an easy way around anyway.

rooby’s picture

I've got around the problem by using a custom apachesolr_do_query() without any caching. I'll turn it into a patch soon and see if you think it's commitable.

I have run into another problem although you might deem it to need its own issue.

Even when I clear out the static response cache, the current query, and the solr object from their drupal_static() variables after my secondary searches, if the $base_path for the secondary search is not the same as the base path for the main search, the main search facet links are wrong.

Why does the $base_path persist through to the facets even after clearing out all those statics?

neoxavier’s picture

hello,

I have the same need.
The problem is the cache use searcher (base on name . '@' . $this->solr->getId(); ) as cache key. But, I don't know why it decided like that.

I think it would be better to use the hash of actuall query as the cache key.

What did you do to solve the issues?

pmichelazzo’s picture

Issue summary: View changes

Hi @rooby,

Did you have the patch to run this kind of scenario like you mentioned on #3? I'm trying to run a second query like you but, without success.

I just need to receive all nid's from the query without the pagination and this situation getting hard.

Thanks for any clue.

Best

rooby’s picture

@pmichelazzo

I didn't end up making a patch or anything yet but I have something that's been working for my use case for a long time now.

Since in this case I am calling apachesolr_do_query() myself from custom modules instead of using the apachesolr search module, I replicate that function in one of my custom modules and make some changes then call that when I want a search that is not affected by the main search.
Essentially I'm just removing the cache read and write parts from that function.

So I have this:

<?php
/**
 * Do a standalone solr query without affecting query caches, page facets, etc.
 *
 * apachesolr_do_query sets query caches and will load from that cache instead
 * of running a new query if there is already one in there for the current page
 * load.
 * This is so that facets and other things can access the query for the current
 * page but also means that you can't run multiple queries on the same page.
 * This function allows for running additional queries on a page that don't deal
 * with this query cache.
 *
 * @see apachesolr_do_query()
 */
function MYMODULE_do_standalone_query(DrupalSolrQueryInterface $current_query) {
  if (!is_object($current_query)) {
    throw new Exception(t('NULL query object in function apachesolr_do_query()'));
  }

  // Allow modules to alter the query prior to statically caching it.
  // This can e.g. be used to add available sorts.
  $searcher = $current_query->getSearcher();

  if (module_exists('facetapi')) {
    // Gets enabled facets, adds filter queries to $params.
    $adapter = facetapi_adapter_load($searcher);
    if ($adapter) {
      // Realm could be added but we want all the facets
      $adapter->addActiveFilters($current_query);
    }
  }

  foreach (module_implements('apachesolr_query_prepare') as $module) {
    $function_name = $module . '_apachesolr_query_prepare';
    $function_name($current_query);
  }

  // Cache the original query. Since all the built queries go through
  // this process, all the hook_invocations will happen later
  $env_id = $current_query->solr('getId');

  // Add our defType setting here. Normally this would be dismax or the setting
  // from the solrconfig.xml. This allows the setting to be overridden.
  $defType = apachesolr_environment_variable_get($env_id, 'apachesolr_query_type');
  if (!empty($defType)) {
    $current_query->addParam('defType', $defType);
  }

  // Normally here apachesolr_do_query() would load from caches here.
  $query = clone $current_query;

  $query->addParam('start', $query->page * $query->getParam('rows'));

  // This hook allows modules to modify the query and params objects.
  drupal_alter('apachesolr_query', $query);

  if ($query->abort_search) {
    // A module implementing HOOK_apachesolr_query_alter() aborted the search.
    return array(NULL, array());
  }

  $keys = $query->getParam('q');

  if (strlen($keys) == 0 && ($filters = $query->getFilters())) {
    // Move the fq params to q.alt for better performance. Only suitable
    // when using dismax or edismax, so we keep this out of the query class itself
    // for now.
    $qalt = array();
    foreach ($filters as $delta => $filter) {
      // Move the fq param if it has no local params and is not negative.
      if (!$filter['#exclude'] && !$filter['#local']) {
        $qalt[] = '(' . $query->makeFilterQuery($filter) . ')';
        $query->removeFilter($filter['#name'], $filter['#value'], $filter['#exclude']);
      }
    }
    if ($qalt) {
      $query->addParam('q.alt', implode(' ', $qalt));
    }
  }
  // We must run htmlspecialchars() here since converted entities are in the index.
  // and thus bare entities &, > or < won't match. Single quotes are converted
  // too, but not double quotes since the dismax parser looks at them for
  // phrase queries.
  $keys = htmlspecialchars($keys, ENT_NOQUOTES, 'UTF-8');
  $keys = str_replace("'", '&#039;', $keys);
  $response = $query->search($keys);
  // Normally here apachesolr_do_query() would save to caches here.
  return array($query, $response);
}
?>

So I replaced:

<?php
  $query = apachesolr_current_query($env_id, $current_query);

  // Verify if this query was already executed in the same page load
  if ($response = apachesolr_static_response_cache($searcher)) {
    // Return cached query object
    return array($query, $response);
  }
?>

with:

<?php
  $query = clone $current_query;
?>

And removed this:

<?php
  // The response is cached so that it is accessible to the blocks and anything
  // else that needs it beyond the initial search.
  apachesolr_static_response_cache($searcher, $response);
?>

Then in my modules I use the normal apachesolr_do_query() function for main searches and MYMODULE_do_standalone_query() for additional searches that I don't want to affect or be affected by the main search.

pmichelazzo’s picture

Hi @roobi, thanks for the code and tips.

Just one question. I'm trying to use it but I'm receiving an error in my log, like: __clone method called on non-object in

Like you, I replace the apachesolr_current_query call for for the $query = clone $current_query; and nothing happens.

I know that's my fault but I don't know where.

May you help me?

Best

rooby’s picture

It must be with the way you are calling the function.
You have to pass in an object parameter of type DrupalSolrQueryInterface, like you do with apachesolr_do_query().

Because in this case my searches are all custom code, to generate a query object for the query I want to run I use the apachesolr_drupal_query() function.

pmichelazzo’s picture

@rooby, I just need to say thank you!

I made some changes in your function to fit what I need and it's working like a charm, taking me off a huge weight from my shoulders.

Again, thank you.

Best regards.

rooby’s picture

No problem