mirror of
https://github.com/discourse/discourse.git
synced 2025-01-31 03:08:29 +08:00
PERF: handle debounce in redis cause SQL can be slow
This commit is contained in:
parent
442a17bfb2
commit
bf68d394f4
|
@ -19,42 +19,54 @@ class SearchLog < ActiveRecord::Base
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.redis_key(ip_address:, user_id: nil)
|
||||||
|
if user_id
|
||||||
|
"__SEARCH__LOG_#{user_id}"
|
||||||
|
else
|
||||||
|
"__SEARCH__LOG_#{ip_address}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# for testing
|
||||||
|
def self.clear_debounce_cache!
|
||||||
|
$redis.keys("__SEARCH__LOG_*").each do |k|
|
||||||
|
$redis.del(k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.log(term:, search_type:, ip_address:, user_id: nil)
|
def self.log(term:, search_type:, ip_address:, user_id: nil)
|
||||||
|
|
||||||
search_type = search_types[search_type]
|
search_type = search_types[search_type]
|
||||||
return [:error] unless search_type.present? && ip_address.present?
|
return [:error] unless search_type.present? && ip_address.present?
|
||||||
|
|
||||||
update_sql = <<~SQL
|
key = redis_key(user_id: user_id, ip_address: ip_address)
|
||||||
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(
|
result = nil
|
||||||
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
|
if existing = $redis.get(key)
|
||||||
result = create(
|
id, old_term = existing.split(",", 2)
|
||||||
|
if term.start_with?(old_term)
|
||||||
|
where(id: id.to_i).update_all(
|
||||||
|
created_at: Time.zone.now,
|
||||||
|
term: term
|
||||||
|
)
|
||||||
|
result = [:updated, id.to_i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if !result
|
||||||
|
log = create(
|
||||||
term: term,
|
term: term,
|
||||||
search_type: search_type,
|
search_type: search_type,
|
||||||
ip_address: ip_address,
|
ip_address: ip_address,
|
||||||
user_id: user_id
|
user_id: user_id
|
||||||
)
|
)
|
||||||
[:created, result.id]
|
result = [:created, log.id]
|
||||||
else
|
|
||||||
[:updated, rows[0]['id'].to_i]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
$redis.setex(key, 5, "#{result[1]},#{term}")
|
||||||
|
|
||||||
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.term_details(term, period = :weekly, search_type = :all)
|
def self.term_details(term, period = :weekly, search_type = :all)
|
||||||
|
|
|
@ -2,6 +2,10 @@ require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe SearchLog, type: :model do
|
RSpec.describe SearchLog, type: :model do
|
||||||
|
|
||||||
|
before do
|
||||||
|
SearchLog.clear_debounce_cache!
|
||||||
|
end
|
||||||
|
|
||||||
describe ".log" do
|
describe ".log" do
|
||||||
|
|
||||||
context "invalid arguments" do
|
context "invalid arguments" do
|
||||||
|
@ -122,6 +126,7 @@ RSpec.describe SearchLog, type: :model do
|
||||||
expect(action).to eq(:created)
|
expect(action).to eq(:created)
|
||||||
|
|
||||||
freeze_time(10.minutes.from_now)
|
freeze_time(10.minutes.from_now)
|
||||||
|
$redis.del(SearchLog.redis_key(ip_address: '192.168.0.1', user_id: user.id))
|
||||||
|
|
||||||
action, _ = SearchLog.log(
|
action, _ = SearchLog.log(
|
||||||
term: 'hello',
|
term: 'hello',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user