Skip to content

Instantly share code, notes, and snippets.

@tonyta
Last active August 29, 2015 14:05
Show Gist options
  • Save tonyta/293a82631cddf56165c1 to your computer and use it in GitHub Desktop.
Save tonyta/293a82631cddf56165c1 to your computer and use it in GitHub Desktop.
Sunspot-Solr Job Searcher Spike

Sunspot-Solr Job Searcher Spike

So here is what I've come up with for the JobSearcher.

Brian suggested that breaking this out into another controller which is what I started doing. I haven't looked too much into what the convention here is, so this is just a spike.

I applied what I learned from looking at the Sunspot source to make the searcher.

The main property that we seem to organize Jobs into is by state. From there, an aspect can be called, returning a Sunspot object. I'm aware that some of this will become the responsibility of Tasks, but what I learned from looking at the Sunspot source can be applied to that as well.

There are still a few things yet to be implemented, but I thought I'd get some feedback before going forward:

  • any pagination
  • faceting for calendar views
  • fulltext searches
  • advanced filtering

Routes

Scripted::Application.routes.draw do
  get 'job_states/:state',         to: 'job_states#index'
  get 'job_states/:state/:aspect', to: 'job_states#index'
  
  # get 'job_states/in_authorship/:aspect',       to: 'job_states#in_authorship'
  # get 'job_states/plagiarized/:aspect',         to: 'job_states#plagiarized'
  # get 'job_states/needs_extra_review/:aspect',  to: 'job_states#needs_extra_review'
  # get 'job_states/in_extra_review/:aspect',     to: 'job_states#in_extra_review'
  # get 'job_states/fixing_extra_review/:aspect', to: 'job_states#fixing_extra_review'
  # get 'job_states/needs_review/:aspect',        to: 'job_states#needs_review'
  # get 'job_states/needs_final_review/:aspect',  to: 'job_states#needs_final_review'
  # get 'job_states/any_state/:aspect',           to: 'job_states#any_state'
  # get 'job_states/reviewed/:aspect',            to: 'job_states#reviewed'
  # get 'job_states/in_any_edits/:aspect',        to: 'job_states#in_any_edits'
end

Controller

class JobStatesController < ApplicationController

  def index
    if @searcher = JobSearcher.search(params)
      render_results
    else
      render json: { error: { msg: 'you done messed up' } }
    end
  end

  # def in_authorship
  #   @searcher = JobSearcher::InAuthorship.search(params)
  #   render_results
  # end

  # def plagiarized
  #   @searcher = JobSearcher::Plagiarized.search(params)
  #   render_results
  # end

  # def needs_extra_review
  #   @searcher = JobSearcher::NeedsExtraReview.search(params)
  #   render_results
  # end

  # def needs_review
  #   @searcher = JobSearcher::NeedsReview.search(params)
  #   render_results
  # end

  # def needs_final_review
  #   @searcher = JobSearcher::NeedsFinalReview.search(params)
  #   render_results
  # end

  # def any_state
  #   @searcher = JobSearcher::AnyState.search(params)
  #   render_results
  # end

  # def reviewed
  #   @searcher = JobSearcher::Reviewed.search(params)
  #   render_results
  # end

  # def in_any_edits
  #   @searcher = JobSearcher::InAnyEdits.search(params)
  #   render_results
  # end

  def render_results
    render json: {
      params: params,
      hits: @searcher.hits.inspect
    }
  end
end

Searchers

module JobSearcher

  class Base

    def self.search(params)
      search_object = self.new(params)
      aspect = params[:aspect] && params[:aspect].to_sym
      if search_object.public_methods(false).include?(aspect)
        search_object.send(aspect)
      else
        search_object.all
      end
    end

    def initialize(params)
      searchable_class = FinishedJob
      setup = Sunspot::Setup.for(searchable_class)
      @params = params.with_indifferent_access
      @searcher = Sunspot.new_search(searchable_class)
      @query = Sunspot::DSL::Search.new(searcher, setup)
    end

    private

    attr_reader :params, :searcher, :query

    def base_search
      setup_perspective
      query.order_by(:deadline_at, :asc)
      searcher.execute
    end

    def setup_perspective
      query.with(:needs_cc).equal_to(false) if admin?
      query.with(:business_id).equal_to(params[:business_id]) if business?
      query.with(:writer_id).equal_to(params[:writer_id]) if writer?
    end

    def admin?
      params[:admin_id].present?
    end

    def business?
      params[:business_id].present?
    end

    def writer?
      params[:writer_id].present?
    end
  end


  class InAuthorship < Base

    def all
      query.with(:state).equal_to(IN_AUTHORSHIP)
      base_search
    end

    def specialists
      query.with(:requires_expertise).equal_to(true)
      all
    end

    def red_flags
      query.any_of do
        with(:flake_type, %w(implicit explicit))
        with(:no_content).equal_to(true)
        with(:writer_deadline_at).less_than(Time.now)
      end
      all
    end

    def unclaimed
      query.with(:taken).equal_to(false)
      all
    end

    def claimed
      query.with(:taken).equal_to(true)
      all
    end

    def superheroes
      query.with(:flake_type, %w(implicit explicit))
      claimed
    end
  end


  class Plagiarized < Base
    def all
      query.with(:state).equal_to(PLAGIARIZED)
      base_search
    end

    def ithenticate
      query.with(:paraphrased).equal_to(false)
      all
    end

    def paraphrased
      query.with(:paraphrased).equal_to(true)
      all
    end
  end


  class NeedsExtraReview < Base
    def all
      query.with(:state).equal_to(NEEDS_EXTRA_REVIEW)
      query.order_by(:deadline_at, :desc)
      base_search
    end

    def by_admin
      query.with(:extra_reviewer_type).equal_to('Admin')
      all
    end

    def by_business
      query.with(:extra_reviewer_type).equal_to('Business')
      all
    end

    def by_editor
      query.with(:extra_reviewer_type).equal_to('Writer')
      all
    end
  end


  class InExtraReview < Base
    def all
      query.with(:state).equal_to(IN_EXTRA_REVIEW)
      base_search
    end
  end


  class FixingExtraReview < Base
    def all
      query.with(:state).equal_to(FIXING_EXTRA_REVIEW)
      base_search
    end
  end


  class NeedsReview < Base
    def all
      query.with(:state).equal_to(NEEDS_REVIEW)
      base_search
    end
  end


  class NeedsFinalReview < Base
    def all
      query.with(:state).equal_to(NEEDS_FINAL_REVIEW)
      base_search
    end
  end


  class AnyState < Base
    def all
      query.order_by(:deadline_at, :desc)
      base_search
    end
  end


  class Reviewed < Base
    def all
      query.with(:state).greater_than(NEEDS_FINAL_REVIEW)
      query.order_by(:deadline_at, :desc)
      base_search
    end
  end


  class InAnyEdits < Base
    def all
      query.with(:state, [FIXING_PLAGIARISM, FIXING_EXTRA_REVIEW, NEEDS_EDITS])
      query.with(:sent_to_writer_at).less_than(2.days.ago) if admin?
      base_search
    end
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment