parisholley / wordpress-fantastic-elasticsearch

Improve wordpress search performance/accuracy and enable faceted search by leveraging an ElasticSearch server.
MIT License
162 stars 64 forks source link

Add support for 'completion' type mapping for auto-suggest #115

Open kosso opened 9 years ago

kosso commented 9 years ago

Hi,

How hard would it be to add some mappings for a 'completion' type, to use for an auto-suggest textfield?

see : http://www.elasticsearch.org/blog/you-complete-me/

thanks.

parisholley commented 9 years ago

Would just need to add a hook/filter for the mapping process in Indexer.php, shouldn tbe too bad

kosso commented 9 years ago

That would be great. ;)

kosso commented 9 years ago

Hi. I have managed to do this in the Indexer.php and also some other specific customisations I needed in the _build_document(), _build_tax_values() and _build_field_values() methods. (Added a suggest input & payload. Also added thumbnail urls for posts)

But now it's occurred to me that this might not be the best way to go about it - ie: modifying the plugin. I've now seen that I could use the elasticsearch_indexer_build_document wordpress filter in my theme to modify the document before Indexing.

I'm not quite sure what I'm doing wrong, but I don't seem to be getting the $post data when trying this. (It does modify the document structure before indexes though:

In my theme's functions.php I have added :

add_filter('elasticsearch_indexer_build_document', function($document, $post){
    // Modify document array before it is sent to indexer
    $blog_id = get_current_blog_id();

    // How do I get the current index name from Elastica here?
    // This is how I did it in Indexer.php
    // $index = self::_index(false)->getName();

    // Build the suggest field input. 
    // Start with the post title itself
    $document['suggest']->input = array( strip_tags($post->post_title) );

    // Currently I'm also adding tags to the suggest input via Indexer.php:_build_tax_values()

    // Now create the 'suggest' payload....
    // Get the 'thumbnail' image from the WP_Post Object
    $thumb_id = get_post_thumbnail_id($post->ID);
    if($thumb_id > 0){
      $thumb_url_array = wp_get_attachment_image_src($thumb_id,'thumbnail');
      if(is_array($thumb_url_array)){
        $thumb_url = $thumb_url_array[0];
      }
    }

    // TEST
    $document['TEST'] = 'this field and data was added in the Wordpress filter in functions.php';

    $document['suggest']->payload = array( 'image' => $thumb_url, '_type' => $post->post_type, 'find_by' =>  $post->guid, 'blog_id' => $blog_id, 'post_name' => $post->post_name, 'post_date' => $post->post_date);

    // Add the image to the _source too...
    $document['image_small'] = $thumb_url;

    return $document;

  });

But it doesn't appear to have anything set in $post What am I doing wrong?

thanks. K

ps: I manually mapped the 'suggest' field for completion etc. when I created the index before running the plugin using :

suggest: {
    type: "completion",
    analyzer: "simple",
    payloads: true,
    preserve_separators: true,
    preserve_position_increments: true,
    max_input_length: 50
}

This then provides the data for an autocompletion suggestion via this POST : (for pasting into the Sense Chrome extension)

POST /_suggest
{   

    "my_autocomplete_suggest":{
        "text":"foo",
        "completion":{
            "field":"suggest"        
        }
    }
}

This data can then be consumed by a library like Typeahead.js (using the data as the remote source for Bloodhound ) to build a nice autosuggestion drop-down.

kosso commented 9 years ago

update: Argh. I just realised I was missing the $priority and $accepted_args parameters when calling add_filter()

I'm now doing it like this :

function add_suggest_and_thumbs ($document, $post){

  // Build the suggest field input. 
  // Start with the post title itself
  $document['suggest']->input = array( strip_tags($post->post_title) );

  // add tags to the suggest input here too..

  // Now create the 'suggest' payload....

  $blog_id = get_current_blog_id();

  // Get the 'thumbnail' image from the WP_Post Object
  $thumb_id = get_post_thumbnail_id($post->ID);
  if($thumb_id > 0){
    $thumb_url_array = wp_get_attachment_image_src($thumb_id,'thumbnail');
    if(is_array($thumb_url_array)){
      $thumb_url = $thumb_url_array[0];
    }
  }

  $document['suggest']->payload = array( 'image' => $thumb_url, '_type' => $post->post_type, 'find_by' =>  $post->guid, 'blog_id' => $blog_id, 'post_name' => $post->post_name, 'post_date' => $post->post_date);

  // Add the image to the _source too...
  $document['image_small'] = $thumb_url;

  // TEST
  $document['TEST'] = 'this field and data was added in the Wordpress filter in functions.php';

  // How do I get the current index name from Elastica here? I'd like to add it to the suggest payload.
  // This is how I did it in Indexer.php
  // $index = self::_index(false)->getName();

  return $document;

}

add_filter('elasticsearch_indexer_build_document', 'add_suggest_and_thumbs', 10, 2);