elasticsearch-autocomplete 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +11 -0
- data/README.md +150 -0
- data/Rakefile +8 -0
- data/lib/elasticsearch.rb +1 -0
- data/lib/elasticsearch/autocomplete.rb +16 -0
- data/lib/elasticsearch/autocomplete/filters.rb +72 -0
- data/lib/elasticsearch/autocomplete/multiple_request.rb +36 -0
- data/lib/elasticsearch/autocomplete/multiple_response.rb +6 -0
- data/lib/elasticsearch/autocomplete/request.rb +30 -0
- data/lib/elasticsearch/autocomplete/response.rb +53 -0
- data/lib/elasticsearch/autocomplete/search.rb +57 -0
- data/lib/elasticsearch/autocomplete/single_request.rb +37 -0
- data/lib/elasticsearch/autocomplete/single_response.rb +19 -0
- data/lib/elasticsearch/autocomplete/type.rb +74 -0
- data/lib/elasticsearch/autocomplete/version.rb +5 -0
- metadata +157 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: 3a632d2806037ffcbd72284c1740ffbb74e62583
         | 
| 4 | 
            +
              data.tar.gz: a5886398ab278a66e506b05bcf4909352de8b745
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 070583334041cff1cc3a18d207627fe25356769dcec49a885ec427b909ec7a44452f49ec0315bdb78d0c8d90a34b9810728f1e691055dd37cd13659a108b2f3c
         | 
| 7 | 
            +
              data.tar.gz: 6490e715fe8d4712aed10d1586bc90f2b8b11b0543db858ffa16e7d24892505aef1836f9ff811f20463631ecdc4c0c1726c70177a9374d3de4f081a81d45001e
         | 
    
        data/CHANGELOG.md
    ADDED
    
    | @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            ## 0.1.1
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            - Added {field}.beginning to filters
         | 
| 4 | 
            +
            - Added analysis filter `ngram_beginning` for analyser `beginning`
         | 
| 5 | 
            +
            - Updated specs and README to reflect addition
         | 
| 6 | 
            +
            - Current fields for `multi_field`
         | 
| 7 | 
            +
              - field, field.exact, field.beginning, field.autocomplete, field.fuzzy
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ## 0.1.0
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            - Initial Release
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,150 @@ | |
| 1 | 
            +
            # ElasticSearch Autocomplete
         | 
