ruby-on-railselasticsearchelasticsearch-rails

How can I increase the rank for a particular search result based on user selection in Elastic search using rails


So let's say I enter the text "Ebook" for searching and get the following results:

Ebook for Rails
Elastic Ebook
Booking for ebook.

Now I select "Elastic Ebook" from the list. Let's say that several other users input Ebook for searching and most of them select "Elastic Ebook" from the list. This clearly indicates the popularity for Elastic Ebook for the key word "Ebook". Hence in further searches, I would want Elastic Ebook to have higher priority and appear at the top.

Elastic Ebook
Ebook for Rails
Booking for an ebook.

Is there any way to achieve this.

My code document.rb :

require 'elasticsearch/model'

class Document < ApplicationRecord
  include Elasticsearch::Model
  include Elasticsearch::Model::Callbacks
  belongs_to :user

  Document.import force: true


  def self.search(query)
  __elasticsearch__.search({
      query: {
        multi_match: {
          query: query,
          fields: ['name^10', 'service'],
          fuzziness: "AUTO"
      }
    }
    })
  end


  settings index: { 
    "number_of_shards": 1, 
    analysis: {
      analyzer: {
        edge_ngram_analyzer: { type: "custom", tokenizer: "standard", filter: 
          ["lowercase", "edge_ngram_filter", "stop", "kstem" ] },
            }
        },
        filter: {
                  edge_ngram_filter: { type: "edgeNGram", min_gram: "3", 
                                      max_gram: "20" } 
      }
    } do
    mapping do
      indexes :name, type: "string", analyzer: "edge_ngram_analyzer"
      indexes :service, type: "string", analyzer: "edge_ngram_analyzer"
    end 
  end
end

search controller code:

def search
  if params[:query].nil?
    @documents = []
  else
    @documents = Document.search params[:query]
  end
end

Solution

  • There is no simple solution for this. Elasticsearch does not know what your users choose in the application.

    In the simplest approach it would have to be your responsibility to tell elasticesearch what is popular (just after user searched and clicked on one of the results from the list), and store this information in your documents by updating them. Technically updating means deleting and inserting the document again but it can be done with Update API and scripts.

    Having this, you can use function_score queries to search with boosting-by-popularity:

    {
      "query": {
        "function_score": { 
          "query": { 
            "multi_match": {
              "query":    "Rental",
              "fields": [ "name"]
            }
          },
          "field_value_factor": { 
            "field": "popularity",
            "modifier": "..."
          }
        }
      }
    }
    

    where popularity is the field you update.

    It is also possible to store the information about popluratity in separate documents and extend the query to combine these two sources of information.

    There are also plugins for Learning to Rank integration but I've never used them so it's hard to tell how complicated it is to integrate.