discourse/app/models/search_log.rb
Arpit Jalan e3925278e2 FEATURE: support search click through tracking for user, category and tags
https://meta.discourse.org/t/search-logs-page/73281/11?u=techapj

This commit adds following features:

- support for tracking click through to user, tag and category
- new filter for search type (header, full page)

This commit also removes "most viewed topic" field from search logs page because we are now tracking multiple click through entities, so topic is not a special entity anymore. This also improves query perf. The query now takes `20.5ms` to runs, as opposed to `655.9ms` previously.
2017-12-01 12:04:55 +05:30

107 lines
2.6 KiB
Ruby

require_dependency 'enum'
class SearchLog < ActiveRecord::Base
validates_presence_of :term, :ip_address
def self.search_types
@search_types ||= Enum.new(
header: 1,
full_page: 2
)
end
def self.search_result_types
@search_result_types ||= Enum.new(
topic: 1,
user: 2,
category: 3,
tag: 4
)
end
def self.log(term:, search_type:, ip_address:, user_id: nil)
search_type = search_types[search_type]
return [:error] unless search_type.present? && ip_address.present?
update_sql = <<~SQL
UPDATE search_logs
SET term = :term,
created_at = :created_at
WHERE created_at > :timeframe AND
position(term IN :term) = 1 AND
((:user_id IS NULL AND ip_address = :ip_address) OR
(user_id = :user_id))
RETURNING id
SQL
rows = exec_sql(
update_sql,
term: term,
created_at: Time.zone.now,
timeframe: 5.seconds.ago,
user_id: user_id,
ip_address: ip_address
)
if rows.cmd_tuples == 0
result = create(
term: term,
search_type: search_type,
ip_address: ip_address,
user_id: user_id
)
[:created, result.id]
else
[:updated, rows[0]['id'].to_i]
end
end
def self.trending(period = :all, search_type = :all)
result = SearchLog.select("term,
COUNT(*) AS searches,
SUM(CASE
WHEN search_result_id IS NOT NULL THEN 1
ELSE 0
END) AS click_through,
COUNT(DISTINCT ip_address) AS unique")
.where('created_at > ?', start_of(period))
result = result.where('search_type = ?', search_types[search_type]) unless search_type == :all
result = result.group(:term)
.order('COUNT(DISTINCT ip_address) DESC, COUNT(*) DESC')
.limit(100).to_a
end
def self.start_of(period)
case period
when :yearly then 1.year.ago
when :monthly then 1.month.ago
when :quarterly then 3.months.ago
when :weekly then 1.week.ago
when :daily then 1.day.ago
else 1000.years.ago
end
end
def self.clean_up
search_id = SearchLog.order(:id).offset(SiteSetting.search_query_log_max_size).limit(1).pluck(:id)
if search_id.present?
SearchLog.where('id < ?', search_id[0]).delete_all
end
end
end
# == Schema Information
#
# Table name: search_logs
#
# id :integer not null, primary key
# term :string not null
# user_id :integer
# ip_address :inet not null
# clicked_topic_id :integer
# search_type :integer not null
# created_at :datetime not null
#