Problem/Motivation

Currently, it's impossible to pull query suggestions from different collections/front-ends. Only the one collection/frontend combo selected in the Drupal Google Appliance configuration screen. There could be many reasons to use different collections/frontends for different query suggestion sets. The reason initially proposed was different languages provided by different collections/frontends to return suggestions in the right language.

Proposed resolution

Implement a alter/hook to provide google_appliance_suggest_callback.php with a different site/frontend. If none are provided, we can still default to what's currently being used.

User interface changes

There should be no user interface changes required.

API changes

We may be need to add a hook_google_appliance_suggest_query_alter().

Original report by wavepoint

Hi there,

I've found that when using this module with i18n it isn't able to pass the appropriate language via users session. The primary reason for this I thought, was because the bootstrap process was set to variables, which doesn't include language information. After some changes to bootstrap full, I've found that when passing the language variable, it's only passed as the sites default. I believe this is cause due to initiating a second bootstrap, which creates a secondary user session due to the way the google_appliance_suggest_callback.php is coded.

Instead of having the JavaScript form callback go directly to the google_appliance_suggest_callback.php page, I'm looking at creating a menu router, and sending it through the main module instead. This way google_appliance_suggest_callback.php won't need it's own bootstrap process, which is un-necessary.

A secondary option could be to make the language part of the request call to the callback.php page, however I don't like the idea of exposing this URL to a PHP page directly.

Overall the module works great, but doesn't play nice with Internationalization (i18n) so I'll see what I can do to contribute.

Thanks,
Steve

Comments

iamEAP’s picture

The reason it goes through the secondary bootstrap process is performance. Going the usual menu router route would mean that Drupal would be fully bootstrapped (almost) every keystroke when someone searches. I'd prefer to keep to improve the secondary boostrap process over adding a menu router option, but we'll see how things progress.

Is GSA capable of returning query suggestions specific to a language anyway? If so, do you know how? I'd be interested in this functionality.

cdnsteve’s picture

Status: Active » Needs review
StatusFileSize
new10.46 KB

Here's the code which enables i18n support, through the Admin interface, it also disables the last part of the JavaScript due to errors in IE 7.
It also provides input filtering on the $_GET request before sending it to the GSA for security reasons.

Thanks,
Steve

iamEAP’s picture

Status: Needs review » Needs work

Thanks for the patch, @cdnsteve.

Could we open separate issues for the following from your patch?

  • IE7 JavaScript errors
  • Filtering search queries before sending them to the GSA

Regarding the i18n support, it appears your patch appends the language to the collection/frontend. While that may suit your particular use-case, I don't believe this naming convention for frontends/collection is necessarily common practice. In other words, it's not specifically multilingual support (although it could be), it's actually just the ability to dynamically alter the frontend/collection. Maybe a drupal_alter/hook would be better suited, so you could perform that modification in your own module?

cdnsteve’s picture

It's my first Drupal patch attempt so my apologies if it's not following the normal conventions!
I'll separate those two issues into new items and submit patches.

You're correct it's specific to my particular configuration. I never considered a drupal_alter or hook, I'll look into doing that. Thanks :)

iamEAP’s picture

Title: i18n - multiple languages issue » Allow alteration of collection/frontend when getting query suggestions

@cdnsteve Didn't know it was your first patch attempt. Very cool! A couple of other notes: your patch above also included some packaging details that Drupal adds automatically. Not 100% sure how that got in there, but you might find this page useful for creating patches for this particular module.

Back to the main issue: after digging into GSA documentation, I can't find any specific multilingual support for query suggestions (no extra variables to pass, for instance). As hinted at by patches/suggestions previously, the best we can do is to allow other modules to dynamically alter the frontend/collection before making the suggestion query to the GSA.

I think a hook_google_appliance_suggest_query_alter just before the query is sent and a hook_google_appliance_suggest_results_alter before the results are displayed should be more than adequate. I'd still really prefer to keep this in the alternate bootstrap rather than adding a menu callback, but I'm not sure how well alters/hooks will play in the alternate bootstrap process.

iamEAP’s picture

Issue summary: View changes

Updating issue using d.o issue template.

iamEAP’s picture

And actually, after digging into the code a bit, I think the best we can do in terms of altering the site/client is to append them to the file name in the autocomplete path, and change the callback to expect it in the form of:

/path/to/google_appliance_suggest_callback.php/site/client/token

If we're going to introduce that kind of a pattern, though, we could get away with passing everything we're forced to get via variable_get() in the callback, and using a lower bootstrap level in the callback. Something like...

/path/to/google_appliance_suggest_callback.php/cache/hostname/timeout/max/site/client/token