| 2 | 
            +
            [](https://codeclimate.com/github/spodlecki/elasticsearch-autocomplete)
         | 
| 3 | 
            +
            [](https://codeclimate.com/github/spodlecki/elasticsearch-autocomplete/coverage)
         | 
| 4 | 
            +
            [](https://travis-ci.org/spodlecki/elasticsearch-autocomplete)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Quick and simple way to perform autocomplete with ElasticSearch Servers.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            ## Installation
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            Add this line to your application's Gemfile:
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ```
         | 
| 13 | 
            +
            gem 'elasticsearch-autocomplete'
         | 
| 14 | 
            +
            ```
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            And then execute:
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                $ bundle install
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            ## Dependencies
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            - [Elasticsearch::Model](https://github.com/elastic/elasticsearch-rails/tree/master/elasticsearch-model)
         | 
| 23 | 
            +
            - [Rails > 3.2.8](http://rubyonrails.org/)
         | 
| 24 | 
            +
            - [Elasticsearch Server > 1.0.1](http://www.elastic.co)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            ## Usage
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            ### Field Explaination
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            
         | 
| 31 | 
            +
            Access each field as if they were a nested attribute (`field.fuzzy`, `field.exact`, ...).
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            ### Searching
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            **map file**
         | 
| 36 | 
            +
            (**ROOT**/lib/elasticsearch/autocomplete/**TYPE**_type.rb)
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            ```
         | 
| 39 | 
            +
            module Elasticsearch
         | 
| 40 | 
            +
              module Autocomplete
         | 
| 41 | 
            +
                class ColorType < Type
         | 
| 42 | 
            +
                  # Value of ElasticSearch's _type
         | 
| 43 | 
            +
                  # => String
         | 
| 44 | 
            +
                  def type
         | 
| 45 | 
            +
                    'color'
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  # Search Hash
         | 
| 49 | 
            +
                  # This is the entire search query for ElasticSearch
         | 
| 50 | 
            +
                  #
         | 
| 51 | 
            +
                  def to_hash
         | 
| 52 | 
            +
                    {
         | 
| 53 | 
            +
                      query: { match_all: {}},
         | 
| 54 | 
            +
                      filter: {
         | 
| 55 | 
            +
                        and: [
         | 
| 56 | 
            +
                          { term: {_type: 'color'} }
         | 
| 57 | 
            +
                        ]
         | 
| 58 | 
            +
                      }
         | 
| 59 | 
            +
                    }
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  # Return the hash to which the result is mapped from
         | 
| 63 | 
            +
                  # @method mapped
         | 
| 64 | 
            +
                  # @param source {OpenStruct} Source value from ElasticSearch result
         | 
| 65 | 
            +
                  # @return Hash
         | 
| 66 | 
            +
                  #
         | 
| 67 | 
            +
                  def mapped(source)
         | 
| 68 | 
            +
                    {
         | 
| 69 | 
            +
                      id: source.id,
         | 
| 70 | 
            +
                      name: source.name,
         | 
| 71 | 
            +
                      image: image_path(source.icon),
         | 
| 72 | 
            +
                      type: type
         | 
| 73 | 
            +
                    }
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  # Optional to set
         | 
| 77 | 
            +
                  # If you intend on using any of the helpers, this will need to be set
         | 
| 78 | 
            +
                  #
         | 
| 79 | 
            +
                  def field
         | 
| 80 | 
            +
                    :name
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
            end
         | 
| 85 | 
            +
            ```
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            **controller**
         | 
| 88 | 
            +
            ```
         | 
| 89 | 
            +
            # Search Multiple Types, each with their own query
         | 
| 90 | 
            +
            search = Elasticsearch::Autocomplete::Search.find(index_string, params[:term], ['actress'])
         | 
| 91 | 
            +
            search.results # => []
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            # Multiple Types, with a single result set
         | 
| 94 | 
            +
            # @param index {String} ElasticSearch Index Name
         | 
| 95 | 
            +
            # @param term {String} Query String being searched
         | 
| 96 | 
            +
            # @param types {Array} Array of types being searched for in ElasticSearch
         | 
| 97 | 
            +
            # @param multisearch {Boolean} Are we splitting each type into its own query?
         | 
| 98 | 
            +
            # @param field {String|Symbol} If doing a single query, pass the name of the field to be searched
         | 
| 99 | 
            +
            search = Elasticsearch::Autocomplete::Search.find(index_string, params[:term], ['actress'], false, :name)
         | 
| 100 | 
            +
            search.results # => []
         | 
| 101 | 
            +
            ```
         | 
| 102 | 
            +
             | 
| 103 | 
            +
            **model indexing**
         | 
| 104 | 
            +
            ```
         | 
| 105 | 
            +
            # Assuming you are using Elasticsearch::Model as your indexing tool
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            mapping do
         | 
| 108 | 
            +
              # ...
         | 
| 109 | 
            +
              indexes :field_name, Elasticsearch::Autocomplete::Filters.config(:field_name)
         | 
| 110 | 
            +
              # ...
         | 
| 111 | 
            +
            end
         | 
| 112 | 
            +
            ```
         | 
| 113 | 
            +
             | 
| 114 | 
            +
            ## Development
         | 
| 115 | 
            +
             | 
| 116 | 
            +
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         | 
| 117 | 
            +
             | 
| 118 | 
            +
            ## Type Helper Methods
         | 
| 119 | 
            +
             | 
| 120 | 
            +
            ```
         | 
| 121 | 
            +
            def image_path(image_string)
         | 
| 122 | 
            +
              # => Generates an asset url for an image
         | 
| 123 | 
            +
            end
         | 
| 124 | 
            +
            ```
         | 
| 125 | 
            +
             | 
| 126 | 
            +
            ```
         | 
| 127 | 
            +
            # https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
         | 
| 128 | 
            +
            # Quickly use the multiple fields matcher search format
         | 
| 129 | 
            +
            # Usage: { query: multi_match({exact: 30}) }
         | 
| 130 | 
            +
            #
         | 
| 131 | 
            +
            def multi_match(rank_overrides={})
         | 
| 132 | 
            +
              ranks = {exact: 10, beginning: 7, autocomplete: 5, fuzzy: 1}.merge(rank_overrides)
         | 
| 133 | 
            +
             | 
| 134 | 
            +
              {..}
         | 
| 135 | 
            +
              # => returns built hash for the multi_match query
         | 
| 136 | 
            +
            end
         | 
| 137 | 
            +
            ```
         | 
| 138 | 
            +
             | 
| 139 | 
            +
            ## Contributing
         | 
| 140 | 
            +
             | 
| 141 | 
            +
            1. Fork it
         | 
| 142 | 
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         | 
| 143 | 
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         | 
| 144 | 
            +
            4. Push to the branch (`git push origin my-new-feature`)
         | 
| 145 | 
            +
            5. Create new Pull Request
         | 
| 146 | 
            +
             | 
| 147 | 
            +
            ## TODO
         | 
| 148 | 
            +
             | 
| 149 | 
            +
            - Create generator for new types
         | 
| 150 | 
            +
            - Get codeclimate online
         | 
    
        data/Rakefile
    ADDED
    
    
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            require 'elasticsearch/autocomplete'
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            require 'elasticsearch/autocomplete/version'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'elasticsearch/autocomplete/filters'
         | 
| 4 | 
            +
            require 'elasticsearch/autocomplete/type'
         | 
| 5 | 
            +
            require 'elasticsearch/autocomplete/request'
         | 
| 6 | 
            +
            require 'elasticsearch/autocomplete/multiple_request'
         | 
| 7 | 
            +
            require 'elasticsearch/autocomplete/single_request'
         | 
| 8 | 
            +
            require 'elasticsearch/autocomplete/response'
         | 
| 9 | 
            +
            require 'elasticsearch/autocomplete/multiple_response'
         | 
| 10 | 
            +
            require 'elasticsearch/autocomplete/single_response'
         | 
| 11 | 
            +
            require 'elasticsearch/autocomplete/search'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            module Elasticsearch
         | 
| 14 | 
            +
              module Autocomplete
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,72 @@ | |
| 1 | 
            +
            # TODO
         | 
| 2 | 
            +
            # Add beginning of entire string rank
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Elasticsearch
         | 
| 5 | 
            +
              module Autocomplete
         | 
| 6 | 
            +
                module Filters
         | 
| 7 | 
            +
                  module ClassMethods
         | 
| 8 | 
            +
                    def analysis
         | 
| 9 | 
            +
                      {
         | 
| 10 | 
            +
                        analysis: {
         | 
| 11 | 
            +
                          analyzer: {
         | 
| 12 | 
            +
                            simple: {
         | 
| 13 | 
            +
                              type: "custom",
         | 
| 14 | 
            +
                              tokenizer: "standard",
         | 
| 15 | 
            +
                              filter: [ "standard", "lowercase", "stop" ]
         | 
| 16 | 
            +
                            },
         | 
| 17 | 
            +
                            autocomplete: {
         | 
| 18 | 
            +
                              type: "custom",
         | 
| 19 | 
            +
                              tokenizer: "standard",
         | 
| 20 | 
            +
                              filter: [ 'asciifolding', "standard", "lowercase", "stop", "kstem", "ngram_front" ]
         | 
| 21 | 
            +
                            },
         | 
| 22 | 
            +
                            fuzzy: {
         | 
| 23 | 
            +
                              type: "custom",
         | 
| 24 | 
            +
                              tokenizer: "standard",
         | 
| 25 | 
            +
                              filter: [ 'asciifolding', "standard", "lowercase", "stop", "kstem", "ngram_short" ]
         | 
| 26 | 
            +
                            },
         | 
| 27 | 
            +
                            beginning: {
         | 
| 28 | 
            +
                              type: "custom",
         | 
| 29 | 
            +
                              tokenizer: "keyword",
         | 
| 30 | 
            +
                              filter: [ "lowercase", 'asciifolding', 'ngram_beginning' ]
         | 
| 31 | 
            +
                            }
         | 
| 32 | 
            +
                          },
         | 
| 33 | 
            +
                          filter: {
         | 
| 34 | 
            +
                            ngram_beginning: {
         | 
| 35 | 
            +
                              type: "edgeNGram",
         | 
| 36 | 
            +
                              min_gram: 2,
         | 
| 37 | 
            +
                              max_gram: 30
         | 
| 38 | 
            +
                            },
         | 
| 39 | 
            +
                            ngram_front: {
         | 
| 40 | 
            +
                              type: "edgeNGram",
         | 
| 41 | 
            +
                              min_gram: 2,
         | 
| 42 | 
            +
                              max_gram: 15
         | 
| 43 | 
            +
                            },
         | 
| 44 | 
            +
                            ngram_short: {
         | 
| 45 | 
            +
                              type: "ngram",
         | 
| 46 | 
            +
                              min_gram: 2,
         | 
| 47 | 
            +
                              max_gram: 15
         | 
| 48 | 
            +
                            }
         | 
| 49 | 
            +
                          }
         | 
| 50 | 
            +
                        }
         | 
| 51 | 
            +
                      }
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    def build_config(field)
         | 
| 55 | 
            +
                      {
         | 
| 56 | 
            +
                        :type => :multi_field,
         | 
| 57 | 
            +
                        :fields => {
         | 
| 58 | 
            +
                          field.to_sym => { type: 'string' },
         | 
| 59 | 
            +
                          :"#{field}.exact" => { type: 'string', index_analyzer: 'simple' },
         | 
| 60 | 
            +
                          :"#{field}.beginning" => { type: 'string', index_analyzer: 'beginning'},
         | 
| 61 | 
            +
                          :"#{field}.autocomplete" => { type: 'string', index_analyzer: 'autocomplete'},
         | 
| 62 | 
            +
                          :"#{field}.fuzzy" => { type: 'string', index_analyzer: 'fuzzy'}
         | 
| 63 | 
            +
                        }
         | 
| 64 | 
            +
                      }
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                    alias_method :config, :build_config
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
                  extend ClassMethods
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
            end
         | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            ###
         | 
| 2 | 
            +
            # Returns the search body as a hash for autocomplete module
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # Building the hash in a specific format is vital to developing
         | 
| 5 | 
            +
            # a multi-query search from elasticsearch. Results are returned in the specific
         | 
| 6 | 
            +
            # order you submit the query in.
         | 
| 7 | 
            +
            #
         | 
| 8 | 
            +
            # Each 'type' should have a corrisponding class.
         | 
| 9 | 
            +
            # Example:
         | 
| 10 | 
            +
            # If the type would be a 'tag'-
         | 
| 11 | 
            +
            # => Elasticsearch::Autocomplete::TagType
         | 
| 12 | 
            +
            ###
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            module Elasticsearch
         | 
| 15 | 
            +
              module Autocomplete
         | 
| 16 | 
            +
                class MultipleRequest < Request
         | 
| 17 | 
            +
                  def body
         | 
| 18 | 
            +
                    @body ||= begin
         | 
| 19 | 
            +
                      result = []
         | 
| 20 | 
            +
                      types.each do |t|
         | 
| 21 | 
            +
                        result << index_hash
         | 
| 22 | 
            +
                        result << t.to_hash
         | 
| 23 | 
            +
                      end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                      result
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                private
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  def index_hash
         | 
| 32 | 
            +
                    {:index => index}
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            ###
         | 
| 2 | 
            +
            # Returns the search body as a hash for autocomplete module
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # Building the hash in a specific format is vital to developing
         | 
| 5 | 
            +
            # a multi-query search from elasticsearch. Results are returned in the specific
         | 
| 6 | 
            +
            # order you submit the query in.
         | 
| 7 | 
            +
            #
         | 
| 8 | 
            +
            # Each 'type' should have a corrisponding class.
         | 
| 9 | 
            +
            # Example:
         | 
| 10 | 
            +
            # If the type would be a 'tag'-
         | 
| 11 | 
            +
            # => Elasticsearch::Autocomplete::TagType
         | 
| 12 | 
            +
            ###
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            module Elasticsearch
         | 
| 15 | 
            +
              module Autocomplete
         | 
| 16 | 
            +
                class Request
         | 
| 17 | 
            +
                  attr_accessor :query, :types, :index
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def initialize(index, query, types)
         | 
| 20 | 
            +
                    self.query = query
         | 
| 21 | 
            +
                    self.types = types
         | 
| 22 | 
            +
                    self.index = index
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  def body
         | 
| 26 | 
            +
                    {}
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            require 'ostruct'
         | 
| 2 | 
            +
            require 'elasticsearch/model'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Elasticsearch
         | 
| 5 | 
            +
              module Autocomplete
         | 
| 6 | 
            +
                class Response
         | 
| 7 | 
            +
                  include Enumerable
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  delegate :body, to: :request
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  attr_accessor :types, :request, :results
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def initialize(types, request)
         | 
| 14 | 
            +
                    self.request = request
         | 
| 15 | 
            +
                    self.types = types
         | 
| 16 | 
            +
                    self.results = search
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def each(&block)
         | 
| 20 | 
            +
                    results.each do |result|
         | 
| 21 | 
            +
                      member = parse_response(result)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                      block.call(member)
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                protected
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  def search
         | 
| 30 | 
            +
                    r = Elasticsearch::Model.client.msearch(:body => body)
         | 
| 31 | 
            +
                    r['responses']
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def parse_response(results)
         | 
| 35 | 
            +
                    results['hits']['hits'].map do |search_result|
         | 
| 36 | 
            +
                      src = search_result['_source']
         | 
| 37 | 
            +
                      type = search_result['_type']
         | 
| 38 | 
            +
                      score = search_result['_score']
         | 
| 39 | 
            +
                      returned_type = types.select{|t| t.type == type }.first
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                      if returned_type
         | 
| 42 | 
            +
                        returned_type.mapped(
         | 
| 43 | 
            +
                          OpenStruct.new(src)
         | 
| 44 | 
            +
                        )
         | 
| 45 | 
            +
                      else
         | 
| 46 | 
            +
                        src
         | 
| 47 | 
            +
                      end.merge(:_score => score, :_type => type)
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            module Elasticsearch
         | 
| 2 | 
            +
              module Autocomplete
         | 
| 3 | 
            +
                class Search
         | 
| 4 | 
            +
                  module ClassMethods
         | 
| 5 | 
            +
                    def find(index, query, types=[])
         | 
| 6 | 
            +
                      search = self.new(index, query, types)
         | 
| 7 | 
            +
                    end
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
                  extend ClassMethods
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  attr_accessor :query, :types, :index, :multisearch, :field
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def initialize(index, query, types, multisearch=true, field=nil)
         | 
| 14 | 
            +
                    raise "Specify a field when running a single search." if multisearch == false && field.nil?
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    self.query = query
         | 
| 17 | 
            +
                    self.types = types_mapped(types)
         | 
| 18 | 
            +
                    self.index = index
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    self.multisearch = multisearch
         | 
| 21 | 
            +
                    self.field = field
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def results
         | 
| 25 | 
            +
                    @results ||= begin
         | 
| 26 | 
            +
                      if multisearch
         | 
| 27 | 
            +
                        MultipleResponse.new(types, request)
         | 
| 28 | 
            +
                      else
         | 
| 29 | 
            +
                        SingleResponse.new(types, request)
         | 
| 30 | 
            +
                      end
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def request
         | 
| 35 | 
            +
                    @request ||= begin
         | 
| 36 | 
            +
                      if multisearch
         | 
| 37 | 
            +
                        MultipleRequest.new(index, query, types)
         | 
| 38 | 
            +
                      else
         | 
| 39 | 
            +
                        SingleRequest.new(index, query, types, field)
         | 
| 40 | 
            +
                      end
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                private
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def types_mapped(types)
         | 
| 47 | 
            +
                    types = Array(types)
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    types.map do |type|
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                      "Elasticsearch::Autocomplete::#{type.capitalize}Type".constantize
         | 
| 52 | 
            +
                                                              .new(query)
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            ###
         | 
| 2 | 
            +
            # Returns the search body as a hash for autocomplete module
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # Building the hash in a specific format is vital to developing
         | 
| 5 | 
            +
            # a multi-query search from elasticsearch. Results are returned in the specific
         | 
| 6 | 
            +
            # order you submit the query in.
         | 
| 7 | 
            +
            #
         | 
| 8 | 
            +
            # Each 'type' should have a corrisponding class.
         | 
| 9 | 
            +
            # Example:
         | 
| 10 | 
            +
            # If the type would be a 'tag'-
         | 
| 11 | 
            +
            # => Elasticsearch::Autocomplete::TagType
         | 
| 12 | 
            +
            ###
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            module Elasticsearch
         | 
| 15 | 
            +
              module Autocomplete
         | 
| 16 | 
            +
                class SingleRequest < Request
         | 
| 17 | 
            +
                  attr_accessor :field
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def initialize(index, query, types, field)
         | 
| 20 | 
            +
                    super(index, query, types)
         | 
| 21 | 
            +
                    self.field = field
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def body
         | 
| 25 | 
            +
                    @body ||= begin
         | 
| 26 | 
            +
                      {
         | 
| 27 | 
            +
                        :index => index,
         | 
| 28 | 
            +
                        :type => types.map(&:type).uniq,
         | 
| 29 | 
            +
                        :body => {
         | 
| 30 | 
            +
                          :query => Type.single_search(query, field)
         | 
| 31 | 
            +
                        }
         | 
| 32 | 
            +
                      }
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module Elasticsearch
         | 
| 2 | 
            +
              module Autocomplete
         | 
| 3 | 
            +
                class SingleResponse < Response
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  def each(&block)
         | 
| 6 | 
            +
                    members = parse_response(results)
         | 
| 7 | 
            +
                    members.each do |member|
         | 
| 8 | 
            +
                      block.call(member)
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                protected
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def search
         | 
| 15 | 
            +
                    @search ||= Elasticsearch::Model.client.search(body)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,74 @@ | |
| 1 | 
            +
            require 'action_controller'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Elasticsearch
         | 
| 4 | 
            +
              module Autocomplete
         | 
| 5 | 
            +
                class Type
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  module ClassMethods
         | 
| 8 | 
            +
                    def single_search(query, field)
         | 
| 9 | 
            +
                      t = self.new(query)
         | 
| 10 | 
            +
                      t.send(:multi_match, {}, query, field)
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  extend ClassMethods
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  attr_accessor :query
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def initialize(query)
         | 
| 19 | 
            +
                    self.query = query
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  # => String
         | 
| 23 | 
            +
                  def type
         | 
| 24 | 
            +
                    raise "Replace #type with the ElasticSearch _type"
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  # => Hash
         | 
| 28 | 
            +
                  def to_hash
         | 
| 29 | 
            +
                    raise "Replace #to_hash with ElasticSearch Query Hash"
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  # Return the hash to which the result is mapped from
         | 
| 33 | 
            +
                  # @param source {OpenStruct} Source value from ElasticSearch result
         | 
| 34 | 
            +
                  # => Hash
         | 
| 35 | 
            +
                  def mapped(source)
         | 
| 36 | 
            +
                    raise "Replace #mapped with a mapped response hash"
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  # The field to search on
         | 
| 40 | 
            +
                  # You'll only need this if you intend on using the search
         | 
| 41 | 
            +
                  # helpers below
         | 
| 42 | 
            +
                  #
         | 
| 43 | 
            +
                  def field
         | 
| 44 | 
            +
                    raise "Replace #field with the ElasticSearch field name"
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                protected
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  def image_path(img)
         | 
| 50 | 
            +
                    return if img.blank?
         | 
| 51 | 
            +
                    ActionController::Base.helpers.image_path(img)
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  # https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
         | 
| 55 | 
            +
                  # Quickly use the multiple fields matcher search format
         | 
| 56 | 
            +
                  # => { query: multi_match({exact: 30}) }
         | 
| 57 | 
            +
                  #
         | 
| 58 | 
            +
                  def multi_match(rank_overrides={}, query_override=nil, field_override=nil, tie_breaker=0.3)
         | 
| 59 | 
            +
                    ranks = {exact: 10, beginning: 7, autocomplete: 5, fuzzy: 1}.merge(rank_overrides)
         | 
| 60 | 
            +
                    field_override ||= field
         | 
| 61 | 
            +
                    query_override ||= query
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    {
         | 
| 64 | 
            +
                      :multi_match => {
         | 
| 65 | 
            +
                        :query  => query_override,
         | 
| 66 | 
            +
                        :type   => 'most_fields',
         | 
| 67 | 
            +
                        :fields => ranks.map{|k,v| :"#{field_override}.#{k}^#{v}" },
         | 
| 68 | 
            +
                        :tie_breaker =>  tie_breaker
         | 
| 69 | 
            +
                      }
         | 
| 70 | 
            +
                    }
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,157 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: elasticsearch-autocomplete
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.1.1
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - s.podlecki
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2015-06-19 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: rails
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ">"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: 3.2.0
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ">"
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: 3.2.0
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: elasticsearch
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - ">="
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '0'
         | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - ">="
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '0'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: elasticsearch-model
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - ">="
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '0'
         | 
| 48 | 
            +
              type: :runtime
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - ">="
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: elasticsearch-rails
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ">="
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '0'
         | 
| 62 | 
            +
              type: :runtime
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - ">="
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '0'
         | 
| 69 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            +
              name: bundler
         | 
| 71 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 | 
            +
                requirements:
         | 
| 73 | 
            +
                - - ">="
         | 
| 74 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            +
                    version: '0'
         | 
| 76 | 
            +
              type: :development
         | 
| 77 | 
            +
              prerelease: false
         | 
| 78 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 | 
            +
                requirements:
         | 
| 80 | 
            +
                - - ">="
         | 
| 81 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            +
                    version: '0'
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: rake
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - "~>"
         | 
| 88 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                    version: '10.0'
         | 
| 90 | 
            +
              type: :development
         | 
| 91 | 
            +
              prerelease: false
         | 
| 92 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - "~>"
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: '10.0'
         | 
| 97 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 98 | 
            +
              name: rspec
         | 
| 99 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 100 | 
            +
                requirements:
         | 
| 101 | 
            +
                - - ">="
         | 
| 102 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 103 | 
            +
                    version: '0'
         | 
| 104 | 
            +
              type: :development
         | 
| 105 | 
            +
              prerelease: false
         | 
| 106 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 107 | 
            +
                requirements:
         | 
| 108 | 
            +
                - - ">="
         | 
| 109 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 110 | 
            +
                    version: '0'
         | 
| 111 | 
            +
            description: Include autocomplete into your project. Base capability can perform multiple
         | 
| 112 | 
            +
              queries per request.
         | 
| 113 | 
            +
            email:
         | 
| 114 | 
            +
            - s.podlecki@gmail.com
         | 
| 115 | 
            +
            executables: []
         | 
| 116 | 
            +
            extensions: []
         | 
| 117 | 
            +
            extra_rdoc_files: []
         | 
| 118 | 
            +
            files:
         | 
| 119 | 
            +
            - CHANGELOG.md
         | 
| 120 | 
            +
            - README.md
         | 
| 121 | 
            +
            - Rakefile
         | 
| 122 | 
            +
            - lib/elasticsearch.rb
         | 
| 123 | 
            +
            - lib/elasticsearch/autocomplete.rb
         | 
| 124 | 
            +
            - lib/elasticsearch/autocomplete/filters.rb
         | 
| 125 | 
            +
            - lib/elasticsearch/autocomplete/multiple_request.rb
         | 
| 126 | 
            +
            - lib/elasticsearch/autocomplete/multiple_response.rb
         | 
| 127 | 
            +
            - lib/elasticsearch/autocomplete/request.rb
         | 
| 128 | 
            +
            - lib/elasticsearch/autocomplete/response.rb
         | 
| 129 | 
            +
            - lib/elasticsearch/autocomplete/search.rb
         | 
| 130 | 
            +
            - lib/elasticsearch/autocomplete/single_request.rb
         | 
| 131 | 
            +
            - lib/elasticsearch/autocomplete/single_response.rb
         | 
| 132 | 
            +
            - lib/elasticsearch/autocomplete/type.rb
         | 
| 133 | 
            +
            - lib/elasticsearch/autocomplete/version.rb
         | 
| 134 | 
            +
            homepage: https://github.com/spodlecki/elasticsearch-autocomplete
         | 
| 135 | 
            +
            licenses: []
         | 
| 136 | 
            +
            metadata: {}
         | 
| 137 | 
            +
            post_install_message: 
         | 
| 138 | 
            +
            rdoc_options: []
         | 
| 139 | 
            +
            require_paths:
         | 
| 140 | 
            +
            - lib
         | 
| 141 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 142 | 
            +
              requirements:
         | 
| 143 | 
            +
              - - ">="
         | 
| 144 | 
            +
                - !ruby/object:Gem::Version
         | 
| 145 | 
            +
                  version: '0'
         | 
| 146 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 147 | 
            +
              requirements:
         | 
| 148 | 
            +
              - - ">="
         | 
| 149 | 
            +
                - !ruby/object:Gem::Version
         | 
| 150 | 
            +
                  version: '0'
         | 
| 151 | 
            +
            requirements: []
         | 
| 152 | 
            +
            rubyforge_project: 
         | 
| 153 | 
            +
            rubygems_version: 2.4.6
         | 
| 154 | 
            +
            signing_key: 
         | 
| 155 | 
            +
            specification_version: 4
         | 
| 156 | 
            +
            summary: Autocomplete Helpers and Builder
         | 
| 157 | 
            +
            test_files: []
         |