Allowing us to avoid loading all modules in DRUPAL_BOOTSTRAP_VARIABLES, and potentially avoiding database initialization completely if the user opts not to cache the suggestions.

A hook/alter interface for editing those variables is still desirable, though.

cdnsteve’s picture

I should back up an explain where my issue is coming from a bit more.
I think the issue in my case is because of the way the google_appliance module operates. It only allows for one collection and frontend to be specified, in my case, for a multilingual site is a problem. As a work around for this, I've already used their hook_gsa_google_appliance_query_alter and sent in my current language to be appended to the frontend and collection name.

What is actually stored in the interface and DB for collection and frontend is only half of what's needed.
EG:
Collection;
mysite

The GSA's actual collection is mysite_en and mysite_fr.

I hook on and alter the collection to be mysite_lang, similar to what I've changed in this patch.

GSA Suggest doesn't seem to have a language parameter we can pass as you said. However, the suggest data that is returned from the GSA depends on the current Frontend defined in the module. Therefore, if you have two different language Frontends, with respective collections (multilingual site), the terms become intermixed and create bad results. It becomes important to separate these search suggestions or the data in the GSA will not be what you expect.
As a side note, I did find something in their documentation that might be useful, if you go to your GSA URL http://yourgsa/ss.js they have a pre-made JavaScript file for use. I haven't looked to deeply into this yet.

In my case of using the external bootstrap with this file, no language is passed from the current users session from i18n, so it doesn't work.
I agree that the hook_alter would work well, so everyone can customize based on their needs, similar to what I did with the google_appliance hook but this will still need leverage the menu hook.

// allow implementation of hook_google_appliance_query_alter() by other modules
drupal_alter('google_appliance_query', $search_query_data);

iamEAP’s picture

I actually tried building a version of this module when my organization's site was on Drupal 6 using the JavaScript files provided by the Appliance (the ss.js you mentioned). It was very messy and required some server reconfiguration. Check this sandbox project for details.

I may have a patch for this later today. If there isn't one here by then, others are more than welcome to chime in.

iamEAP’s picture

Status: Needs work » Needs review
StatusFileSize
new5.11 KB

Here's a patch that adds the ability to alter all aspects of the query, including: hostname, collection, frontend, timeout, whether or not to cache the result, and the maximum number of results to return. For example:

/**
 * Implements hook_google_appliance_suggest_query_alter().
 */
function MODULE_google_appliance_suggest_query_alter(&$query) {
  global $language;
  $query['collection'] .= $language->language;
}

Part of me thinks this isn't the best idea, but another part of me loves that we're adding additional functionality and making it more performant.

Some very rough benchmarking. Average time it takes to deliver query suggestion results:

  • No patch, cache disabled: 147ms
  • No patch, cache enabled: 111ms
  • Patch, cache disabled: 67.8ms
  • Patch, cache enabled: 69.4ms
cdnsteve’s picture

Curious, what are you using to do the benchmarking?
I'd like to see how fast the menu router option is.

cdnsteve’s picture

I've tried doing the following benchmark using the menu router method.

in the callback.inc

Start of the file:
function google_appliance_suggest_callback() {
$time = microtime(true);

Then when outputting
drupal_json_output($response);
$micro = $time - floor($time); // microseconds part
print $micro * 100;

Then gone directly to the URL producting the GSA query and watched the output and refreshed a few times.
57.0334911346
40.3610944748
53.8459062576
24.0187883377

It's pretty snappy, not sure if there's a better way to test this.

iamEAP’s picture

Back from holiday. Sorry for the delay!

All I did was look at the network pane of webkit's developer tools and averaged 10 visits per scenario. That being said, specific results from this will vary wildly between sites. My baseline was a very high 0.15 seconds because it was on a site with over 100 modules installed. What's important is the difference between the baseline and what's being proposed. Mine shows a ~2x gain because it ends up not having to reload all 100 of those modules into memory on the server every time a user adds a keystroke to their search query.

In an ideal world, we'd make a direct call via AJAX to the GSA unit but can't due to JavaScript's same origin policy, hence the workaround. The closer we can get to the ideal in terms of speed, the better.

What I'm less certain of is the security implications of passing all of the query parameters via the URL.

cdnsteve’s picture

I was thinking about the direct call via AJAX as well, it sounds good in theory but it doesn't work in my specific corporate environment.
The reason being is that the GSA is not directly externally available, so JavaScript doesn't work.

I haven't had time to submit my other issues but in regards to the security addition about passing query params, whether using GET or POST, I added filtering to the request first. I'd suggest adding a filter_xss or check_url to the request before sending it off to the GSA.

cdnsteve’s picture

Issue summary: View changes

Fixing malformed HTML.