diff --git a/.env_sample b/.env_sample
index 1a9fcf4c3..0645a5ca0 100644
--- a/.env_sample
+++ b/.env_sample
@@ -33,9 +33,6 @@ REDIS_SIDEKIQ_URL="redis://localhost:6379"
# Redis Devices/Rpush storage
REDIS_RPUSH_URL="redis://localhost:6379"
-# Elasticsearch
-ELASTICSEARCH_URL="http://localhost:9200"
-
# OpenResty
OPENRESTY_URL=""
@@ -164,4 +161,4 @@ SENDGRID_API_KEY="Optional, Production only"
# Disable simplecov coverage testing when running rspec locally
-COVERAGE="false"
\ No newline at end of file
+COVERAGE="false"
diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile
index a8a6f369d..c05178468 100644
--- a/.gitpod.dockerfile
+++ b/.gitpod.dockerfile
@@ -18,12 +18,3 @@ RUN sudo apt-get update \
&& sudo apt-get install -y \
redis-server \
&& sudo rm -rf /var/lib/apt/lists/*
-
-# Install Elasticsearch
-ARG ES_REPO=https://artifacts.elastic.co/downloads/elasticsearch
-ARG ES_ARCHIVE=elasticsearch-oss-7.5.2-linux-x86_64.tar.gz
-RUN wget "${ES_REPO}/${ES_ARCHIVE}" \
- && wget "${ES_REPO}/${ES_ARCHIVE}.sha512" \
- && shasum -a 512 -c ${ES_ARCHIVE}.sha512 \
- && tar -xzf ${ES_ARCHIVE} \
- && rm ${ES_ARCHIVE} ${ES_ARCHIVE}.sha512
diff --git a/.gitpod.yml b/.gitpod.yml
index 3e081f489..181d298fc 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -10,16 +10,11 @@ ports:
onOpen: ignore
- port: 6379
onOpen: ignore
- - port: 9200
- onOpen: ignore
- - port: 9300
- onOpen: ignore
tasks:
- name: Forem Server
before: |
redis-server &
- /home/gitpod/elasticsearch-7.5.2/bin/elasticsearch &
init: >
cp .env_sample .env &&
gem install solargraph &&
diff --git a/.travis.yml b/.travis.yml
index 3321bfce3..d1b273bcf 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -39,20 +39,11 @@ env:
- KNAPSACK_PRO_CI_NODE_TOTAL=3
- COVERAGE_REPORTS_TOTAL=4
- FOREM_OWNER_SECRET="secret" # test secret so e2e tests can run properly.
- - ELASTICSEARCH_URL="http://localhost:9200"
before_install:
- gem install bundler:"<2.3"
install:
- date --rfc-3339=seconds
- nvm install
- - pkill -9 -f elasticsearch || true
- - curl -s -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.5.2-amd64.deb
- - sudo dpkg -i --force-confnew elasticsearch-7.5.2-amd64.deb
- - sudo sed -i.old 's/-Xms1g/-Xms128m/' /etc/elasticsearch/jvm.options
- - sudo sed -i.old 's/-Xmx1g/-Xmx128m/' /etc/elasticsearch/jvm.options
- - echo -e '-XX:+DisableExplicitGC\n-Djdk.io.permissionsUseCanonicalPath=true\n-Dlog4j.skipJansi=true\n-server\n' | sudo tee -a /etc/elasticsearch/jvm.options
- - sudo chown -R elasticsearch:elasticsearch /etc/default/elasticsearch
- - sudo systemctl start elasticsearch
- bundle config set path 'vendor/bundle'
- cp .env_sample .env
- bin/ci-bundle
diff --git a/Gemfile b/Gemfile
index e521a9b11..9197f872c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -28,7 +28,6 @@ gem "devise" # Flexible authentication solution for Rails
gem "devise_invitable", "~> 2.0.5" # Allows invitations to be sent for joining
gem "dogstatsd-ruby", "~> 4.8" # A client for DogStatsD, an extension of the StatsD metric server for Datadog
gem "doorkeeper", "~> 5.5" # Oauth 2 provider
-gem "elasticsearch", "~> 7.12" # Powers DEVs core search functionality
gem "email_validator", "~> 2.2" # Email validator for Rails and ActiveModel
gem "emoji_regex", "~> 3.2" # A pair of Ruby regular expressions for matching Unicode Emoji symbols
gem "fastly", "~> 3.0" # Client library for the Fastly acceleration system
@@ -65,7 +64,7 @@ gem "omniauth-github", "~> 2.0" # OmniAuth strategy for GitHub
gem "omniauth-rails_csrf_protection", "~> 1.0" # Provides CSRF protection on OmniAuth request endpoint on Rails application.
gem "omniauth-twitter", "~> 1.4" # OmniAuth strategy for Twitter
gem "parallel", "~> 1.20" # Run any kind of code in parallel processes
-gem "patron", "~> 0.13.3" # HTTP client library based on libcurl, used with Elasticsearch to support http keep-alive connections
+gem "patron", "~> 0.13.3" # HTTP client library based on libcurl, used with GitHub OAuth client
gem "pg", "~> 1.2" # Pg is the Ruby interface to the PostgreSQL RDBMS
gem "pg_search", "~> 2.3.5" # PgSearch builds Active Record named scopes that take advantage of PostgreSQL's full text search
gem "puma", "~> 5.2.2" # Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
diff --git a/Gemfile.lock b/Gemfile.lock
index 9799ecc0c..097690b86 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -223,14 +223,6 @@ GEM
dotenv-rails (2.7.6)
dotenv (= 2.7.6)
railties (>= 3.2)
- elasticsearch (7.12.0)
- elasticsearch-api (= 7.12.0)
- elasticsearch-transport (= 7.12.0)
- elasticsearch-api (7.12.0)
- multi_json
- elasticsearch-transport (7.12.0)
- faraday (~> 1)
- multi_json
em-websocket (0.5.2)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0)
@@ -880,7 +872,6 @@ DEPENDENCIES
dogstatsd-ruby (~> 4.8)
doorkeeper (~> 5.5)
dotenv-rails (~> 2.7.6)
- elasticsearch (~> 7.12)
email_validator (~> 2.2)
emoji_regex (~> 3.2)
erb_lint (~> 0.0.37)
diff --git a/README.md b/README.md
index 83def2cda..e0dcfe3ec 100644
--- a/README.md
+++ b/README.md
@@ -116,7 +116,6 @@ A more complete overview of our stack is available in
- [ImageMagick](https://imagemagick.org/): please refer to ImageMagick's
[installation instructions](https://imagemagick.org/script/download.php).
- [Redis](https://redis.io/) 4 or higher.
-- [Elasticsearch](https://www.elastic.co) 7 or higher.
#### Containers
diff --git a/app/controllers/api/v0/health_checks_controller.rb b/app/controllers/api/v0/health_checks_controller.rb
index 26a5abc3e..31e1b719f 100644
--- a/app/controllers/api/v0/health_checks_controller.rb
+++ b/app/controllers/api/v0/health_checks_controller.rb
@@ -7,14 +7,6 @@ module Api
render json: { message: "App is up!" }, status: :ok
end
- def search
- if Search::Client.ping
- render json: { message: "Search ping succeeded!" }, status: :ok
- else
- render json: { message: "Search ping failed!" }, status: :internal_server_error
- end
- end
-
def database
if ActiveRecord::Base.connected?
render json: { message: "Database connected" }, status: :ok
diff --git a/app/controllers/chat_channels_controller.rb b/app/controllers/chat_channels_controller.rb
index ecc56f786..91e153160 100644
--- a/app/controllers/chat_channels_controller.rb
+++ b/app/controllers/chat_channels_controller.rb
@@ -159,7 +159,6 @@ class ChatChannelsController < ApplicationController
authorize chat_channel
chat_channel.status = "blocked"
chat_channel.save
- chat_channel.chat_channel_memberships.map(&:index_to_elasticsearch)
render json: { status: "success", message: "chat channel blocked" }, status: :ok
end
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 27ff8f0af..1cd2fd519 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -93,10 +93,6 @@ class SearchController < ApplicationController
render json: { result: result }
end
- def users
- render json: { result: user_search }
- end
-
def usernames
result = Search::Postgres::Username.search_documents(params[:username])
@@ -197,10 +193,6 @@ class SearchController < ApplicationController
)
end
- def user_search
- Search::User.search_documents(params: user_params.to_h)
- end
-
def chat_channel_params
params.permit(CHAT_CHANNEL_PARAMS)
end
diff --git a/app/lib/acts_as_taggable_on/tag.rb b/app/lib/acts_as_taggable_on/tag.rb
deleted file mode 100644
index 715cb1eee..000000000
--- a/app/lib/acts_as_taggable_on/tag.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-module ActsAsTaggableOn
- class Tag
- after_commit on: %i[create update] do
- ::Tag.find(id).index_to_elasticsearch
- end
-
- after_commit on: :update do
- DataSync::Elasticsearch::Tag.new(self).call
- end
- end
-end
diff --git a/app/lib/forem_stats_drivers/datadog_driver.rb b/app/lib/forem_stats_drivers/datadog_driver.rb
index ab4280196..cba2c38fa 100644
--- a/app/lib/forem_stats_drivers/datadog_driver.rb
+++ b/app/lib/forem_stats_drivers/datadog_driver.rb
@@ -9,7 +9,6 @@ module ForemStatsDrivers
c.tracer enabled: ENV["DD_API_KEY"].present?
c.tracer partial_flush: true
c.tracer priority_sampling: true
- c.use :elasticsearch
c.use :sidekiq
c.use :redis, service_name: "redis", describes: { url: ENV["REDIS_URL"] }
c.use :redis, service_name: "redis-sessions", describes: { url: ENV["REDIS_SESSIONS_URL"] }
diff --git a/app/models/article.rb b/app/models/article.rb
index 098ba2997..cc840b6ea 100644
--- a/app/models/article.rb
+++ b/app/models/article.rb
@@ -3,14 +3,9 @@ class Article < ApplicationRecord
include ActionView::Helpers
include Storext.model
include Reactable
- include Searchable
include UserSubscriptionSourceable
include PgSearch::Model
- SEARCH_SERIALIZER = Search::ArticleSerializer
- SEARCH_CLASS = Search::FeedContent
- DATA_SYNC_CLASS = DataSync::Elasticsearch::Article
-
acts_as_taggable_on :tags
resourcify
@@ -112,9 +107,6 @@ class Article < ApplicationRecord
}
after_commit :async_score_calc, :touch_collection, on: %i[create update]
- after_commit :index_to_elasticsearch, on: %i[create update]
- after_commit :sync_related_elasticsearch_docs, on: %i[update]
- after_commit :remove_from_elasticsearch, on: [:destroy]
# The trigger `update_reading_list_document` is used to keep the `articles.reading_list_document` column updated.
#
@@ -361,7 +353,6 @@ class Article < ApplicationRecord
def touch_by_reaction
async_score_calc
- index_to_elasticsearch
end
def comments_blob
diff --git a/app/models/chat_channel_membership.rb b/app/models/chat_channel_membership.rb
index 83d8220bf..6396dd36c 100644
--- a/app/models/chat_channel_membership.rb
+++ b/app/models/chat_channel_membership.rb
@@ -1,10 +1,6 @@
class ChatChannelMembership < ApplicationRecord
attr_accessor :invitation_usernames
- include Searchable
- SEARCH_SERIALIZER = Search::ChatChannelMembershipSerializer
- SEARCH_CLASS = Search::ChatChannelMembership
-
ROLES = %w[member mod].freeze
STATUSES = %w[active inactive pending rejected left_channel removed_from_channel joining_request].freeze
@@ -18,9 +14,6 @@ class ChatChannelMembership < ApplicationRecord
validate :permission
- after_commit :index_to_elasticsearch, on: %i[create update]
- after_commit :remove_from_elasticsearch, on: [:destroy]
-
delegate :channel_type, to: :chat_channel
scope :eager_load_serialized_data, -> { includes(:user, :channel) }
diff --git a/app/models/comment.rb b/app/models/comment.rb
index 4d5c0fda6..b395a0197 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -4,10 +4,6 @@ class Comment < ApplicationRecord
include PgSearch::Model
include Reactable
- include Searchable
-
- SEARCH_SERIALIZER = Search::CommentSerializer
- SEARCH_CLASS = Search::FeedContent
BODY_MARKDOWN_SIZE_RANGE = (1..25_000).freeze
@@ -63,18 +59,9 @@ class Comment < ApplicationRecord
after_create_commit :send_to_moderator
after_commit :calculate_score, on: %i[create update]
- after_commit :index_to_elasticsearch, on: %i[create update]
after_update_commit :update_notifications, if: proc { |comment| comment.saved_changes.include? "body_markdown" }
- after_commit :remove_from_elasticsearch, on: [:destroy]
-
- # [@atsmith813] this is adapted from the `search_field` property in
- # `config/elasticsearch/mappings/feed_content.json` and
- # `app/serializers/search/comment_serializer.rb`
- #
- # highlighter settings are taken from
- # Search::QueryBuildersFeedContent#add_highlight_fields
pg_search_scope :search_comments,
against: %i[body_markdown],
using: {
diff --git a/app/models/concerns/searchable.rb b/app/models/concerns/searchable.rb
deleted file mode 100644
index fb0dc774d..000000000
--- a/app/models/concerns/searchable.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-module Searchable
- def search_id
- id
- end
-
- def index_to_elasticsearch
- Search::IndexWorker.perform_async(self.class.name, id)
- end
-
- def index_to_elasticsearch_inline
- self.class::SEARCH_CLASS.index(search_id, serialized_search_hash)
- end
-
- def remove_from_elasticsearch
- # Callbacks can cause index and removal jobs to be enqueued at the same time
- # to avoid indexing a document after removing it we delay the removal job by 5 seconds to
- # ensure it is run last
- Search::RemoveFromIndexWorker.perform_in(5.seconds, self.class::SEARCH_CLASS.to_s, search_id)
- end
-
- def serialized_search_hash
- self.class::SEARCH_SERIALIZER.new(self).serializable_hash.dig(:data, :attributes)
- end
-
- def elasticsearch_doc
- self.class::SEARCH_CLASS.find_document(search_id)
- end
-
- def sync_related_elasticsearch_docs
- self.class::DATA_SYNC_CLASS.new(self).call
- end
-end
diff --git a/app/models/listing.rb b/app/models/listing.rb
index eee54211c..adadc1170 100644
--- a/app/models/listing.rb
+++ b/app/models/listing.rb
@@ -3,12 +3,8 @@ class Listing < ApplicationRecord
# We standardized on the latter, but keeping the table name was easier.
self.table_name = "classified_listings"
- include Searchable
include PgSearch::Model
- SEARCH_SERIALIZER = Search::ListingSerializer
- SEARCH_CLASS = Search::Listing
-
attr_accessor :action
# NOTE: categories were hardcoded at first and the model was only added later.
@@ -19,8 +15,6 @@ class Listing < ApplicationRecord
before_validation :modify_inputs
before_save :evaluate_markdown
before_create :create_slug
- after_commit :index_to_elasticsearch, on: %i[create update]
- after_commit :remove_from_elasticsearch, on: [:destroy]
acts_as_taggable_on :tags
has_many :credits, as: :purchase, inverse_of: :purchase, dependent: :nullify
@@ -33,8 +27,6 @@ class Listing < ApplicationRecord
validate :restrict_markdown_input
validate :validate_tags
- # [@atsmith813] this is adapted from the `listing_search` property in
- # `config/elasticsearch/mappings/listings.json`
pg_search_scope :search_listings,
against: %i[body_markdown cached_tag_list location slug title],
using: { tsearch: { prefix: true } }
diff --git a/app/models/message.rb b/app/models/message.rb
index 1f964156e..6a6848f44 100644
--- a/app/models/message.rb
+++ b/app/models/message.rb
@@ -31,7 +31,6 @@ class Message < ApplicationRecord
def update_chat_channel_last_message_at
chat_channel.touch(:last_message_at)
- ChatChannels::IndexesMembershipsWorker.perform_async(chat_channel.id)
end
def update_all_has_unopened_messages_statuses
diff --git a/app/models/organization.rb b/app/models/organization.rb
index 5ab97ddb7..0e77ea9dd 100644
--- a/app/models/organization.rb
+++ b/app/models/organization.rb
@@ -30,7 +30,6 @@ class Organization < ApplicationRecord
# This callback will eventually invoke Article.update_cached_user to update the organization.name
# only when it has been changed, thus invoking the trigger on Article.reading_list_document
after_update_commit :update_articles_cached_organization
- after_update_commit :sync_related_elasticsearch_docs
after_destroy_commit :bust_cache, :article_sync
has_many :articles, dependent: :nullify
@@ -173,10 +172,6 @@ class Organization < ApplicationRecord
errors.add(:slug, "is taken.") if slug_taken
end
- def sync_related_elasticsearch_docs
- DataSync::Elasticsearch::Organization.new(self).call
- end
-
def article_sync
# Syncs article cached organization and updates Elasticsearch docs
Article.where(id: cached_article_ids).find_each(&:save)
diff --git a/app/models/podcast_episode.rb b/app/models/podcast_episode.rb
index 464c93b35..78accaab6 100644
--- a/app/models/podcast_episode.rb
+++ b/app/models/podcast_episode.rb
@@ -4,10 +4,6 @@ class PodcastEpisode < ApplicationRecord
]
include PgSearch::Model
- include Searchable
-
- SEARCH_SERIALIZER = Search::PodcastEpisodeSerializer
- SEARCH_CLASS = Search::FeedContent
acts_as_taggable
@@ -38,13 +34,6 @@ class PodcastEpisode < ApplicationRecord
after_destroy :purge, :purge_all
after_save :bust_cache
- after_commit :index_to_elasticsearch, on: %i[update]
- after_commit :remove_from_elasticsearch, on: [:destroy]
-
- # [@atsmith813] this is adapted from the `search_field` property in
- # `config/elasticsearch/mappings/feed_content.json` and
- # `app/serializers/search/podcast_episode_serializer.rb` with a couple of
- # extras
pg_search_scope :search_podcast_episodes,
against: %i[body subtitle title],
using: { tsearch: { prefix: true } }
diff --git a/app/models/tag.rb b/app/models/tag.rb
index 0842898d6..07e0d7d40 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -1,5 +1,3 @@
-require_relative "../lib/acts_as_taggable_on/tag"
-
class Tag < ActsAsTaggableOn::Tag
attr_accessor :points, :tag_moderator_id, :remove_moderator_id
@@ -8,8 +6,6 @@ class Tag < ActsAsTaggableOn::Tag
# This model doesn't inherit from ApplicationRecord so this has to be included
include Purgeable
- include Searchable
-
include PgSearch::Model
ALLOWED_CATEGORIES = %w[uncategorized language library tool site_mechanic location subcommunity].freeze
@@ -39,9 +35,6 @@ class Tag < ActsAsTaggableOn::Tag
before_save :mark_as_updated
after_commit :bust_cache
- after_commit :index_to_elasticsearch, on: %i[create update]
- after_commit :sync_related_elasticsearch_docs, on: [:update]
- after_commit :remove_from_elasticsearch, on: [:destroy]
pg_search_scope :search_by_name,
against: :name,
@@ -49,10 +42,6 @@ class Tag < ActsAsTaggableOn::Tag
scope :eager_load_serialized_data, -> {}
- SEARCH_SERIALIZER = Search::TagSerializer
- SEARCH_CLASS = Search::Tag
- DATA_SYNC_CLASS = DataSync::Elasticsearch::Tag
-
# possible social previews templates for articles with a particular tag
def self.social_preview_templates
Rails.root.join("app/views/social_previews/articles").children.map { |ch| File.basename(ch, ".html.erb") }
diff --git a/app/models/user.rb b/app/models/user.rb
index d4b47bc89..8b27e6e0b 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,8 +1,8 @@
class User < ApplicationRecord
resourcify
+ rolify
include CloudinaryHelper
- include Searchable
include Storext.model
# @citizen428 Preparing to drop profile columns from the users table
@@ -100,12 +100,6 @@ class User < ApplicationRecord
:add_credits, :remove_credits, :add_org_credits, :remove_org_credits, :ip_address,
:current_password
- rolify after_add: :index_roles, after_remove: :index_roles
-
- SEARCH_SERIALIZER = Search::UserSerializer
- SEARCH_CLASS = Search::User
- DATA_SYNC_CLASS = DataSync::Elasticsearch::User
-
acts_as_followable
acts_as_follower
@@ -310,9 +304,6 @@ class User < ApplicationRecord
after_create_commit :send_welcome_notification
after_commit :bust_cache
- after_commit :index_to_elasticsearch, on: %i[create update]
- after_commit :sync_related_elasticsearch_docs, on: %i[create update]
- after_commit :remove_from_elasticsearch, on: [:destroy]
def self.dev_account
find_by(id: Settings::Community.staff_user_id)
@@ -676,14 +667,6 @@ class User < ApplicationRecord
follows.destroy_all
end
- def index_roles(_role)
- return unless persisted?
-
- index_to_elasticsearch_inline
- rescue StandardError => e
- Honeybadger.notify(e, context: { user_id: id })
- end
-
def can_send_confirmation_email
return if changes[:email].blank? || id.blank?
diff --git a/app/services/data_sync/elasticsearch/article.rb b/app/services/data_sync/elasticsearch/article.rb
deleted file mode 100644
index abc03c709..000000000
--- a/app/services/data_sync/elasticsearch/article.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-module DataSync
- module Elasticsearch
- class Article < Base
- RELATED_DOCS = %i[
- comments
- ].freeze
-
- SHARED_FIELDS = %i[
- published
- title
- ].freeze
-
- delegate :comments, to: :@updated_record
- end
- end
-end
diff --git a/app/services/data_sync/elasticsearch/base.rb b/app/services/data_sync/elasticsearch/base.rb
deleted file mode 100644
index b20054a97..000000000
--- a/app/services/data_sync/elasticsearch/base.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-module DataSync
- module Elasticsearch
- class Base
- attr_reader :updated_record
-
- def initialize(updated_record)
- @updated_record = updated_record
- end
-
- def call
- return unless sync_needed?
-
- sync_related_documents
- end
-
- private
-
- def sync_needed?
- updated_fields.slice(*self.class::SHARED_FIELDS).any?
- end
-
- def sync_related_documents
- self.class::RELATED_DOCS.each do |relation_name|
- __send__(relation_name).find_each(&:index_to_elasticsearch)
- end
- end
-
- def updated_fields
- updated_record.saved_changes
- end
- end
- end
-end
diff --git a/app/services/data_sync/elasticsearch/organization.rb b/app/services/data_sync/elasticsearch/organization.rb
deleted file mode 100644
index 94e06e684..000000000
--- a/app/services/data_sync/elasticsearch/organization.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-module DataSync
- module Elasticsearch
- class Organization < Base
- RELATED_DOCS = %i[
- articles
- ].freeze
-
- SHARED_FIELDS = %i[
- slug
- name
- profile_image
- ].freeze
-
- delegate :articles, to: :@updated_record
- end
- end
-end
diff --git a/app/services/data_sync/elasticsearch/tag.rb b/app/services/data_sync/elasticsearch/tag.rb
deleted file mode 100644
index 2b486856d..000000000
--- a/app/services/data_sync/elasticsearch/tag.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-module DataSync
- module Elasticsearch
- class Tag < Base
- RELATED_DOCS = %i[
- articles
- podcast_episodes
- ].freeze
-
- SHARED_FIELDS = %i[
- keywords_for_search
- ].freeze
-
- private
-
- def articles
- ::Article.cached_tagged_with(updated_record.name)
- end
-
- def reactions
- ::Reaction.readinglist.where(reactable: articles)
- end
-
- def podcast_episodes
- ::PodcastEpisode.where(
- id: updated_record.taggings.where(taggable_type: "PodcastEpisode").select(:taggable_id),
- )
- end
- end
- end
-end
diff --git a/app/services/data_sync/elasticsearch/user.rb b/app/services/data_sync/elasticsearch/user.rb
deleted file mode 100644
index de33ef574..000000000
--- a/app/services/data_sync/elasticsearch/user.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-module DataSync
- module Elasticsearch
- class User < Base
- RELATED_DOCS = %i[
- articles
- podcast_episodes
- chat_channel_memberships
- comments
- ].freeze
-
- SHARED_FIELDS = %i[
- username
- name
- profile_image_url
- ].freeze
-
- delegate :articles, :chat_channel_memberships, :comments, to: :@updated_record
-
- private
-
- def reactions
- updated_record.reactions.readinglist
- end
-
- def podcast_episodes
- PodcastEpisode.for_user(updated_record)
- end
- end
- end
-end
diff --git a/app/services/edge_cache/bust_commentable.rb b/app/services/edge_cache/bust_commentable.rb
index 08a24fdb4..5887c3716 100644
--- a/app/services/edge_cache/bust_commentable.rb
+++ b/app/services/edge_cache/bust_commentable.rb
@@ -7,7 +7,6 @@ module EdgeCache
cache_bust = EdgeCache::Bust.new
cache_bust.call("#{commentable.path}/comments")
- commentable.index_to_elasticsearch_inline
end
end
end
diff --git a/app/services/podcasts/create_episode.rb b/app/services/podcasts/create_episode.rb
index 531188fd4..71995b2aa 100644
--- a/app/services/podcasts/create_episode.rb
+++ b/app/services/podcasts/create_episode.rb
@@ -69,7 +69,6 @@ module Podcasts
def finalize(episode)
episode.purge_all
- episode.index_to_elasticsearch
episode.save if episode.processed_html.blank?
end
end
diff --git a/app/services/search/base.rb b/app/services/search/base.rb
deleted file mode 100644
index 16d7ab4ce..000000000
--- a/app/services/search/base.rb
+++ /dev/null
@@ -1,143 +0,0 @@
-module Search
- class Base
- class << self
- def index(doc_id, serialized_data)
- Search::Client.index(
- id: doc_id,
- index: self::INDEX_ALIAS,
- body: serialized_data.merge(last_indexed_at: Time.current),
- )
- end
-
- def bulk_index(data_hashes)
- indexing_hashes = data_hashes.map do |data_hash|
- model_hash = data_hash.with_indifferent_access
- model_hash[:last_indexed_at] = Time.current
- {
- index: {
- _index: self::INDEX_ALIAS,
- _id: model_hash[:id],
- data: model_hash
- }
- }
- end
-
- process_hashes(indexing_hashes)
- end
-
- def find_document(doc_id)
- Search::Client.get(id: doc_id, index: self::INDEX_ALIAS)
- end
-
- def delete_document(doc_id)
- Search::Client.delete(id: doc_id, index: self::INDEX_ALIAS)
- end
-
- def index_exists?(index_name: self::INDEX_NAME)
- Search::Client.indices.exists(index: index_name)
- end
-
- def create_index(index_name: self::INDEX_NAME)
- Search::Client.indices.create(index: index_name, body: settings)
- end
-
- def update_index(index_name: self::INDEX_NAME)
- return unless dynamic_index_settings.any?
-
- Search::Client.indices.put_settings(index: index_name, body: dynamic_settings)
- end
-
- def delete_index(index_name: self::INDEX_NAME)
- Search::Client.indices.delete(index: index_name)
- end
-
- def refresh_index(index_name: self::INDEX_ALIAS)
- Search::Client.indices.refresh(index: index_name)
- end
-
- def add_alias(index_name: self::INDEX_NAME, index_alias: self::INDEX_ALIAS)
- Search::Client.indices.put_alias(index: index_name, name: index_alias)
- end
-
- def update_mappings(index_alias: self::INDEX_ALIAS)
- Search::Client.indices.put_mapping(index: index_alias, body: self::MAPPINGS)
- end
-
- def document_count
- Search::Client.count(index: self::INDEX_ALIAS)["count"]
- end
-
- def search_documents(params:)
- set_query_size(params)
- query_hash = "Search::QueryBuilders::#{name.demodulize}".safe_constantize.new(params: params).as_hash
-
- results = search(body: query_hash)
- hits = results.dig("hits", "hits").map { |hit| prepare_doc(hit) }
- paginate_hits(hits, params)
- end
-
- private
-
- def prepare_doc(hit)
- hit["_source"]
- end
-
- def search(body:)
- Search::Client.search(index: self::INDEX_ALIAS, body: body)
- end
-
- def set_query_size(params)
- params[:page] ||= self::DEFAULT_PAGE
- params[:per_page] ||= self::DEFAULT_PER_PAGE
-
- # pages start at 0
- params[:size] = params[:per_page].to_i * (params[:page].to_i + 1)
- end
-
- def paginate_hits(hits, params)
- start = params[:per_page] * params[:page]
- hits[start, params[:per_page]] || []
- end
-
- def settings
- { settings: { index: index_settings } }
- end
-
- def index_settings
- raise "Search classes must implement their own index settings"
- end
-
- def dynamic_settings
- { settings: { index: dynamic_index_settings } }
- end
-
- def dynamic_index_settings
- {}
- end
-
- def process_hashes(indexing_hashes)
- indexing_hashes.in_groups_of(1000, false).flat_map do |hashes|
- indexing_chunks(hashes).filter_map { |chunk| Search::Client.bulk(body: chunk) }
- end
- end
-
- def indexing_chunks(hashes)
- return [] unless hashes.any?
- return to_enum(__method__, hashes) unless block_given?
-
- size = 0
- chunk = []
- hashes.each do |hash|
- chunk << hash
- size += hash.to_s.bytesize
- next unless size > 5.megabytes
-
- yield chunk
- size = 0
- chunk = []
- end
- yield chunk
- end
- end
- end
-end
diff --git a/app/services/search/chat_channel_membership.rb b/app/services/search/chat_channel_membership.rb
deleted file mode 100644
index ef6533332..000000000
--- a/app/services/search/chat_channel_membership.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-module Search
- class ChatChannelMembership < Base
- INDEX_NAME = "chat_channel_memberships_#{Rails.env}".freeze
- INDEX_ALIAS = "chat_channel_memberships_#{Rails.env}_alias".freeze
- MAPPINGS = JSON.parse(File.read("config/elasticsearch/mappings/chat_channel_memberships.json"),
- symbolize_names: true).freeze
- DEFAULT_PAGE = 0
- DEFAULT_PER_PAGE = 30
-
- class << self
- private
-
- def index_settings
- if Rails.env.production?
- {
- number_of_shards: 3,
- number_of_replicas: 1
- }
- else
- {
- number_of_shards: 1,
- number_of_replicas: 0
- }
- end
- end
- end
- end
-end
diff --git a/app/services/search/client.rb b/app/services/search/client.rb
deleted file mode 100644
index 985ea3b11..000000000
--- a/app/services/search/client.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-module Search
- # Search client (uses Elasticsearch as a backend)
- class Client
- class << self
- # adapted from https://api.rubyonrails.org/classes/Module.html#method-i-delegate_missing_to
- def method_missing(method, *args, &block)
- return super unless target.respond_to?(method, false)
-
- # define for re-use
- self.class.define_method(method) do |*new_args, &new_block|
- request do
- target.public_send(method, *new_args, &new_block)
- end
- end
-
- # call the original method, this will only be called the first time
- # as in subsequent calls, the newly defined method will prevail
- request do
- target.public_send(method, *args, &block)
- end
- end
-
- # adapted from https://api.rubyonrails.org/classes/Module.html#method-i-delegate_missing_to
- def respond_to_missing?(method, _include_all = false)
- target.respond_to?(method, false) || super
- end
-
- private
-
- TRANSPORT_EXCEPTIONS = [
- Elasticsearch::Transport::Transport::Errors::BadRequest,
- Elasticsearch::Transport::Transport::Errors::NotFound,
- ].freeze
-
- def request
- yield
- rescue *TRANSPORT_EXCEPTIONS => e
- class_name = e.class.name.demodulize
- record_error(e.message, class_name)
-
- # raise specific error if known, generic one if unknown
- error_class = "::Search::Errors::Transport::#{class_name}".safe_constantize
- raise error_class, e.message if error_class
-
- raise ::Search::Errors::TransportError, e.message
- end
-
- def record_error(error_message, class_name)
- Honeycomb.add_field("elasticsearch.result", "error")
- Honeycomb.add_field("elasticsearch.error", class_name)
- ForemStatsClient.increment("elasticsearch.errors", tags: ["error:#{class_name}", "message:#{error_message}"])
- end
-
- def target
- @target ||= Elasticsearch::Client.new(
- url: ApplicationConfig["ELASTICSEARCH_URL"],
- retry_on_failure: 5,
- request_timeout: 30,
- adapter: :patron,
- log: Rails.env.development?,
- )
- end
- end
- end
-end
diff --git a/app/services/search/cluster.rb b/app/services/search/cluster.rb
deleted file mode 100644
index f1457be23..000000000
--- a/app/services/search/cluster.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-module Search
- class Cluster
- SEARCH_CLASSES = [
- Search::ChatChannelMembership,
- Search::Listing,
- Search::FeedContent,
- Search::Tag,
- Search::User,
- ].freeze
-
- class << self
- def recreate_indexes
- delete_indexes
- setup_indexes
- end
-
- def setup_indexes
- update_settings
- create_indexes
- update_indexes
- add_aliases
- update_mappings
- end
-
- def update_settings
- Search::Client.cluster.put_settings(body: default_settings)
- end
-
- def create_indexes
- SEARCH_CLASSES.each do |search_class|
- next if search_class.index_exists?
-
- search_class.create_index
- end
- end
-
- def update_indexes
- SEARCH_CLASSES.each(&:update_index)
- end
-
- def add_aliases
- SEARCH_CLASSES.each(&:add_alias)
- end
-
- def update_mappings
- SEARCH_CLASSES.each(&:update_mappings)
- end
-
- def delete_indexes
- return if Rails.env.production?
-
- SEARCH_CLASSES.each do |search_class|
- next unless Search::Client.indices.exists(index: search_class::INDEX_NAME)
-
- search_class.delete_index
- end
- end
-
- private
-
- def default_settings
- {
- persistent: {
- action: {
- auto_create_index: false
- }
- }
- }
- end
- end
- end
-end
diff --git a/app/services/search/feed_content.rb b/app/services/search/feed_content.rb
deleted file mode 100644
index f098202de..000000000
--- a/app/services/search/feed_content.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-module Search
- class FeedContent < Base
- INDEX_NAME = "feed_content_#{Rails.env}".freeze
- INDEX_ALIAS = "feed_content_#{Rails.env}_alias".freeze
- MAPPINGS = JSON.parse(File.read("config/elasticsearch/mappings/feed_content.json"), symbolize_names: true).freeze
- DEFAULT_PAGE = 0
- DEFAULT_PER_PAGE = 60
-
- INCLUDED_CLASS_NAMES = %w[Article Comment PodcastEpisode].freeze
-
- class << self
- INCLUDED_CLASS_NAMES.each do |class_name|
- define_method("#{class_name.underscore.pluralize}_document_count") do
- Search::Client.count(
- index: self::INDEX_ALIAS, body: count_filter(class_name),
- )["count"]
- end
- end
-
- private
-
- def prepare_doc(hit)
- source = hit["_source"]
- source["tag_list"] = hit["tags"]&.map { |t| t["name"] } || []
- source["id"] = source["id"].split("_").last.to_i
- source["tag_list"] = source["tags"]&.map { |t| t["name"] } || []
- source["flare_tag"] = source["flare_tag_hash"]
- source["user_id"] = source.dig("user", "id")
- source["highlight"] = hit["highlight"]
- source["readable_publish_date"] = source["readable_publish_date_string"]
- source["podcast"] = {
- "slug" => source["slug"],
- "image_url" => source["main_image"],
- "title" => source["title"]
- }
- source["_score"] = hit["_score"]
-
- source.merge(timestamps_hash(hit))
- end
-
- def timestamps_hash(hit)
- published_at = hit.dig("_source", "published_at")
- published_at_timestamp = Time.zone.parse(published_at || "")
- {
- "published_at_int" => published_at_timestamp.to_i,
- "published_timestamp" => published_at
- }
- end
-
- def count_filter(class_name)
- {
- query: {
- bool: {
- filter: { term: { class_name: class_name } }
- }
- }
- }
- end
-
- def index_settings
- if Rails.env.production?
- {
- number_of_shards: 10,
- number_of_replicas: 1
- }
- else
- {
- number_of_shards: 1,
- number_of_replicas: 0
- }
- end
- end
-
- def dynamic_index_settings
- if Rails.env.production?
- { refresh_interval: "5s" }
- else
- { refresh_interval: "1s" }
- end
- end
- end
- end
-end
diff --git a/app/services/search/listing.rb b/app/services/search/listing.rb
deleted file mode 100644
index a93d6aaad..000000000
--- a/app/services/search/listing.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-module Search
- class Listing < Base
- # We used to use both "classified listing" and "listing" throughout the app.
- # We standardized on the latter in most places, but kept the index name here.
- INDEX_NAME = "classified_listings_#{Rails.env}".freeze
- INDEX_ALIAS = "classified_listings_#{Rails.env}_alias".freeze
- MAPPINGS = JSON.parse(File.read("config/elasticsearch/mappings/listings.json"), symbolize_names: true).freeze
- DEFAULT_PAGE = 0
- DEFAULT_PER_PAGE = 75
-
- class << self
- private
-
- def index_settings
- if Rails.env.production?
- {
- number_of_shards: 2,
- number_of_replicas: 1
- }
- else
- {
- number_of_shards: 1,
- number_of_replicas: 0
- }
- end
- end
- end
- end
-end
diff --git a/app/services/search/query_builders/chat_channel_membership.rb b/app/services/search/query_builders/chat_channel_membership.rb
deleted file mode 100644
index 5158d6429..000000000
--- a/app/services/search/query_builders/chat_channel_membership.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-module Search
- module QueryBuilders
- class ChatChannelMembership < QueryBase
- FILTER_KEYS = %i[
- channel_status
- channel_type
- status
- viewable_by
- ].freeze
-
- TERMS_FILTER_KEYS = %i[viewable_by status].freeze
-
- QUERY_KEYS = %i[
- channel_text
- ].freeze
-
- DEFAULT_PARAMS = {
- sort_by: "channel_last_message_at",
- sort_direction: "desc",
- size: 0
- }.freeze
-
- def initialize(params:)
- super()
-
- @params = params.deep_symbolize_keys
- @params[:viewable_by] = @params[:user_id]
-
- # TODO: @mstruve: When we want to allow people like admins to
- # search ALL memberships this will need to change
- @params[:status] = %w[active joining_request]
-
- build_body
- end
-
- private
-
- def build_queries
- @body[:query] = {}
- @body[:query][:bool] = { filter: filter_conditions }
- @body[:query][:bool][:must] = query_conditions if query_keys_present?
- end
-
- def filter_conditions
- FILTER_KEYS.filter_map do |filter_key|
- next if @params[filter_key].blank? || @params[filter_key] == "all"
-
- if TERMS_FILTER_KEYS.include?(filter_key)
- { terms: { filter_key => @params[filter_key] } }
- else
- { term: { filter_key => @params[filter_key] } }
- end
- end
- end
- end
- end
-end
diff --git a/app/services/search/query_builders/feed_content.rb b/app/services/search/query_builders/feed_content.rb
deleted file mode 100644
index f81bec168..000000000
--- a/app/services/search/query_builders/feed_content.rb
+++ /dev/null
@@ -1,202 +0,0 @@
-module Search
- module QueryBuilders
- class FeedContent < QueryBase
- # In order for highlighting to work properly we have to search the fields we want to highlight
- QUERY_KEYS = {
- search_fields: [
- "tags.keywords_for_search",
- "tags.name^3",
- "body_text^2",
- "title^6",
- "user.name",
- "user.username",
- "organization.name",
- ]
- }.freeze
-
- # Search keys from our controllers may not match what we have stored in Elasticsearch so we map them here,
- # this allows us to change our Elasticsearch docs without worrying about the frontend
- TERM_KEYS = {
- id: "id", # NOTE: FeedContent ids are formatted article_#, podcast_episode_#, comment_#
- tag_names: "tags.name",
- approved: "approved",
- user_id: "user.id",
- class_name: "class_name",
- published: "published",
- organization_id: "organization.id"
- }.freeze
-
- RANGE_KEYS = %i[
- published_at
- ].freeze
-
- DEFAULT_PARAMS = {
- sort: [
- :_score,
- { score: "desc" },
- { hotness_score: "desc" },
- { comments_count: "desc" },
- ],
- size: 0
- }.freeze
-
- HIGHLIGHT_FIELDS = %w[
- body_text
- ].freeze
-
- SOURCE = %i[
- id
- class_name
- cloudinary_video_url
- comments_count
- flare_tag_hash
- main_image
- path
- public_reactions_count
- published_at
- readable_publish_date_string
- reading_time
- slug
- tags
- title
- video_duration_in_minutes
- video_duration_string
- user
- organization
- ].freeze
-
- attr_accessor :params, :body
-
- def initialize(params:)
- super()
-
- @params = params.deep_symbolize_keys
-
- # Default to only showing published articles to start
- @params[:published] = true
-
- build_body
- add_function_scoring unless sort_params_present?
- end
-
- private
-
- def add_sort
- return @body[:sort] = DEFAULT_PARAMS[:sort] unless sort_params_present?
-
- @body[:sort] = { @params[:sort_by] => @params[:sort_direction] }
- end
-
- def add_highlight_fields
- highlight_fields = { encoder: "html", pre_tags: "", post_tags: "", fields: {} }
- HIGHLIGHT_FIELDS.each do |field_name|
- # This hash can be filled with options to further customize our highlighting
- # https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html#request-body-search-highlighting
- highlight_fields[:fields][field_name] = { order: :score, number_of_fragments: 2, fragment_size: 75 }
- end
- @body[:highlight] = highlight_fields
- end
-
- def filter_source
- @body[:_source] = SOURCE
- end
-
- def build_queries
- @body[:query] = { bool: {} }
- @body[:query][:bool][:filter] = filter_conditions if filter_keys_present?
- return unless query_keys_present?
-
- @body[:query][:bool][:must] = query_conditions
- # Boost the score of queries that match these conditions but if they dont match any,
- # minimum_should_match: 0, then that is OK
- @body[:query][:bool][:should] = match_phrase_conditions
- @body[:query][:bool][:minimum_should_match] = 0
- end
-
- def filter_conditions
- filter_conditions = []
-
- filter_conditions.concat(term_keys) if terms_keys_present?
- filter_conditions.concat(range_keys) if range_keys_present?
-
- filter_conditions
- end
-
- def filter_keys_present?
- range_keys_present? || terms_keys_present?
- end
-
- def terms_keys_present?
- TERM_KEYS.detect { |key, _| @params[key].present? }
- end
-
- def range_keys_present?
- RANGE_KEYS.detect { |key| @params[key].present? }
- end
-
- def term_keys
- TERM_KEYS.filter_map do |term_key, search_key|
- next unless @params.key? term_key
-
- values = Array.wrap(@params[term_key])
-
- if params[:tag_boolean_mode] == "all" && term_key == :tag_names
- values.map { |val| { term: { search_key => val } } }
- else
- { terms: { search_key => values } }
- end
- end.compact
- end
-
- def range_keys
- RANGE_KEYS.filter_map do |range_key|
- next unless @params.key? range_key
-
- { range: { range_key => @params[range_key] } }
- end
- end
-
- def query_hash(key, fields)
- {
- simple_query_string: {
- query: key.downcase,
- fields: fields,
- lenient: true,
- analyze_wildcard: true,
- minimum_should_match: 2
- }
- }
- end
-
- def add_function_scoring
- @body[:query] = { function_score: { query: @body[:query] } }
- @body[:query][:function_score][:functions] = scoring_functions
- end
-
- def scoring_functions
- [
- scoring_filter(1000, 2.5),
- scoring_filter(500, 2),
- scoring_filter(100, 1.5),
- ]
- end
-
- def scoring_filter(score, weight)
- {
- filter: {
- range: {
- score: {
- gte: score
- }
- }
- },
- weight: weight
- }
- end
-
- def sort_params_present?
- @params[:sort_by] && @params[:sort_direction]
- end
- end
- end
-end
diff --git a/app/services/search/query_builders/listing.rb b/app/services/search/query_builders/listing.rb
deleted file mode 100644
index 4b5332fdf..000000000
--- a/app/services/search/query_builders/listing.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-module Search
- module QueryBuilders
- class Listing < QueryBase
- TERM_KEYS = %i[
- category
- contact_via_connect
- location
- published
- slug
- tags
- title
- user_id
- ].freeze
-
- RANGE_KEYS = %i[
- bumped_at
- expires_at
- ].freeze
-
- QUERY_KEYS = %i[
- listing_search
- ].freeze
-
- DEFAULT_PARAMS = {
- published: true,
- sort_by: "bumped_at",
- sort_direction: "desc",
- size: 0
- }.freeze
-
- def initialize(params:)
- super()
-
- @params = params.deep_symbolize_keys
-
- # For now, we're not allowing searches for Listings that are
- # not published. If we want to change this in the future we can do:
- # @params[:published] = DEFAULT_PARAMS[:published] unless @params.key?(:published)
- @params[:published] = DEFAULT_PARAMS[:published]
-
- build_body
- end
-
- private
-
- def build_queries
- @body[:query] = { bool: {} }
- @body[:query][:bool][:filter] = filter_conditions
- @body[:query][:bool][:must] = query_conditions if query_keys_present?
- end
-
- def filter_conditions
- filter_conditions = []
-
- # term_keys are always present because we are setting a filter of
- # published: true by default
- filter_conditions.concat term_keys
-
- filter_conditions.concat range_keys if range_keys_present?
-
- filter_conditions
- end
-
- def term_keys
- TERM_KEYS.flat_map do |term_key|
- next unless @params.key? term_key
-
- values = Array.wrap(@params[term_key])
-
- if params[:tag_boolean_mode] == "all" && term_key == :tags
- values.map { |tag| { terms: { term_key => Array.wrap(tag) } } }
- else
- { terms: { term_key => values } }
- end
- end.compact
- end
-
- def range_keys
- RANGE_KEYS.filter_map do |range_key|
- next unless @params.key? range_key
-
- { range: { range_key => @params[range_key] } }
- end
- end
-
- def range_keys_present?
- RANGE_KEYS.detect { |key| @params[key].present? }
- end
- end
- end
-end
diff --git a/app/services/search/query_builders/query_base.rb b/app/services/search/query_builders/query_base.rb
deleted file mode 100644
index 9f9600ef7..000000000
--- a/app/services/search/query_builders/query_base.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-module Search
- module QueryBuilders
- class QueryBase
- attr_accessor :params, :body
-
- def as_hash
- @body
- end
-
- private
-
- def build_body
- @body = ActiveSupport::HashWithIndifferentAccess.new
- build_queries
- add_sort
- set_size
- add_highlight_fields
- filter_source
- end
-
- def add_highlight_fields; end
-
- def filter_source; end
-
- def add_sort
- sort_key = @params[:sort_by] || self.class::DEFAULT_PARAMS[:sort_by]
- sort_direction = @params[:sort_direction] || self.class::DEFAULT_PARAMS[:sort_direction]
- @body[:sort] = {
- sort_key => sort_direction
- }
- end
-
- def set_size
- # By default we will return 0 documents if size is not specified
- @body[:size] = @params[:size] || self.class::DEFAULT_PARAMS[:size]
- end
-
- def query_keys_present?
- self.class::QUERY_KEYS.detect { |key, _| @params[key].present? }
- end
-
- def query_conditions
- self.class::QUERY_KEYS.filter_map do |query_key, query_fields|
- next if @params[query_key].blank?
-
- fields = query_fields.presence || [query_key]
-
- query_hash(@params[query_key], fields)
- end
- end
-
- def match_phrase_conditions
- self.class::QUERY_KEYS.filter_map do |query_key, _fields|
- next if @params[query_key].blank?
-
- match_phrase(@params[query_key], query_key)
- end
- end
-
- def match_phrase(phrase, query_key)
- {
- match_phrase: {
- query_key => { query: phrase, slop: 0 }
- }
- }
- end
-
- def query_hash(key, fields)
- {
- simple_query_string: {
- query: "#{key}*",
- fields: fields,
- lenient: true,
- analyze_wildcard: true
- }
- }
- end
- end
- end
-end
diff --git a/app/services/search/query_builders/user.rb b/app/services/search/query_builders/user.rb
deleted file mode 100644
index e832edba0..000000000
--- a/app/services/search/query_builders/user.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-module Search
- module QueryBuilders
- class User < QueryBase
- QUERY_KEYS = %i[
- search_fields
- ].freeze
-
- # In the event we want to search for documents that do NOT contain certain values
- EXCLUDED_TERM_KEYS = {
- exclude_roles: "roles"
- }.freeze
-
- DEFAULT_PARAMS = {
- sort_by: "hotness_score",
- sort_direction: "desc",
- size: 0
- }.freeze
-
- def initialize(params:)
- super()
-
- @params = params.deep_symbolize_keys
-
- # default to excluding users who are suspended
- # TODO: [@jacobherrington] banned can be removed once the data scripts have succesfully run on all Forems
- @params[:exclude_roles] = %w[suspended banned]
-
- build_body
- end
-
- private
-
- def build_queries
- @body[:query] = { bool: {} }
- @body[:query][:bool][:must] = query_conditions if query_keys_present?
- @body[:query][:bool][:must_not] = excluded_term_keys if excluded_term_keys_present?
- end
-
- def excluded_term_keys_present?
- self.class::EXCLUDED_TERM_KEYS.detect { |key, _| @params[key].present? }
- end
-
- def excluded_term_keys
- EXCLUDED_TERM_KEYS.filter_map do |term_key, search_key|
- next unless @params.key? term_key
-
- { terms: { search_key => Array.wrap(@params[term_key]) } }
- end
- end
- end
- end
-end
diff --git a/app/services/search/reading_list.rb b/app/services/search/reading_list.rb
deleted file mode 100644
index cc696a438..000000000
--- a/app/services/search/reading_list.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-module Search
- # This class does not inherit from Search::Base like our other search classes bc it
- # is using the FeedContent index to search for ReadingList reaction articles rather than its
- # own separate index. The primary function of this class is to help combine and parse reaction
- # data with article Elasticsearch data to populate the Reading List view.
- class ReadingList
- DEFAULT_PAGE = 0
- DEFAULT_PER_PAGE = 60
- DEFAULT_STATUS = %w[valid confirmed].freeze
-
- # Using a class method here to follow the pattern of the other Search classes
- def self.search_documents(params:, user:)
- new(params: params, user: user).reading_list_reactions
- end
-
- def initialize(params:, user:)
- self.status = params.delete(:status) || DEFAULT_STATUS
- self.view_page = params.delete(:page) || DEFAULT_PAGE
- self.view_per_page = params.delete(:per_page) || DEFAULT_PER_PAGE
- self.user = user
- self.search_params = params
- end
-
- def reading_list_reactions
- ordered_articles = parse_and_order_articles(article_docs)
- { "reactions" => paginate_articles(ordered_articles), "total" => total }
- end
-
- private
-
- attr_accessor :search_params, :user, :status, :view_page, :view_per_page, :total
-
- def paginate_articles(ordered_articles)
- start = view_per_page * view_page
- ordered_articles[start, view_per_page] || []
- end
-
- def article_docs
- return @article_docs if @article_docs
-
- # Gather articles from Elasticsearch based on search criteria containing
- # tags, text search, status, and the list of IDs of all articles in a user's
- # reading list
- docs = FeedContent.search_documents(
- params: search_params.merge(
- id: search_ids,
- class_name: "Article",
- page: 0,
- per_page: reading_list_article_ids.count,
- ),
- )
- self.total = docs.count
- @article_docs = docs.index_by { |doc| doc["id"] }
- end
-
- def reading_list_article_ids
- # Collect all reading list IDs and article IDs for a user
- @reading_list_article_ids ||= user.reactions.readinglist.where(status: status).order(id: :desc).pluck(
- :reactable_id, :id
- ).to_h
- end
-
- def search_ids
- reading_list_article_ids.keys.map { |id| "article_#{id}" }
- end
-
- def parse_and_order_articles(articles)
- # Combines reaction and article data to create hashes that contain the fields
- # the reading list view needs. Ensures articles are returned in order of reaction ID
- reading_list_article_ids.filter_map do |article_id, reaction_id|
- found_article_doc = articles[article_id]
- next unless found_article_doc
-
- { "id" => reaction_id, "user_id" => user.id, "reactable" => articles[article_id] }
- end
- end
- end
-end
diff --git a/app/services/search/tag.rb b/app/services/search/tag.rb
deleted file mode 100644
index 53c965b45..000000000
--- a/app/services/search/tag.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-module Search
- class Tag < Base
- INDEX_NAME = "tags_#{Rails.env}".freeze
- INDEX_ALIAS = "tags_#{Rails.env}_alias".freeze
- MAPPINGS = JSON.parse(File.read("config/elasticsearch/mappings/tags.json"), symbolize_names: true).freeze
-
- class << self
- def search_documents(query_string)
- results = search(body: query(query_string))
- results.dig("hits", "hits").map { |tag_doc| tag_doc["_source"] }
- end
-
- private
-
- def query(query_string)
- {
- query: {
- query_string: {
- query: query_string,
- analyze_wildcard: true,
- allow_leading_wildcard: false
- }
- },
- sort: {
- hotness_score: "desc"
- }
- }
- end
-
- def index_settings
- if Rails.env.production?
- {
- number_of_shards: 1,
- number_of_replicas: 1
- }
- else
- {
- number_of_shards: 1,
- number_of_replicas: 0
- }
- end
- end
- end
- end
-end
diff --git a/app/services/search/user.rb b/app/services/search/user.rb
deleted file mode 100644
index ea9ce87b4..000000000
--- a/app/services/search/user.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-module Search
- class User < Base
- INDEX_NAME = "users_#{Rails.env}".freeze
- INDEX_ALIAS = "users_#{Rails.env}_alias".freeze
- MAPPINGS = JSON.parse(File.read("config/elasticsearch/mappings/users.json"), symbolize_names: true).freeze
- DEFAULT_PAGE = 0
- DEFAULT_PER_PAGE = 20
-
- class << self
- def search_usernames(username)
- results = search(body: username_query(username))
- results.dig("hits", "hits").map do |doc|
- source = doc["_source"]
- {
- "username" => source["username"],
- "name" => source["name"],
- "profile_image_90" => source["profile_image_90"]
- }
- end
- end
-
- private
-
- def username_query(username)
- {
- query: {
- query_string: {
- query: "username:#{username}*",
- analyze_wildcard: true,
- allow_leading_wildcard: false
- }
- },
- size: Search::Postgres::Username::MAX_RESULTS # Limit the number of results we return to the frontend
- }
- end
-
- def prepare_doc(hit)
- source = hit["_source"]
- {
- "user" => {
- "username" => source["username"],
- "name" => source["username"],
- "profile_image_90" => source["profile_image_90"]
- },
- "title" => source["name"],
- "path" => source["path"],
- "id" => source["id"],
- "class_name" => "User",
- "public_reactions_count" => source["public_reactions_count"],
- "comments_count" => source["comments_count"],
- "badge_achievements_count" => source["badge_achievements_count"],
- "last_comment_at" => source["last_comment_at"],
- "user_id" => source["id"]
- }
- end
-
- def index_settings
- if Rails.env.production?
- {
- number_of_shards: 10,
- number_of_replicas: 1
- }
- else
- {
- number_of_shards: 1,
- number_of_replicas: 0
- }
- end
- end
-
- def dynamic_index_settings
- if Rails.env.production?
- { refresh_interval: "10s" }
- else
- { refresh_interval: "1s" }
- end
- end
- end
- end
-end
diff --git a/app/services/users/delete_activity.rb b/app/services/users/delete_activity.rb
index cb6f9dd24..83054c027 100644
--- a/app/services/users/delete_activity.rb
+++ b/app/services/users/delete_activity.rb
@@ -2,8 +2,6 @@ module Users
module DeleteActivity
module_function
- # If you're removing data that is in Elasticsearch, make sure to use
- # .destroy_all to trigger the callback to remove the document(s)
def call(user)
delete_social_media(user)
delete_profile_info(user)
diff --git a/app/services/users/delete_articles.rb b/app/services/users/delete_articles.rb
index 33d8945e1..64853fa2b 100644
--- a/app/services/users/delete_articles.rb
+++ b/app/services/users/delete_articles.rb
@@ -12,10 +12,8 @@ module Users
comment.reactions.delete_all
EdgeCache::BustComment.call(comment.commentable)
EdgeCache::BustUser.call(comment.user)
- comment.remove_from_elasticsearch
comment.delete
end
- article.remove_from_elasticsearch
article.delete
article.purge
end
diff --git a/app/services/users/delete_comments.rb b/app/services/users/delete_comments.rb
index 7659dfc77..273d30bed 100644
--- a/app/services/users/delete_comments.rb
+++ b/app/services/users/delete_comments.rb
@@ -9,7 +9,6 @@ module Users
comment.reactions.delete_all
EdgeCache::BustComment.call(comment.commentable)
comment.remove_notifications
- comment.remove_from_elasticsearch
comment.delete
end
EdgeCache::BustUser.call(user)
diff --git a/app/workers/articles/score_calc_worker.rb b/app/workers/articles/score_calc_worker.rb
index b6fa3c573..dddf0cce3 100644
--- a/app/workers/articles/score_calc_worker.rb
+++ b/app/workers/articles/score_calc_worker.rb
@@ -9,7 +9,6 @@ module Articles
return unless article
article.update_score
- article.index_to_elasticsearch_inline
end
end
end
diff --git a/app/workers/chat_channels/indexes_memberships_worker.rb b/app/workers/chat_channels/indexes_memberships_worker.rb
deleted file mode 100644
index 31f0fbcea..000000000
--- a/app/workers/chat_channels/indexes_memberships_worker.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-module ChatChannels
- class IndexesMembershipsWorker
- include Sidekiq::Worker
-
- sidekiq_options queue: :high_priority, lock: :until_executing
-
- def perform(chat_channel_id)
- chat_channel = ChatChannel.find(chat_channel_id)
- chat_channel.chat_channel_memberships.each(&:index_to_elasticsearch)
- end
- end
-end
diff --git a/app/workers/metrics/record_data_counts_worker.rb b/app/workers/metrics/record_data_counts_worker.rb
index 2e900646f..575932fe2 100644
--- a/app/workers/metrics/record_data_counts_worker.rb
+++ b/app/workers/metrics/record_data_counts_worker.rb
@@ -14,16 +14,6 @@ module Metrics
Rails.logger.info(message: "db_table_size", table_info: { table_name: model.table_name, table_size: db_count })
ForemStatsClient.gauge("postgres.db_table_size", db_count, tags: ["table_name:#{model.table_name}"])
-
- next unless model.const_defined?(:SEARCH_CLASS)
-
- document_count = if model::SEARCH_CLASS.respond_to?("#{model.to_s.underscore.pluralize}_document_count")
- model::SEARCH_CLASS.public_send("#{model.to_s.underscore.pluralize}_document_count")
- else
- model::SEARCH_CLASS.document_count
- end
- ForemStatsClient.gauge("elasticsearch.document_count", document_count,
- tags: ["table_name:#{model.table_name}"])
end
end
end
diff --git a/app/workers/rating_votes/assign_rating_worker.rb b/app/workers/rating_votes/assign_rating_worker.rb
index 2a1a55167..9a13a54e0 100644
--- a/app/workers/rating_votes/assign_rating_worker.rb
+++ b/app/workers/rating_votes/assign_rating_worker.rb
@@ -16,7 +16,6 @@ module RatingVotes
experience_level_rating_distribution: ratings.max - ratings.min,
last_experience_level_rating_at: Time.current,
)
- article.index_to_elasticsearch_inline
end
end
end
diff --git a/app/workers/search/bulk_index_worker.rb b/app/workers/search/bulk_index_worker.rb
deleted file mode 100644
index 9d81ba0f1..000000000
--- a/app/workers/search/bulk_index_worker.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-module Search
- class BulkIndexWorker
- include Sidekiq::Worker
-
- sidekiq_options queue: :high_priority, lock: :until_executing
-
- def perform(object_class, ids)
- data_hashes = object_class.constantize
- .eager_load_serialized_data
- .where(id: ids)
- .find_each.map(&:serialized_search_hash)
-
- search_class = object_class.constantize::SEARCH_CLASS
-
- search_class.bulk_index(data_hashes)
- end
- end
-end
diff --git a/app/workers/search/index_worker.rb b/app/workers/search/index_worker.rb
deleted file mode 100644
index 247f7f846..000000000
--- a/app/workers/search/index_worker.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-module Search
- class IndexWorker
- include Sidekiq::Worker
-
- sidekiq_options queue: :high_priority, lock: :until_executing
-
- def perform(object_class, id)
- object = object_class.constantize.find_by(id: id)
- object&.index_to_elasticsearch_inline
- end
- end
-end
diff --git a/app/workers/search/remove_from_index_worker.rb b/app/workers/search/remove_from_index_worker.rb
deleted file mode 100644
index fecf9db5d..000000000
--- a/app/workers/search/remove_from_index_worker.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-module Search
- class RemoveFromIndexWorker
- include Sidekiq::Worker
-
- sidekiq_options queue: :medium_priority, lock: :until_executing
-
- def perform(search_class, id)
- search_class.safe_constantize.delete_document(id)
- rescue Search::Errors::Transport::NotFound
- # Often race conditions cause us never to index a document and
- # we end up with an error when trying to remove it. Because
- # we have count checks that run every hour to track the counts in
- # Elasticsearch and db to ensure they match we can ignore this error
- nil
- end
- end
-end
diff --git a/bin/setup b/bin/setup
index 98ecea7bf..e0fb2b846 100755
--- a/bin/setup
+++ b/bin/setup
@@ -30,9 +30,6 @@ FileUtils.chdir APP_ROOT do
FileUtils.cp "config/database.yml.sample", "config/database.yml"
end
- puts "\n== Preparing Test Elasticsearch =="
- system! 'RAILS_ENV="test" bin/rails search:setup'
-
puts "\n== Initializing the application =="
system! "bin/rails app_initializer:setup forem:setup"
diff --git a/config/elasticsearch/mappings/chat_channel_memberships.json b/config/elasticsearch/mappings/chat_channel_memberships.json
deleted file mode 100644
index 1e188ea99..000000000
--- a/config/elasticsearch/mappings/chat_channel_memberships.json
+++ /dev/null
@@ -1,61 +0,0 @@
-{
- "dynamic": "strict",
- "properties": {
- "id": {
- "type": "keyword"
- },
- "status": {
- "type": "keyword"
- },
- "viewable_by": {
- "type": "keyword"
- },
- "chat_channel_id": {
- "type": "keyword"
- },
- "last_opened_at": {
- "type": "date"
- },
- "channel_text": {
- "type": "text"
- },
- "channel_last_message_at": {
- "type": "date"
- },
- "channel_status": {
- "type": "keyword"
- },
- "channel_status": {
- "type": "keyword"
- },
- "channel_type": {
- "type": "keyword"
- },
- "channel_username": {
- "type": "keyword"
- },
- "channel_name": {
- "type": "text"
- },
- "channel_image": {
- "type": "keyword"
- },
- "channel_modified_slug": {
- "type": "text",
- "fields": {
- "raw": {
- "type": "keyword"
- }
- }
- },
- "channel_messages_count": {
- "type": "integer"
- },
- "channel_discoverable": {
- "type": "boolean"
- },
- "last_indexed_at": {
- "type": "date"
- }
- }
-}
diff --git a/config/elasticsearch/mappings/feed_content.json b/config/elasticsearch/mappings/feed_content.json
deleted file mode 100644
index 04124a792..000000000
--- a/config/elasticsearch/mappings/feed_content.json
+++ /dev/null
@@ -1,186 +0,0 @@
-{
- "dynamic": "strict",
- "properties": {
- "id": {
- "type": "keyword"
- },
- "approved": {
- "type": "boolean"
- },
- "body_text": {
- "type": "text",
- "copy_to": "search_fields"
- },
- "class_name": {
- "type": "keyword"
- },
- "cloudinary_video_url": {
- "type": "keyword"
- },
- "comments_count": {
- "type": "integer"
- },
- "experience_level_rating": {
- "type": "integer"
- },
- "experience_level_rating_distribution": {
- "type": "integer"
- },
- "featured": {
- "type": "boolean"
- },
- "featured_number": {
- "type": "integer"
- },
- "flare_tag_hash": {
- "dynamic": "strict",
- "properties": {
- "name": {
- "type": "keyword"
- },
- "bg_color_hex": {
- "type": "keyword"
- },
- "text_color_hex": {
- "type": "keyword"
- }
- }
- },
- "hotness_score": {
- "type": "integer"
- },
- "last_indexed_at": {
- "type": "date"
- },
- "main_image": {
- "type": "keyword"
- },
- "organization": {
- "dynamic": "strict",
- "properties": {
- "slug": {
- "type": "keyword"
- },
- "name": {
- "type": "text",
- "copy_to": "search_fields",
- "fields": {
- "raw": {
- "type": "keyword"
- }
- }
- },
- "id": {
- "type": "keyword"
- },
- "profile_image_90": {
- "type": "keyword"
- }
- }
- },
- "path": {
- "type": "keyword"
- },
- // deprecated in favor of public_reactions_count, to be removed
- "positive_reactions_count": {
- "type": "integer"
- },
- "public_reactions_count": {
- "type": "integer"
- },
- "published": {
- "type": "boolean"
- },
- "published_at": {
- "type": "date"
- },
- "quote": {
- "type": "text"
- },
- "reactions_count": {
- "type": "integer"
- },
- "readable_publish_date": {
- "type": "date"
- },
- "readable_publish_date_string": {
- "type": "keyword"
- },
- "reading_time": {
- "type": "integer"
- },
- "score": {
- "type": "integer"
- },
- "search_fields": {
- "type": "text"
- },
- "search_score": {
- "type": "integer"
- },
- "slug": {
- "type": "keyword"
- },
- "subtitle": {
- "type": "text"
- },
- "summary": {
- "type": "text"
- },
- "tags": {
- "dynamic": "strict",
- "properties": {
- "name": {
- "type": "keyword",
- "copy_to": "search_fields"
- },
- "keywords_for_search": {
- "type": "keyword",
- "copy_to": "search_fields"
- }
- }
- },
- "title": {
- "type": "text",
- "copy_to": "search_fields",
- "fields": {
- "raw": {
- "type": "keyword"
- }
- }
- },
- "user": {
- "dynamic": "strict",
- "properties": {
- "username": {
- "type": "keyword",
- "copy_to": "search_fields"
- },
- "name": {
- "type": "text",
- "copy_to": "search_fields",
- "fields": {
- "raw": {
- "type": "keyword"
- }
- }
- },
- "id": {
- "type": "keyword"
- },
- "profile_image_90": {
- "type": "keyword"
- }
- }
- },
- "video_duration_in_minutes": {
- "type": "integer"
- },
- "video_duration_string": {
- "type": "keyword"
- },
- "website_url": {
- "type": "keyword"
- }
- }
-}
diff --git a/config/elasticsearch/mappings/listings.json b/config/elasticsearch/mappings/listings.json
deleted file mode 100644
index e832e30af..000000000
--- a/config/elasticsearch/mappings/listings.json
+++ /dev/null
@@ -1,87 +0,0 @@
-{
- "dynamic": "strict",
- "properties": {
- "id": {
- "type": "keyword"
- },
- "author": {
- "dynamic": "strict",
- "properties": {
- "username": {
- "type": "keyword"
- },
- "name": {
- "type": "keyword"
- },
- "profile_image_90": {
- "type": "keyword"
- }
- }
- },
- "body_markdown": {
- "type": "text",
- "copy_to": "listing_search"
- },
- "originally_published_at": {
- "type": "date"
- },
- "bumped_at": {
- "type": "date"
- },
- "category": {
- "type": "keyword"
- },
- "listing_search": {
- "type": "text"
- },
- "contact_via_connect": {
- "type": "boolean"
- },
- "expires_at": {
- "type": "date"
- },
- "last_indexed_at": {
- "type": "date"
- },
- "location": {
- "type": "text",
- "copy_to": "listing_search",
- "fields": {
- "raw": {
- "type": "keyword"
- }
- }
- },
- "processed_html": {
- "type": "keyword"
- },
- "published": {
- "type": "boolean"
- },
- "slug": {
- "type": "text",
- "copy_to": "listing_search",
- "fields": {
- "raw": {
- "type": "keyword"
- }
- }
- },
- "tags": {
- "type": "keyword",
- "copy_to": "listing_search"
- },
- "title": {
- "type": "text",
- "copy_to": "listing_search",
- "fields": {
- "raw": {
- "type": "keyword"
- }
- }
- },
- "user_id": {
- "type": "keyword"
- }
- }
-}
diff --git a/config/elasticsearch/mappings/reactions.json b/config/elasticsearch/mappings/reactions.json
deleted file mode 100644
index 30dab30fd..000000000
--- a/config/elasticsearch/mappings/reactions.json
+++ /dev/null
@@ -1,96 +0,0 @@
-{
- "dynamic": "strict",
- "properties": {
- "id": {
- "type": "keyword"
- },
- "category": {
- "type": "keyword"
- },
- "created_at": {
- "type": "date"
- },
- "last_indexed_at": {
- "type": "date"
- },
- "reactable": {
- "dynamic": "strict",
- "properties": {
- "id": {
- "type": "keyword"
- },
- "body_text": {
- "type": "text",
- "copy_to": "search_fields"
- },
- "class_name": {
- "type": "keyword"
- },
- "path": {
- "type": "keyword"
- },
- "published_date_string": {
- "type": "keyword"
- },
- "reading_time": {
- "type": "integer"
- },
- "tags": {
- "dynamic": "strict",
- "properties": {
- "name": {
- "type": "keyword",
- "copy_to": "search_fields"
- },
- "keywords_for_search": {
- "type": "keyword",
- "copy_to": "search_fields"
- }
- }
- },
- "title": {
- "type": "text",
- "copy_to": "search_fields",
- "fields": {
- "raw": {
- "type": "keyword"
- }
- }
- },
- "user": {
- "dynamic": "strict",
- "properties": {
- "username": {
- "type": "keyword",
- "copy_to": "search_fields"
- },
- "name": {
- "type": "text",
- "copy_to": "search_fields",
- "fields": {
- "raw": {
- "type": "keyword"
- }
- }
- },
- "id": {
- "type": "keyword"
- },
- "profile_image_90": {
- "type": "keyword"
- }
- }
- }
- }
- },
- "search_fields": {
- "type": "text"
- },
- "status": {
- "type": "keyword"
- },
- "user_id": {
- "type": "keyword"
- }
- }
-}
diff --git a/config/elasticsearch/mappings/tags.json b/config/elasticsearch/mappings/tags.json
deleted file mode 100644
index ce5374ef4..000000000
--- a/config/elasticsearch/mappings/tags.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "dynamic": "strict",
- "properties": {
- "id": {
- "type": "keyword"
- },
- "last_indexed_at": {
- "type": "date"
- },
- "name": {
- "type": "text",
- "fields": {
- "raw": {
- "type": "keyword"
- }
- }
- },
- "hotness_score": {
- "type": "integer"
- },
- "supported": {
- "type": "boolean"
- },
- "short_summary": {
- "type": "text"
- },
- "rules_html": {
- "type": "text"
- }
- }
-}
diff --git a/config/elasticsearch/mappings/users.json b/config/elasticsearch/mappings/users.json
deleted file mode 100644
index c7f6e594a..000000000
--- a/config/elasticsearch/mappings/users.json
+++ /dev/null
@@ -1,87 +0,0 @@
-{
- "dynamic": "strict",
- "properties": {
- "id": {
- "type": "keyword"
- },
- "available_for": {
- "type": "keyword",
- "copy_to": "search_fields"
- },
- "badge_achievements_count": {
- "type": "integer"
- },
- "comments_count": {
- "type": "integer"
- },
- "employer_name": {
- "type": "keyword",
- "copy_to": "search_fields"
- },
- "hotness_score": {
- "type": "integer"
- },
- "last_comment_at": {
- "type": "date"
- },
- "last_indexed_at": {
- "type": "date"
- },
- "mostly_work_with": {
- "type": "keyword",
- "copy_to": "search_fields"
- },
- "name": {
- "type": "text",
- "copy_to": "search_fields"
- },
- "path": {
- "type": "keyword"
- },
- // deprecated in favor of public_reactions_count, to be removed
- "positive_reactions_count": {
- "type": "integer"
- },
- "public_reactions_count": {
- "type": "integer"
- },
- "profile_image_90": {
- "type": "keyword"
- },
- "reactions_count": {
- "type": "integer"
- },
- "roles": {
- "type": "keyword"
- },
- "search_fields": {
- "type": "text"
- },
- "username": {
- "type": "keyword",
- "copy_to": "search_fields"
- },
- "profile_fields": {
- "type": "nested",
- "properties": {
- "name": {
- "type": "keyword"
- },
- "value": {
- "type": "keyword"
- }
- }
- },
- "custom_profile_fields": {
- "type": "nested",
- "properties": {
- "name": {
- "type": "keyword"
- },
- "value": {
- "type": "keyword"
- }
- }
- }
- }
-}
diff --git a/config/initializers/cypress_rails.rb b/config/initializers/cypress_rails.rb
index 14f2b96a7..857fb06ea 100644
--- a/config/initializers/cypress_rails.rb
+++ b/config/initializers/cypress_rails.rb
@@ -22,7 +22,6 @@ end
CypressRails.hooks.before_server_stop do
# Called once, at_exit
puts "Cleaning up and stopping server for end to end tests."
- Rake::Task["search:destroy"].invoke
Rake::Task["db:truncate_all"].invoke
puts "The end to end test server shutdown gracefully."
end
diff --git a/config/routes.rb b/config/routes.rb
index 6834c380b..5095553f4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -89,7 +89,6 @@ Rails.application.routes.draw do
resources :health_checks, only: [] do
collection do
get :app
- get :search
get :database
get :cache
end
@@ -212,7 +211,6 @@ Rails.application.routes.draw do
get "/search/tags", to: "search#tags"
get "/search/chat_channels", to: "search#chat_channels"
get "/search/listings", to: "search#listings"
- get "/search/users", to: "search#users"
get "/search/usernames", to: "search#usernames"
get "/search/feed_content", to: "search#feed_content"
get "/search/reactions", to: "search#reactions"
diff --git a/container-compose.yml b/container-compose.yml
index f21c99aca..00d9d608f 100644
--- a/container-compose.yml
+++ b/container-compose.yml
@@ -8,13 +8,11 @@ services:
depends_on:
- bundle
- db
- - elasticsearch
- redis
- yarn
environment:
RAILS_ENV: development
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
REDIS_SESSIONS_URL: redis://redis:6379
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
@@ -24,7 +22,7 @@ services:
APP_DOMAIN: rails
volumes:
- .:/opt/apps/forem:z
- entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "http://elasticsearch:9200", "-wait", "tcp://redis:6379", "-wait", "file:///opt/apps/forem/vendor/bundle/.bundle_finished", "-timeout", "2700s"]
+ entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "tcp://redis:6379", "-wait", "file:///opt/apps/forem/vendor/bundle/.bundle_finished", "-timeout", "2700s"]
command: [ "bash", "-c", "./scripts/entrypoint.sh bootstrap && bundle exec rails server -b 0.0.0.0 -p 3000"]
bundle:
@@ -36,7 +34,6 @@ services:
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
volumes:
- .:/opt/apps/forem:z
command: ["./scripts/bundle.sh"]
@@ -50,7 +47,6 @@ services:
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
volumes:
- .:/opt/apps/forem:z
command: [ "bash", "-c", "yarn install --dev"]
@@ -67,7 +63,6 @@ services:
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
volumes:
- .:/opt/apps/forem:z
entrypoint: ["dockerize", "-wait", "file:///opt/apps/forem/node_modules/.bin/webpack-dev-server", "-timeout", "300s"]
@@ -80,17 +75,15 @@ services:
- rails
- redis
- db
- - elasticsearch
environment:
RAILS_ENV: development
REDIS_SESSIONS_URL: redis://redis:6379
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
volumes:
- .:/opt/apps/forem:z
- entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "http://elasticsearch:9200", "-wait", "tcp://redis:6379", "-wait", "http://rails:3000", "-timeout", "300s"]
+ entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "tcp://redis:6379", "-wait", "http://rails:3000", "-timeout", "300s"]
command: ["bundle", "exec", "rake","db:seed"]
sidekiq:
@@ -100,17 +93,15 @@ services:
- rails
- redis
- db
- - elasticsearch
environment:
RAILS_ENV: development
REDIS_SESSIONS_URL: redis://redis:6379
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
volumes:
- .:/opt/apps/forem:z
- entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "http://elasticsearch:9200", "-wait", "tcp://redis:6379", "-wait", "http://rails:3000", "-timeout", "300s"]
+ entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "tcp://redis:6379", "-wait", "http://rails:3000", "-timeout", "300s"]
command: ["bundle", "exec", "sidekiq","-c","2"]
db:
@@ -131,23 +122,5 @@ services:
ports:
- "6379:6379"
- elasticsearch:
- image: docker.elastic.co/elasticsearch/elasticsearch:7.5.2
- container_name: forem_elasticsearch
- environment:
- - cluster.name=forem
- - bootstrap.memory_lock=true
- - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- - "discovery.type=single-node"
- - xpack.security.enabled=false
- - xpack.monitoring.enabled=false
- - xpack.graph.enabled=false
- - xpack.watcher.enabled=false
- ports:
- - "9200:9200"
- # volumes:
- # - es_data:/usr/share/elasticsearch/data:Z
-
volumes:
db_data:
- # es_data:
diff --git a/docker-compose.yml b/docker-compose.yml
index 9fd4a60c9..6f9ecdc1d 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -9,13 +9,11 @@ services:
depends_on:
- bundle
- db
- - elasticsearch
- redis
- yarn
environment:
RAILS_ENV: development
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
REDIS_SESSIONS_URL: redis://redis:6379
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
@@ -25,7 +23,7 @@ services:
APP_DOMAIN: rails
volumes:
- .:/opt/apps/forem:delegated
- entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "http://elasticsearch:9200", "-wait", "tcp://redis:6379", "-wait", "file:///opt/apps/forem/vendor/bundle/.bundle_finished", "-timeout", "2700s", "-wait-retry-interval", "10s"]
+ entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "tcp://redis:6379", "-wait", "file:///opt/apps/forem/vendor/bundle/.bundle_finished", "-timeout", "2700s", "-wait-retry-interval", "10s"]
command: [ "bash", "-c", "./scripts/entrypoint.sh bootstrap && bundle exec rails server -b 0.0.0.0 -p 3000"]
bundle:
@@ -38,7 +36,6 @@ services:
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
volumes:
- .:/opt/apps/forem:delegated
command: ["./scripts/bundle.sh"]
@@ -53,7 +50,6 @@ services:
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
volumes:
- .:/opt/apps/forem:delegated
command: yarn install --dev
@@ -72,7 +68,6 @@ services:
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
volumes:
- .:/opt/apps/forem:delegated
entrypoint: ["dockerize", "-wait", "file:///opt/apps/forem/node_modules/.bin/webpack-dev-server", "-wait", "file:///opt/apps/forem/vendor/bundle/.bundle_finished", "-timeout", "2700s", "-wait-retry-interval", "10s"]
@@ -86,17 +81,15 @@ services:
- rails
- redis
- db
- - elasticsearch
environment:
RAILS_ENV: development
REDIS_SESSIONS_URL: redis://redis:6379
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
volumes:
- .:/opt/apps/forem:delegated
- entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "http://elasticsearch:9200", "-wait", "tcp://redis:6379", "-wait", "http://rails:3000", "-timeout", "2700s", "-wait-retry-interval", "20s"]
+ entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "tcp://redis:6379", "-wait", "http://rails:3000", "-timeout", "2700s", "-wait-retry-interval", "20s"]
command: ["bundle", "exec", "rake","db:seed"]
sidekiq:
@@ -107,17 +100,15 @@ services:
- rails
- redis
- db
- - elasticsearch
environment:
RAILS_ENV: development
REDIS_SESSIONS_URL: redis://redis:6379
REDIS_SIDEKIQ_URL: redis://redis:6379
REDIS_URL: redis://redis:6379
DATABASE_URL: postgresql://forem:forem@db:5432/PracticalDeveloper_development
- ELASTICSEARCH_URL: http://elasticsearch:9200
volumes:
- .:/opt/apps/forem:delegated
- entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "http://elasticsearch:9200", "-wait", "tcp://redis:6379", "-wait", "http://rails:3000", "-timeout", "2700s", "-wait-retry-interval", "20s"]
+ entrypoint: ["dockerize", "-wait", "tcp://db:5432", "-wait", "tcp://redis:6379", "-wait", "http://rails:3000", "-timeout", "2700s", "-wait-retry-interval", "20s"]
command: ["bundle", "exec", "sidekiq","-c","2"]
db:
@@ -138,28 +129,5 @@ services:
ports:
- "6379:6379"
- elasticsearch:
- image: docker.elastic.co/elasticsearch/elasticsearch:7.5.2
- container_name: forem_elasticsearch
- environment:
- - cluster.name=forem
- - bootstrap.memory_lock=true
- - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- - "discovery.type=single-node"
- - xpack.security.enabled=false
- - xpack.monitoring.enabled=false
- - xpack.graph.enabled=false
- - xpack.watcher.enabled=false
- volumes:
- - es_data:/usr/share/elasticsearch/data:delegated
- ports:
- - "9200:9200"
- ulimits:
- memlock:
- soft: -1
- hard: -1
-
volumes:
db_data:
- es_data:
-
diff --git a/docs/admin/admin-search.md b/docs/admin/admin-search.md
index 2beff7180..3d671f795 100644
--- a/docs/admin/admin-search.md
+++ b/docs/admin/admin-search.md
@@ -16,9 +16,9 @@ The view responsible for managing user reports can be found at
action of the [`admin/feedback_messages_controller`][feedback_messages].
For Forem, Ransack is being used exclusively in admin, for search problems in
-other parts of the app we use [Elasticsearch][elasticsearch].
+other parts of the app we use [PostgreSQL Full Text Search][postgres_fts].
[feedback_messages]:
https://github.com/forem/forem/blob/4e41e4a2ac893fa2a6c36990cfe475858ffb086a/app/controllers/admin/feedback_messages_controller.rb#L4
[ransack]: https://github.com/activerecord-hackery/ransack
-[elasticsearch]: /backend/elasticsearch
+[postgres_fts]: https://www.postgresql.org/docs/11/textsearch.html
diff --git a/docs/backend/data-update-scripts.md b/docs/backend/data-update-scripts.md
index 8e78d5f8f..7143f8676 100644
--- a/docs/backend/data-update-scripts.md
+++ b/docs/backend/data-update-scripts.md
@@ -8,9 +8,7 @@ Data Update Scripts were introduced in
[this PR](https://github.com/forem/forem/pull/6025) and allow us to run any data
updates we might need. For example, if we added a column to the database and
then wanted to backfill that column with data, rather than going and manually
-doing it in a console, we would use a DataUpdateScript. Another example might be
-adding a new attribute to Elasticsearch. We could then use a DataUpdateScript to
-reindex all of our models.
+doing it in a console, we would use a DataUpdateScript.
## How it works
diff --git a/docs/backend/elasticsearch.md b/docs/backend/elasticsearch.md
deleted file mode 100644
index 6a68c6735..000000000
--- a/docs/backend/elasticsearch.md
+++ /dev/null
@@ -1,92 +0,0 @@
----
-title: Elasticsearch
----
-
-# What is [Elasticsearch](https://www.elastic.co/what-is/elasticsearch)?
-
-> Elasticsearch is a distributed, open-source search and analytics engine for
-> all types of data, including textual, numerical, geospatial, structured, and
-> unstructured. Elasticsearch is built on Apache Lucene and was first released
-> in 2010 by Elastic.
-
-# How Forem uses Elasticsearch
-
-### Searchable Models
-
-At Forem we use Elasticsearch for all of our user-facing searching needs. Models
-that are searched using Elasticsearch are:
-
-- Tags
-- Listings
-- Chat Channels
-- Users
-- Podcast Episodes
-- Comments
-- Articles
-
-### Index Setup
-
-The above models are organized in Elasticsearch in different
-[indexes](https://www.elastic.co/blog/what-is-an-elasticsearch-index) to make
-searching more accurate and performant. The index breakdown is:
-
-- Tags index -> Tags
-- Listings index -> Listings
-- Chat Channel Membership index -> Chat Channels
-- User's index -> Users
-- Feed Content index -> Podcast Episodes, Comments, and Articles
-
-You will notice that Podcast Episodes, Comments, and Articles all share the same
-index. This allows us to search and aggregate across all of these documents at
-the same time. These documents also share a lot of similar fields so putting
-them in the same index made sense. In the future, depending on our search needs
-this index structure might change.
-
-Each index that is listed above has a corresponding
-[mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html)
-that defines what fields can and cannot be indexed to it. These mappings are
-similar to a db schema. In our case, all of our index mappings are defined as
-[`strict`](https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic.html#dynamic)
-which means if we try to index a field that is not defined it will throw an
-error. Mappings for each index can be found in
-`app/config/elasticsearch/mappings`.
-
-### Indexing documents into Elasticsearch
-
-In order to index the data from Postgres into Elasticsearch, we rely on
-callbacks in our ActiveRecord models. Whenever a model is created or updated we
-use an `after_commit` callback to enqueue a `Search::IndexWorker` which handles
-indexing the document into Elasticsearch. In order to translate our ActiveRecord
-data to Elasticsearch we use serializers. Each model has its own serializer
-which can be found in `app/serializers/search`
-
-### Searching Elasticsearch
-
-Once the documents are in Elasticsearch then we can search for them. This is
-handled by code in our `app/services/search` directory. Here you will see a
-collection of classes used to help us index and search documents in
-Elasticsearch. The nested `query_builders` directory contains all the logic we
-need to help us build complex search queries to send to Elasticsearch.
-
-# Working With Elasticsearch
-
-## How to add a new field to Elasticsearch
-
-When adding a new field to Elasticsearch here are the steps you have to follow:
-
-1. Add field to mapping by editing the appropriate JSON file in
- `app/config/elasticsearch/mappings`. If you plan to test locally you will
- need to run `bin/setup` to update your local Elasticsearch mappings.
-2. Add field to serializer for model located in `app/serializers/search`.
-3. If the new field needs to be backfilled write a DataUpdateScript to reindex
- all affected models so the field is available and populated in Elasticsearch
-4. DEPLOY - Before you can start using a new field you need to ensure that it is
- added to Elasticsearch and populated properly. The worker that runs the
- DataUpdateScript will run 5 min after a deploy completes. This means you have
- to deploy the code for adding the field separate from the code that will use
- it.
-5. Add code to search for your new field. You likely will need to update the
- allowed params in the searches controller as well as the pertinent query
- builder.
-6. DEPLOY new search code
-7. DONE!
diff --git a/docs/backend/readme.md b/docs/backend/readme.md
index a1b917644..553924150 100644
--- a/docs/backend/readme.md
+++ b/docs/backend/readme.md
@@ -10,7 +10,6 @@ items:
- authorization.md
- configuration.md
- data-update-scripts.md
- - elasticsearch.md
- emails.md
- fastly.md
- internationalization.md
diff --git a/docs/installation/containers.md b/docs/installation/containers.md
index b784e479d..2d4891b16 100644
--- a/docs/installation/containers.md
+++ b/docs/installation/containers.md
@@ -108,12 +108,6 @@ The script executes the following steps:
### Docker on Mac
-- Should you experience problems with the Elasticsearch container, try to
- increase the memory and/or swap allocation for Docker. On macOS this can be
- done via the GUI:
-
- 
-
- In case `rails server` starts with the following message:
```shell
diff --git a/docs/installation/linux.md b/docs/installation/linux.md
index d20f7fb69..aeaf0ae64 100644
--- a/docs/installation/linux.md
+++ b/docs/installation/linux.md
@@ -66,21 +66,6 @@ We recommend following Digital Ocean's extensive guides
[How to Install and Secure Redis](https://www.digitalocean.com/community/tutorial_collections/how-to-install-and-secure-redis)
to setup Redis.
-### Elasticsearch
-
-Forem requires a version of Elasticsearch between 7.1 and 7.5. Version 7.6 is
-not supported. We recommend version 7.5.2.
-
-We recommend following
-[Elasticsearch's guide for installing on Linux](https://www.elastic.co/guide/en/elasticsearch/reference/7.5/targz.html#install-linux).
-
-Elasticsearch is also available as as
-[Debian package](https://www.elastic.co/guide/en/elasticsearch/reference/7.5/deb.html)
-or a
-[RPM package](https://www.elastic.co/guide/en/elasticsearch/reference/7.5/rpm.html).
-
-NOTE: Make sure to download **the OSS version**, `elasticsearch-oss`.
-
## Installing Forem
1. Fork Forem's repository, e.g.
diff --git a/docs/installation/mac.md b/docs/installation/mac.md
index 19f0ddb33..471a38a27 100644
--- a/docs/installation/mac.md
+++ b/docs/installation/mac.md
@@ -8,18 +8,25 @@ title: macOS
### Ruby
-1. **Note:** MacOS ships with a version of Ruby, needed for various operating systems.
- To avoid causing an issue with your operating system you should use a version manager for Ruby.
+1. **Note:** MacOS ships with a version of Ruby, needed for various operating
+ systems. To avoid causing an issue with your operating system you should use
+ a version manager for Ruby.
+
+ If you don't already have a Ruby version manager, we highly recommend
+ [rbenv](https://github.com/rbenv/rbenv). This will allow you to have
+ different versions running on a per project basis. The MacOS system version
+ of Ruby will stay intact while giving you the ability to use the version
+ needed for this Forem project. Please follow their
+ [installation guide](https://github.com/rbenv/rbenv#installation).
- If you don't already have a Ruby version manager, we highly recommend [rbenv](https://github.com/rbenv/rbenv). This will allow you to have different versions running on a per project basis. The MacOS system version of Ruby will stay intact while giving you the ability to use the version needed for this Forem project.
-Please follow their [installation guide](https://github.com/rbenv/rbenv#installation).
2. With the Ruby version manager, install the Ruby version listed on our badge.
(i.e. with rbenv: `rbenv install $(cat .ruby-version)`)
-
- **Note:** The repository must be forked and cloned before running the `rbenv install $(cat .ruby-version)` command.
-
+
+ **Note:** The repository must be forked and cloned before running the
+ `rbenv install $(cat .ruby-version)` command.
### Yarn
+
Please refer to their [installation guide](https://yarnpkg.com/en/docs/install).
### PostgreSQL
@@ -63,146 +70,6 @@ You can test if it's up and running by issuing the following command:
redis-cli ping
```
-### Elasticsearch
-
-Forem requires Elasticsearch 7.x to run. We recommend version 7.5.2.
-
-You have the option of installing Elasticsearch with Homebrew or through an
-archive. We **recommend** installing from archive on Mac.
-
-### Installing Elasticsearch from the archive
-
-We recommend that you **do not** install Elasticsearch in the app directory.
-Instead, we recommend installing it in your home directory (for example,
-`cd $HOME`). (This also ensures that we don't accidentally commit Elasticsearch
-code to the project's repository!)
-
-The following directions were
-[taken from the Elasticsearch docs themselves](https://www.elastic.co/guide/en/elasticsearch/reference/7.5/targz.html#install-macos),
-so check those out if you run into any issues or want further information. Make
-sure to download **the OSS version** of Elasticsearch, `elasticsearch-oss`.
-
-Please note that you will need `wget` in order to proceed with this installation
-(`brew install wget`).
-
-```shell
-wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-7.5.2-darwin-x86_64.tar.gz
-wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-7.5.2-darwin-x86_64.tar.gz.sha512
-shasum -a 512 -c elasticsearch-oss-7.5.2-darwin-x86_64.tar.gz.sha512
-tar -xzf elasticsearch-oss-7.5.2-darwin-x86_64.tar.gz
-```
-
-To start elasticsearch, make sure you are in the correct directory:
-
-```shell
-cd elasticsearch-7.5.2
-```
-
-You can then start it by running:
-
-```shell
-./bin/elasticsearch
-```
-
-To start elasticsearch as a daemonized process:
-
-```shell
-./bin/elasticsearch -d
-```
-
-### Installing Elasticsearch with Homebrew
-
-To install Elasticsearch with Homebrew we will use the following commands to:
-
-- tap the Elastic Homebrew repository
-- install the latest OSS distribution
-- pin the latest OSS distribution.
-
-```shell
-brew tap elastic/tap
-brew install elastic/tap/elasticsearch-oss
-brew pin elasticsearch-oss
-```
-
-After installation you can manually test if the Elasticsearch server starts by
-issuing the command `elasticsearch` in the shell. You can then start the server
-as a service with `brew services start elasticsearch-oss`.
-
-You can find further info on your local Elasticsearch installation by typing
-`brew info elastic/tap/elasticsearch-oss`.
-
-#### Troubleshooting startup issues
-
-Two possible startup issues you might encounter:
-
-- `java.nio.file.FileSystemLoopException`:
-
-```text
-Exception in thread "main" org.elasticsearch.bootstrap.BootstrapException: java.nio.file.FileSystemLoopException: /usr/local/etc/elasticsearch/elasticsearch
-Likely root cause: java.nio.file.FileSystemLoopException: /usr/local/etc/elasticsearch/elasticsearch
-```
-
-This happens because the installation of Elasticsearch might have a recursive
-link in the configuration directory causing the infinite loop:
-
-```shell
-> ll /usr/local/etc/elasticsearch
-elasticsearch -> /usr/local/etc/elasticsearch
-```
-
-By manually removing the link with
-`rm -i /usr/local/etc/elasticsearch/elasticsearch` the issue should be fixed.
-
-- `java.lang.IllegalStateException`:
-
-```text
-java.lang.IllegalStateException: Could not load plugin descriptor for plugin directory [plugins]
-Likely root cause: java.nio.file.NoSuchFileException: /usr/local/Cellar/elasticsearch-oss/7.6.0/libexec/plugins/plugins/plugin-descriptor.properties
-```
-
-This happens for a similar reason as the previous error, the installation might
-create a recursive link in the plugins directory.
-
-```shell
-> ll /usr/local/var/elasticsearch/plugins
-plugins -> /usr/local/var/elasticsearch/plugins
-```
-
-By manually removing the link with
-`rm -i /usr/local/var/elasticsearch/plugins/plugins` the issue should be fixed.
-
-### Testing if Elasticsearch is running
-
-Once installed and started you can test if it's up and running correctly by
-issuing the following command:
-
-```shell
-curl http://localhost:9200
-```
-
-You should receive in response a JSON document containing some information about
-your local Elasticsearch installation, for example:
-
-```json
-{
- "name": "hostname",
- "cluster_name": "elasticsearch_...",
- "cluster_uuid": "...",
- "version": {
- "number": "7.5.2",
- "build_flavor": "oss",
- "build_type": "tar",
- "build_hash": "8bec50e1e0ad29dad5653712cf3bb580cd1afcdf",
- "build_date": "2020-01-15T12:11:52.313576Z",
- "build_snapshot": false,
- "lucene_version": "8.3.0",
- "minimum_wire_compatibility_version": "6.8.0",
- "minimum_index_compatibility_version": "6.0.0-beta1"
- },
- "tagline": "You Know, for Search"
-}
-```
-
## Installing Forem
1. Fork Forem's repository, e.g.
@@ -240,8 +107,7 @@ your local Elasticsearch installation, for example:
### Possible error messages
-**Error:**
-`rbenv install hangs at ruby-build: using readline from homebrew`
+**Error:** `rbenv install hangs at ruby-build: using readline from homebrew`
**_Solution:_**
[Stackoverflow answer](https://stackoverflow.com/questions/63599818/rbenv-install-hangs-at-ruby-build-using-readline-from-homebrew)
diff --git a/docs/installation/windows.md b/docs/installation/windows.md
index 686675c7d..e849d83f9 100644
--- a/docs/installation/windows.md
+++ b/docs/installation/windows.md
@@ -176,60 +176,6 @@ We recommend to follow
[this guide](https://redislabs.com/blog/redis-on-windows-10/) to run Redis under
WSL.
-### Elasticsearch
-
-Forem requires a version of Elasticsearch between 7.1 and 7.5. Version 7.6 is
-not supported. We recommend version 7.5.2.
-
-We recommend that you **do not** install Elasticsearch in the app directory.
-Instead, we recommend installing it in your home directory (for example,
-`cd $HOME`). (This also ensures that we don't accidentally commit Elasticsearch
-code to the project's repository!)
-
-The following directions were taken from
-[the Elasticsearch docs](https://www.elastic.co/guide/en/elasticsearch/reference/7.5/targz.html#install-linux),
-check them out to learn more about the installation process and troubleshooting
-issues. Make sure to refer to **the OSS version**, `elasticsearch-oss` while
-going through the Elasticsearch docs.
-
-To install Elasticsearch perform the following steps:
-
-1. Execute the following commands:
-
- ```shell
- cd
- wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-7.5.2-linux-x86_64.tar.gz
- wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-7.5.2-linux-x86_64.tar.gz.sha512
- shasum -a 512 -c elasticsearch-oss-7.5.2-linux-x86_64.tar.gz.sha512
- tar -xzf elasticsearch-oss-7.5.2-linux-x86_64.tar.gz
- ```
-
-2. Next, switch to the correct directory with:
-
- ```shell
- cd elasticsearch-7.5.2/
- ```
-
-3. To start Elasticsearch, run the following command:
-
- ```shell
- ./bin/elasticsearch
- ```
-
- or, start it as a daemonized process with:
-
- ```shell
- ./bin/elasticsearch -d
- ```
-
-4. Once Elasticsearch is running,
- [verify Elasticsearch's installation](https://www.elastic.co/guide/en/elasticsearch/reference/7.5/targz.html#_checking_that_elasticsearch_is_running)
- by executing the `cURL` command as follows:
-
- ```shell
- curl -X GET "localhost:9200/?pretty"
- ```
-
## Installing Forem
1. Fork Forem's repository, eg.
@@ -277,8 +223,8 @@ To install Elasticsearch perform the following steps:
- You do not need "real" keys for basic development. Some features require
certain keys, so you may be able to add them as you go.
-1. After ensuring that Elasticsearch, the PostgreSQL server, and the Redis
- server are running, run `bin/setup`.
+1. After ensuring that the PostgreSQL server and the Redis server are running,
+ run `bin/setup`.
> The `bin/setup` script is responsible for installing a varienty of
> dependencies. One can find it inside the `bin` folder by the name of
@@ -290,8 +236,8 @@ To install Elasticsearch perform the following steps:
> - It then installs JavaScript dependencies using the script in `bin/yarn`
> file. These dependencies are located in `package.json` in the root of the
> repository.
- > - Next, it uses various Rake files located inside the `lib` folder to setup
- > ElasticSearch environment, PostgreSQL database creation and updation.
+ > - Next, it uses various Rake files located inside the `lib` folder for the
+ > PostgreSQL database creation and updation.
> - Finally it cleans up all the log files and restarts the Puma server.
### Possible error messages
diff --git a/docs/maintainers/deploying.md b/docs/maintainers/deploying.md
index ad0449d65..35e50e207 100644
--- a/docs/maintainers/deploying.md
+++ b/docs/maintainers/deploying.md
@@ -57,10 +57,10 @@ stage will do nothing. If the branch has been merged into main, then this stage
will kick off a deploy. The deploy will run in its own job deploying our
application to Heroku.
-Prior to deploying the code, Heroku will run database migrations, Elasticsearch
-updates, and do some final checks (more information on that below) to make sure
-everything is working as expected. If these all succeed, then the deploy
-completes and our team is notified.
+Prior to deploying the code, Heroku will run database migrations and do some
+final checks (more information on that below) to make sure everything is working
+as expected. If these all succeed, then the deploy completes and our team is
+notified.
## Deploying to Heroku
@@ -84,13 +84,8 @@ directory. During this release step we do a few checks.
successfully before the code that uses it goes live.
3. We run any data update scripts that need to be run. A data update script is
one that allows us to update data in the background separate from a
- migration. For example, if we add a new field to Elasticsearch and need to
- reindex all of our documents we would use a data update script.
-4. We update Elasticsearch. Elasticsearch contains indexes which have mappings.
- Mappings are similar to database schema. The same way we run a migration to
- update our database we have to run a setup task to update any Elasticsearch
- mappings.
-5. Following updating all of our datastores we use the Rails runner to output a
+ migration.
+4. Following updating all of our datastores we use the Rails runner to output a
simple string. Executing a Rails runner command ensures that we can boot up
the entire app successfully before it is deployed. We deploy asynchronously,
so the website is running the new code a few minutes after deploy. A new
diff --git a/docs/technical-overview/architecture.md b/docs/technical-overview/architecture.md
index c6ed9a2fa..6c0bee3cf 100644
--- a/docs/technical-overview/architecture.md
+++ b/docs/technical-overview/architecture.md
@@ -72,10 +72,10 @@ Rails][fastly_rails] docs, but we bust specific URLs via `EdgeCache::Bust#call`.
The home feed is based on a combination of recent collective posts that are
cached and delivered the same to everyone in the HTML, and additional articles
-fetched from an Elasticsearch index after page load. To determine which posts a
-user sees, they are ranked based on the user's followed tags, followed users,
-and relative weights for each tag. Additional fetched articles also follow this
-general pattern.
+fetched from a PostgreSQL Full Text Search index after page load. To determine
+which posts a user sees, they are ranked based on the user's followed tags,
+followed users, and relative weights for each tag. Additional fetched articles
+also follow this general pattern.
Currently, the top post on the home feed, which must have a cover image, is
shared among all users.
diff --git a/docs/technical-overview/stack.md b/docs/technical-overview/stack.md
index 20b4bf877..78a0a406d 100644
--- a/docs/technical-overview/stack.md
+++ b/docs/technical-overview/stack.md
@@ -7,7 +7,8 @@ title: Stack
For the Forem tech stack we use:
- [_Puma_](https://github.com/puma/puma) as the web server
-- [_PostgreSQL_](https://www.postgresql.org/) as the primary database
+- [_PostgreSQL_](https://www.postgresql.org/) as the primary database and for
+ Full Text Search
- [_Redis_](https://redis.io/) to store cached data
- [_Fastly_](https://www.fastly.com/) for
[edge caching](https://dev.to/ben/making-devto-insanely-fast)
@@ -18,7 +19,6 @@ For the Forem tech stack we use:
- [_Sidekiq_](https://github.com/mperham/sidekiq) and
[_Active Job_](https://guides.rubyonrails.org/active_job_basics.html) for
background workers
-- [_Elasticsearch_](https://www.elastic.co/elasticsearch/) for in app searching
- [Ransack](https://github.com/activerecord-hackery/ransack) for internal search
- [_Redcarpet_](https://github.com/vmg/redcarpet) and
[_Rouge_](https://github.com/jneen/rouge) to parse Markdown
diff --git a/docs/tests/readme.md b/docs/tests/readme.md
index b4b59aad2..efae0084e 100644
--- a/docs/tests/readme.md
+++ b/docs/tests/readme.md
@@ -69,8 +69,3 @@ retry the individual job that failed rather than the entire suite in order to
save some time. When you retry the individual job, make sure to also retry the
Deploy job. Even though you may not be deploying that job must complete for the
entire build to pass.
-
-Please note that you will need to have Elasticsearch installed and running for
-certain tests in our test suite. You can find instructions on how to install and
-run Elasticsearch specific to your environment in the
-[Installation Guide](/installation).
diff --git a/docs/tests/test-flags.md b/docs/tests/test-flags.md
index 93f1f6774..6342ee4f2 100644
--- a/docs/tests/test-flags.md
+++ b/docs/tests/test-flags.md
@@ -11,59 +11,15 @@ test example.
Some flags that we use are:
- `js: true`
-- `elasticsearch_reset: true`
-- `elasticsearch: `
-- `stub_elasticsearch: true`
- `throttle: true`
- `type: `
-### Elasticsearch Flags
-
-Two Elasticsearch flags that can be used when dealing with specs that will be
-hitting Elasticsearch. When running a spec that is going to interact with
-Elasticsearch, you want Elasticsearch to be clean like your database. Since we
-don't have a "database cleaner" for Elasticsearch, we have to do it manually.
-There are two ways to do this:
-
-1. `elasticsearch: reset` - This will trigger a complete tear down and rebuild
- of Elasticsearch via a block. This takes time so it's not something you want
- to be doing unless you absolutely have to.
-
-```ruby
- config.around(:each, elasticsearch_reset: true) do |example|
- Search::Cluster.recreate_indexes
- example.run
- Search::Cluster.recreate_indexes
- end
-```
-
-2. `elasticsearch: ` - This will clear the data for the given
- search class index. For example, if you passed "User" as your search class
- name it would clear out the user index data using code from this block.
-
-```ruby
- config.around(:each, :elasticsearch) do |ex|
- klasses = Array.wrap(ex.metadata[:elasticsearch]).map do |search_class|
- Search.const_get(search_class)
- end
- klasses.each { |klass| clear_elasticsearch_data(klass) }
- ex.run
- end
-```
-
### `js: true` Flag
`js: true` indicates that we want the JavaScript on the page to be executed when
the page is rendered, and a headless chrome instance will be initialized to do
so (instead of the default
-[rack_test](https://github.com/teamcapybara/capybara#racktest) driver). One side
-effect of running our JavaScript in our specs is that a lot of pages will hit
-Elasticsearch. Since we don't clean out Elasticsearch between every single spec
-(because it is very costly) this can lead to unexpected data being loaded for a
-spec. To prevent this from happening, we can use the `:stub_elasticsearch` flag.
-The `:stub_elasticsearch` flag will stub all index and search requests made to
-Elasticsearch and return an empty response. This will ensure that no unwanted
-data shows up on your spec's page.
+[rack_test](https://github.com/teamcapybara/capybara#racktest) driver).
If you are debugging a `js: true` spec and want to see the browser, you can set
`HEADLESS=false` before running a spec:
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index 60c1700cb..cf550dbfe 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -33,66 +33,6 @@ The first command creates the user **ec2-user** and the second one creates the
database for this user because every user needs its database. Even if the first
command fails, run the second command to create the missing database.
-## Elasticsearch
-
-### Index read-only error
-
-If you encounter an error similar to the following:
-
-```shell
-{"error":{"root_cause":[{"type":"cluster_block_exception","reason":"index [tags_development] blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];"}],"type":"cluster_block_exception","reason":"index [tags_development] blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];"},"status":403}
-```
-
-it means that Elasticsearch went into read only mode because its disk allocator
-noticed how the disk drive is nearly full:
-
-> Elasticsearch enforces a read-only index block
-> (`index.blocks.read_only_allow_delete`) on every index that has one or more
-> shards allocated on the node that has at least one disk exceeding the flood
-> stage.
-
-This is an indication that you might not have enough space for ES to work
-correctly.
-
-If you want to disable the threshold check on your local machine you can open a
-Rails console (with `rails console`) and issue the following command:
-
-```ruby
-Search::Client.cluster.put_settings(body: {
- persistent: {
- "cluster.routing.allocation.disk.threshold_enabled" => false,
- }
-})
-```
-
-Alternatively you can use the following command in a terminal session:
-
-```shell
-curl -XPUT -H "Content-Type: application/json" http://localhost:9200/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}'
-```
-
-To disable the "read only" mode to allow operations on the Elasticsearch indexes
-you can issue the following command, similary in the Rails console:
-
-```ruby
-Search::Client.indices.get(index: "*").keys.each do |index_name|
- Search::Client.indices.put_settings(
- index: index_name,
- body: { "index.blocks.read_only_allow_delete" => nil }
- )
-end
-```
-
-Or alternatively:
-
-```shell
-curl -XPUT -H "Content-Type: application/json" http://localhost:9200/_cluster/settings -d '{ "transient": { "cluster.routing.allocation.disk.threshold_enabled": false } }'
-```
-
-If instead you want to tune the Elasticsearch disk allocator's settings, please
-refer to
-[Disk-based shard allocation](https://www.elastic.co/guide/en/elasticsearch/reference/current/disk-allocator.html#disk-allocator).
-
## CORS
If you are experiencing CORS issues locally or need to display more information
diff --git a/lib/data_update_scripts/20200218195023_index_chat_channel_memberships_to_elasticsearch.rb b/lib/data_update_scripts/20200218195023_index_chat_channel_memberships_to_elasticsearch.rb
index 73d5d464e..35fa1babb 100644
--- a/lib/data_update_scripts/20200218195023_index_chat_channel_memberships_to_elasticsearch.rb
+++ b/lib/data_update_scripts/20200218195023_index_chat_channel_memberships_to_elasticsearch.rb
@@ -1,7 +1,7 @@
module DataUpdateScripts
class IndexChatChannelMembershipsToElasticsearch
def run
- ChatChannelMembership.find_each(&:index_to_elasticsearch_inline)
+ # ChatChannelMembership.find_each(&:index_to_elasticsearch_inline)
end
end
end
diff --git a/lib/data_update_scripts/20200410152018_resync_elasticsearch_documents.rb b/lib/data_update_scripts/20200410152018_resync_elasticsearch_documents.rb
index 2adea1ffc..dd1c1afae 100644
--- a/lib/data_update_scripts/20200410152018_resync_elasticsearch_documents.rb
+++ b/lib/data_update_scripts/20200410152018_resync_elasticsearch_documents.rb
@@ -2,13 +2,13 @@ module DataUpdateScripts
class ResyncElasticsearchDocuments
def run
# Previous bug: Not getting removed properly
- sync_docs(Article.ids, "Article")
- sync_docs(Comment.ids, "Comment")
- sync_docs(User.ids, "User")
+ # sync_docs(Article.ids, "Article")
+ # sync_docs(Comment.ids, "Comment")
+ # sync_docs(User.ids, "User")
# Previous bug: Not getting indexed on creation properly
- index_docs(PodcastEpisode.ids, "PodcastEpisode")
- index_docs(Tag.ids, "Tag")
+ # index_docs(PodcastEpisode.ids, "PodcastEpisode")
+ # index_docs(Tag.ids, "Tag")
end
private
diff --git a/lib/data_update_scripts/20200519142908_re_index_feed_content_and_users_to_elasticsearch.rb b/lib/data_update_scripts/20200519142908_re_index_feed_content_and_users_to_elasticsearch.rb
index 2131cc3cf..bb54a90a5 100644
--- a/lib/data_update_scripts/20200519142908_re_index_feed_content_and_users_to_elasticsearch.rb
+++ b/lib/data_update_scripts/20200519142908_re_index_feed_content_and_users_to_elasticsearch.rb
@@ -1,21 +1,21 @@
module DataUpdateScripts
class ReIndexFeedContentAndUsersToElasticsearch
def run
- Article.select(:id).in_batches(of: 100) do |batch|
- Search::BulkIndexWorker.set(queue: :default).perform_async(
- "Article", batch.ids
- )
- end
- Comment.select(:id).in_batches(of: 100) do |batch|
- Search::BulkIndexWorker.set(queue: :default).perform_async(
- "Comment", batch.ids
- )
- end
- PodcastEpisode.select(:id).in_batches(of: 100) do |batch|
- Search::BulkIndexWorker.set(queue: :default).perform_async(
- "PodcastEpisode", batch.ids
- )
- end
+ # Article.select(:id).in_batches(of: 100) do |batch|
+ # Search::BulkIndexWorker.set(queue: :default).perform_async(
+ # "Article", batch.ids
+ # )
+ # end
+ # Comment.select(:id).in_batches(of: 100) do |batch|
+ # Search::BulkIndexWorker.set(queue: :default).perform_async(
+ # "Comment", batch.ids
+ # )
+ # end
+ # PodcastEpisode.select(:id).in_batches(of: 100) do |batch|
+ # Search::BulkIndexWorker.set(queue: :default).perform_async(
+ # "PodcastEpisode", batch.ids
+ # )
+ # end
# See: https://github.com/forem/forem/pull/10313#discussion_r487646864
# User.select(:id).in_batches(of: 200) do |batch|
diff --git a/lib/data_update_scripts/20200803142830_reindex_listing_search_column.rb b/lib/data_update_scripts/20200803142830_reindex_listing_search_column.rb
index 0e9a8c4dc..2ac808345 100644
--- a/lib/data_update_scripts/20200803142830_reindex_listing_search_column.rb
+++ b/lib/data_update_scripts/20200803142830_reindex_listing_search_column.rb
@@ -3,7 +3,7 @@ module DataUpdateScripts
def run
# Choose to do inline so development envs are ready immediately after
# this is run
- Listing.find_each(&:index_to_elasticsearch_inline)
+ # Listing.find_each(&:index_to_elasticsearch_inline)
end
end
end
diff --git a/lib/data_update_scripts/20200904132553_remove_draft_articles_with_duplicate_feed_source_url.rb b/lib/data_update_scripts/20200904132553_remove_draft_articles_with_duplicate_feed_source_url.rb
index 742792069..3b0ad601f 100644
--- a/lib/data_update_scripts/20200904132553_remove_draft_articles_with_duplicate_feed_source_url.rb
+++ b/lib/data_update_scripts/20200904132553_remove_draft_articles_with_duplicate_feed_source_url.rb
@@ -5,76 +5,76 @@ module DataUpdateScripts
# This statement deletes all draft articles in excess found to be duplicate over feed_source_url,
# excluding those whose body_markdown is different from the other duplicate occurrences
- result_same_body = ActiveRecord::Base.connection.execute(
- <<-SQL,
- WITH duplicates_draft_articles AS
- (SELECT id
- FROM
- (SELECT id,
- published,
- body_markdown,
- LAG(body_markdown, 1) OVER(PARTITION BY feed_source_url
- ORDER BY id ASC) AS previous_body_markdown,
- ROW_NUMBER() OVER(PARTITION BY feed_source_url
- ORDER BY id ASC) AS row_number
- FROM articles
- WHERE feed_source_url IS NOT NULL ) duplicates
- WHERE duplicates.row_number > 1
- AND published = 'f' -- drafts
- AND body_markdown = previous_body_markdown -- with the same body
- )
- DELETE
- FROM articles
- WHERE id IN (SELECT id FROM duplicates_draft_articles) RETURNING id;
- SQL
- )
-
+ # result_same_body = ActiveRecord::Base.connection.execute(
+ # <<-SQL,
+ # WITH duplicates_draft_articles AS
+ # (SELECT id
+ # FROM
+ # (SELECT id,
+ # published,
+ # body_markdown,
+ # LAG(body_markdown, 1) OVER(PARTITION BY feed_source_url
+ # ORDER BY id ASC) AS previous_body_markdown,
+ # ROW_NUMBER() OVER(PARTITION BY feed_source_url
+ # ORDER BY id ASC) AS row_number
+ # FROM articles
+ # WHERE feed_source_url IS NOT NULL ) duplicates
+ # WHERE duplicates.row_number > 1
+ # AND published = 'f' -- drafts
+ # AND body_markdown = previous_body_markdown -- with the same body
+ # )
+ # DELETE
+ # FROM articles
+ # WHERE id IN (SELECT id FROM duplicates_draft_articles) RETURNING id;
+ # SQL
+ # )
+ #
# Now that all duplicates with the same body are gone, we need to deal with duplicate feed source URLs
# with different bodies.
# We thus select the oldest for removal preserving the most recent one
- result_different_bodies = ActiveRecord::Base.connection.execute(
- <<-SQL,
- WITH duplicates_draft_articles AS
- (SELECT id
- FROM
- (SELECT id,
- published,
- body_markdown,
- LAG(body_markdown, 1) OVER(PARTITION BY feed_source_url
- ORDER BY created_at DESC) AS previous_body_markdown,
- ROW_NUMBER() OVER(PARTITION BY feed_source_url
- ORDER BY created_at DESC) AS row_number
- FROM articles
- WHERE feed_source_url IS NOT NULL ) duplicates
- WHERE duplicates.row_number > 1
- AND published = 'f' -- drafts
- AND body_markdown != previous_body_markdown -- with different bodies
- )
- DELETE
- FROM articles
- WHERE id IN (SELECT id FROM duplicates_draft_articles) RETURNING id;
- SQL
- )
-
- result_same_body_ids = result_same_body.map { |row| row["id"] }
- result_different_bodies_ids = result_different_bodies.map { |row| row["id"] }
+ # result_different_bodies = ActiveRecord::Base.connection.execute(
+ # <<-SQL,
+ # WITH duplicates_draft_articles AS
+ # (SELECT id
+ # FROM
+ # (SELECT id,
+ # published,
+ # body_markdown,
+ # LAG(body_markdown, 1) OVER(PARTITION BY feed_source_url
+ # ORDER BY created_at DESC) AS previous_body_markdown,
+ # ROW_NUMBER() OVER(PARTITION BY feed_source_url
+ # ORDER BY created_at DESC) AS row_number
+ # FROM articles
+ # WHERE feed_source_url IS NOT NULL ) duplicates
+ # WHERE duplicates.row_number > 1
+ # AND published = 'f' -- drafts
+ # AND body_markdown != previous_body_markdown -- with different bodies
+ # )
+ # DELETE
+ # FROM articles
+ # WHERE id IN (SELECT id FROM duplicates_draft_articles) RETURNING id;
+ # SQL
+ # )
+ #
+ # result_same_body_ids = result_same_body.map { |row| row["id"] }
+ # result_different_bodies_ids = result_different_bodies.map { |row| row["id"] }
# Remove all articles from Elasticsearch
- (result_same_body_ids + result_different_bodies_ids).each do |id|
- Search::RemoveFromIndexWorker.perform_in(5.seconds, "Search::FeedContent", "article_#{id}")
- end
+ # (result_same_body_ids + result_different_bodies_ids).each do |id|
+ # Search::RemoveFromIndexWorker.perform_in(5.seconds, "Search::FeedContent", "article_#{id}")
+ # end
# Store deleted IDs temporarily in Redis for safe keeping
- Rails.cache.write(
- "DataUpdateScripts::RemoveDraftArticlesWithDuplicateFeedSourceUrl::SameBody",
- result_same_body_ids,
- expires_in: 2.weeks,
- )
- Rails.cache.write(
- "DataUpdateScripts::RemoveDraftArticlesWithDuplicateFeedSourceUrl::DifferentBodies",
- result_same_body_ids,
- expires_in: 2.weeks,
- )
+ # Rails.cache.write(
+ # "DataUpdateScripts::RemoveDraftArticlesWithDuplicateFeedSourceUrl::SameBody",
+ # result_same_body_ids,
+ # expires_in: 2.weeks,
+ # )
+ # Rails.cache.write(
+ # "DataUpdateScripts::RemoveDraftArticlesWithDuplicateFeedSourceUrl::DifferentBodies",
+ # result_same_body_ids,
+ # expires_in: 2.weeks,
+ # )
end
end
end
diff --git a/lib/data_update_scripts/20200910140109_cleanup_published_articles_with_duplicate_user_id_title_body_markdown.rb b/lib/data_update_scripts/20200910140109_cleanup_published_articles_with_duplicate_user_id_title_body_markdown.rb
index 23ff5a6f1..0a938f6db 100644
--- a/lib/data_update_scripts/20200910140109_cleanup_published_articles_with_duplicate_user_id_title_body_markdown.rb
+++ b/lib/data_update_scripts/20200910140109_cleanup_published_articles_with_duplicate_user_id_title_body_markdown.rb
@@ -34,7 +34,7 @@ module DataUpdateScripts
# save all the magic
article.save
- article.index_to_elasticsearch_inline
+ # article.index_to_elasticsearch_inline
articles_to_delete_ids += articles_to_graft.map { |a| a["id"] }
end
diff --git a/lib/data_update_scripts/20200911045602_reindex_articles_with_videos.rb b/lib/data_update_scripts/20200911045602_reindex_articles_with_videos.rb
index 1ec9484aa..31e7caa4f 100644
--- a/lib/data_update_scripts/20200911045602_reindex_articles_with_videos.rb
+++ b/lib/data_update_scripts/20200911045602_reindex_articles_with_videos.rb
@@ -1,8 +1,8 @@
module DataUpdateScripts
class ReindexArticlesWithVideos
def run
- articles = Article.where.not(video: nil).or(Article.where.not(video: ""))
- articles.find_each(&:index_to_elasticsearch_inline)
+ # articles = Article.where.not(video: nil).or(Article.where.not(video: ""))
+ # articles.find_each(&:index_to_elasticsearch_inline)
end
end
end
diff --git a/lib/data_update_scripts/20200924140813_remove_reaction_index_by_name.rb b/lib/data_update_scripts/20200924140813_remove_reaction_index_by_name.rb
index 77e46414e..9e5415954 100644
--- a/lib/data_update_scripts/20200924140813_remove_reaction_index_by_name.rb
+++ b/lib/data_update_scripts/20200924140813_remove_reaction_index_by_name.rb
@@ -1,10 +1,10 @@
module DataUpdateScripts
class RemoveReactionIndexByName
def run
- index_name = "reactions_#{Rails.env}"
- return unless Search::Client.indices.exists(index: index_name)
+ # index_name = "reactions_#{Rails.env}"
+ # return unless Search::Client.indices.exists(index: index_name)
- Search::Client.indices.delete(index: index_name)
+ # Search::Client.indices.delete(index: index_name)
end
end
end
diff --git a/lib/data_update_scripts/20201030134117_reindex_users_for_username_search.rb b/lib/data_update_scripts/20201030134117_reindex_users_for_username_search.rb
index e131bef58..47d03cd2c 100644
--- a/lib/data_update_scripts/20201030134117_reindex_users_for_username_search.rb
+++ b/lib/data_update_scripts/20201030134117_reindex_users_for_username_search.rb
@@ -1,9 +1,9 @@
module DataUpdateScripts
class ReindexUsersForUsernameSearch
def run
- User.select(:id).in_batches(of: 200) do |batch|
- Search::BulkIndexWorker.set(queue: :default).perform_async("User", batch.ids)
- end
+ # User.select(:id).in_batches(of: 200) do |batch|
+ # Search::BulkIndexWorker.set(queue: :default).perform_async("User", batch.ids)
+ # end
end
end
end
diff --git a/lib/data_update_scripts/20210118194138_resync_unpublished_articles_comments_elasticsearch_document.rb b/lib/data_update_scripts/20210118194138_resync_unpublished_articles_comments_elasticsearch_document.rb
index 5160419ff..4c102122b 100644
--- a/lib/data_update_scripts/20210118194138_resync_unpublished_articles_comments_elasticsearch_document.rb
+++ b/lib/data_update_scripts/20210118194138_resync_unpublished_articles_comments_elasticsearch_document.rb
@@ -1,9 +1,9 @@
module DataUpdateScripts
class ResyncUnpublishedArticlesCommentsElasticsearchDocument
def run
- Article.unpublished.where.not(comments_count: 0).each do |article|
- article.comments.each(&:index_to_elasticsearch)
- end
+ # Article.unpublished.where.not(comments_count: 0).each do |article|
+ # article.comments.each(&:index_to_elasticsearch)
+ # end
end
end
end
diff --git a/lib/tasks/app_initializer.rake b/lib/tasks/app_initializer.rake
index bbc000885..fb7d6f333 100644
--- a/lib/tasks/app_initializer.rake
+++ b/lib/tasks/app_initializer.rake
@@ -1,9 +1,6 @@
namespace :app_initializer do
desc "Prepare Application on Boot Up"
task setup: :environment do
- puts "\n== Preparing Elasticsearch =="
- Rake::Task["search:setup"].execute
-
puts "\n== Preparing database =="
system("bin/rails db:prepare") || exit!(1)
Rake::Task["db:migrate"].execute # it'll re-alphabetize the columns in `schema.rb`
diff --git a/lib/tasks/search.rake b/lib/tasks/search.rake
deleted file mode 100644
index 5c7abd766..000000000
--- a/lib/tasks/search.rake
+++ /dev/null
@@ -1,26 +0,0 @@
-namespace :search do
- desc "set up Elasticsearch indexes"
- task setup: :environment do
- Search::Cluster.setup_indexes
- end
-
- desc "update Elasticsearch index mappings"
- task update_mappings: :environment do
- Search::Cluster.update_mappings
- end
-
- desc "tear down Elasticsearch indexes"
- task destroy: :environment do
- if Rails.env.production?
- puts "Will NOT destroy indexes in production"
- next
- end
-
- Search::Cluster.delete_indexes
- end
-end
-
-if Rails.env.development?
- Rake::Task["db:create"].enhance(["search:setup"])
- Rake::Task["db:drop"].enhance(["search:destroy"])
-end
diff --git a/release-tasks.sh b/release-tasks.sh
index f76338ad4..f77240619 100755
--- a/release-tasks.sh
+++ b/release-tasks.sh
@@ -14,8 +14,7 @@ set -Eex
# abort release if deploy status equals "blocked"
[[ $DEPLOY_STATUS = "blocked" ]] && echo "Deploy blocked" && exit 1
-# runs migration for Postgres, setups/updates Elasticsearch
-# and boots the app to check there are no errors
+# runs migration for Postgres and boots the app to check there are no errors
STATEMENT_TIMEOUT=4500000 bundle exec rails app_initializer:setup
bundle exec rake fastly:update_configs
bundle exec rails runner "puts 'app load success'"
diff --git a/spec/factories/tags.rb b/spec/factories/tags.rb
index 5c395d5f2..9e82608b8 100644
--- a/spec/factories/tags.rb
+++ b/spec/factories/tags.rb
@@ -4,9 +4,5 @@ FactoryBot.define do
factory :tag do
name { generate :name }
supported { true }
-
- trait :search_indexed do
- after(:create, &:index_to_elasticsearch_inline)
- end
end
end
diff --git a/spec/initializers/rack/attack_spec.rb b/spec/initializers/rack/attack_spec.rb
index d02eb099f..9102d14f4 100644
--- a/spec/initializers/rack/attack_spec.rb
+++ b/spec/initializers/rack/attack_spec.rb
@@ -11,12 +11,13 @@ describe Rack::Attack, type: :request, throttle: true do
describe "search_throttle" do
it "throttles /search endpoints based on IP" do
Timecop.freeze do
- allow(Search::User).to receive(:search_documents).and_return({})
+ allow(Search::Postgres::Username).to receive(:search_documents).and_return({})
+
valid_responses = Array.new(5).map do
- get "/search/users", headers: { "HTTP_FASTLY_CLIENT_IP" => "5.6.7.8" }
+ get "/search/usernames", headers: { "HTTP_FASTLY_CLIENT_IP" => "5.6.7.8" }
end
- throttled_response = get "/search/users", headers: { "HTTP_FASTLY_CLIENT_IP" => "5.6.7.8" }
- new_ip_response = get "/search/users", headers: { "HTTP_FASTLY_CLIENT_IP" => "1.1.1.1" }
+ throttled_response = get "/search/usernames", headers: { "HTTP_FASTLY_CLIENT_IP" => "5.6.7.8" }
+ new_ip_response = get "/search/usernames", headers: { "HTTP_FASTLY_CLIENT_IP" => "1.1.1.1" }
valid_responses.each { |r| expect(r).not_to eq(429) }
expect(throttled_response).to eq(429)
diff --git a/spec/lib/acts_as_taggable_on/tag_spec.rb b/spec/lib/acts_as_taggable_on/tag_spec.rb
deleted file mode 100644
index 312d47309..000000000
--- a/spec/lib/acts_as_taggable_on/tag_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require "rails_helper"
-
-RSpec.describe ActsAsTaggableOn::Tag, type: :lib do
- describe "#after_commit" do
- it "on create indexes tag to elasticsearch" do
- tag_name = "muffintag"
- create(:article, body_markdown: "---\ntitle: Me#{rand(1000)}\ntags: #{tag_name}\n---\n\nMeMeMe")
- sidekiq_perform_enqueued_jobs
- tag = Tag.find_by(name: tag_name)
- expect(tag.elasticsearch_doc).not_to be_nil
- end
-
- it "syncs related elasticsearch documents" do
- article = create(:article)
- podcast_episode = create(:podcast_episode)
- tag = article.tags.first
- podcast_episode.tags << tag
- new_keywords = "keyword1, keyword2, keyword3"
- sidekiq_perform_enqueued_jobs
-
- tag.update(keywords_for_search: new_keywords)
- sidekiq_perform_enqueued_jobs
- expect(collect_keywords(article)).to include(new_keywords)
- expect(collect_keywords(podcast_episode)).to include(new_keywords)
- end
- end
-
- def collect_keywords(record)
- record.elasticsearch_doc.dig("_source", "tags").flat_map { |t| t["keywords_for_search"] }
- end
-end
diff --git a/spec/lib/data_update_scripts/index_chat_channel_memberships_to_elasticsearch_spec.rb b/spec/lib/data_update_scripts/index_chat_channel_memberships_to_elasticsearch_spec.rb
deleted file mode 100644
index 137af509c..000000000
--- a/spec/lib/data_update_scripts/index_chat_channel_memberships_to_elasticsearch_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require "rails_helper"
-require Rails.root.join("lib/data_update_scripts/20200218195023_index_chat_channel_memberships_to_elasticsearch.rb")
-
-describe DataUpdateScripts::IndexChatChannelMembershipsToElasticsearch, elasticsearch: "ChatChannelMembership" do
- it "indexes chat channel memberships to Elasticsearch" do
- chat_channel_membership = FactoryBot.create(:chat_channel_membership)
- expect { chat_channel_membership.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
- described_class.new.run
- expect(chat_channel_membership.elasticsearch_doc).not_to be_nil
- end
-end
diff --git a/spec/lib/data_update_scripts/re_index_feed_content_and_users_to_elasticsearch_spec.rb b/spec/lib/data_update_scripts/re_index_feed_content_and_users_to_elasticsearch_spec.rb
deleted file mode 100644
index 98bf55ca9..000000000
--- a/spec/lib/data_update_scripts/re_index_feed_content_and_users_to_elasticsearch_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require "rails_helper"
-require Rails.root.join("lib/data_update_scripts/20200519142908_re_index_feed_content_and_users_to_elasticsearch.rb")
-
-describe DataUpdateScripts::ReIndexFeedContentAndUsersToElasticsearch do
- after do
- Search::FeedContent.refresh_index
- end
-
- it "indexes feed content(articles, comments, podcast episodes) and users to Elasticsearch", :aggregate_failures do
- article = create(:article)
- podcast_episode = create(:podcast_episode)
- comment = create(:comment)
-
- expect { article.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
- expect { podcast_episode.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
- expect { comment.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
-
- sidekiq_perform_enqueued_jobs { described_class.new.run }
-
- expect(article.elasticsearch_doc).not_to be_nil
- expect(podcast_episode.elasticsearch_doc).not_to be_nil
- expect(comment.elasticsearch_doc).not_to be_nil
-
- expect(article.elasticsearch_doc["_source"].keys).to include "public_reactions_count"
- expect(podcast_episode.elasticsearch_doc["_source"].keys).to include "public_reactions_count"
- expect(comment.elasticsearch_doc["_source"].keys).to include "public_reactions_count"
- end
-end
diff --git a/spec/lib/data_update_scripts/reindex_listing_search_column_spec.rb b/spec/lib/data_update_scripts/reindex_listing_search_column_spec.rb
deleted file mode 100644
index 967558231..000000000
--- a/spec/lib/data_update_scripts/reindex_listing_search_column_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require "rails_helper"
-require Rails.root.join("lib/data_update_scripts/20200803142830_reindex_listing_search_column.rb")
-
-describe DataUpdateScripts::ReindexListingSearchColumn, elasticsearch: "Listing" do
- it "indexes listings to Elasticsearch" do
- listing = create(:listing)
- expect { listing.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
- described_class.new.run
- expect(listing.elasticsearch_doc).not_to be_nil
- end
-end
diff --git a/spec/lib/data_update_scripts/reindex_users_for_username_search_spec.rb b/spec/lib/data_update_scripts/reindex_users_for_username_search_spec.rb
deleted file mode 100644
index bd9826833..000000000
--- a/spec/lib/data_update_scripts/reindex_users_for_username_search_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require "rails_helper"
-require Rails.root.join("lib/data_update_scripts/20201030134117_reindex_users_for_username_search.rb")
-
-describe DataUpdateScripts::ReindexUsersForUsernameSearch do
- let(:user) { create :user }
-
- it "reindexes users" do
- sidekiq_assert_enqueued_with(job: Search::BulkIndexWorker, args: ["User", [user.id]], queue: "default") do
- described_class.new.run
- end
- end
-end
diff --git a/spec/lib/data_update_scripts/remove_reaction_index_by_name_spec.rb b/spec/lib/data_update_scripts/remove_reaction_index_by_name_spec.rb
deleted file mode 100644
index 48fb7cb15..000000000
--- a/spec/lib/data_update_scripts/remove_reaction_index_by_name_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require "rails_helper"
-require Rails.root.join("lib/data_update_scripts/20200924140813_remove_reaction_index_by_name.rb")
-
-describe DataUpdateScripts::RemoveReactionIndexByName do
- it "removes reaction index" do
- index_name = "reactions_#{Rails.env}"
- Search::Client.indices.create(index: index_name)
- expect(Search::Client.indices.get(index: "*").keys).to include(index_name)
-
- described_class.new.run
- expect(Search::Client.indices.get(index: "*").keys).not_to include(index_name)
- end
-end
diff --git a/spec/lib/data_update_scripts/resync_elasticsearch_documents_spec.rb b/spec/lib/data_update_scripts/resync_elasticsearch_documents_spec.rb
deleted file mode 100644
index 89063cfef..000000000
--- a/spec/lib/data_update_scripts/resync_elasticsearch_documents_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require "rails_helper"
-require Rails.root.join("lib/data_update_scripts/20200410152018_resync_elasticsearch_documents.rb")
-
-describe DataUpdateScripts::ResyncElasticsearchDocuments, elasticsearch: %w[FeedContent User Tag] do
- after do
- Article::SEARCH_CLASS.refresh_index
- User::SEARCH_CLASS.refresh_index
- end
-
- it "indexes podcast episodes and tags to Elasticsearch" do
- tag = create(:tag)
- podcast_episode = create(:podcast_episode)
- Sidekiq::Worker.clear_all
-
- expect { tag.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
- expect { podcast_episode.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
-
- sidekiq_perform_enqueued_jobs { described_class.new.run }
- expect(tag.elasticsearch_doc).not_to be_nil
- expect(podcast_episode.elasticsearch_doc).not_to be_nil
- end
-
- it "syncs articles, comments, and users to Elasticsearch", :aggregate_failures do
- article = create(:article)
- comment = create(:comment)
- user = create(:user)
- index_real_and_mock_documents(article, comment, user)
-
- expect(Article::SEARCH_CLASS.articles_document_count).not_to eq(Article.count)
- expect(Comment::SEARCH_CLASS.comments_document_count).not_to eq(Comment.count)
- expect(User::SEARCH_CLASS.document_count).not_to eq(User.count)
-
- sidekiq_perform_enqueued_jobs { described_class.new.run }
- refresh_indexes
-
- expect(article.elasticsearch_doc).not_to be_nil
- expect(user.elasticsearch_doc).not_to be_nil
- expect(comment.elasticsearch_doc).not_to be_nil
- expect(Article::SEARCH_CLASS.articles_document_count).to eq(Article.count)
- expect(Comment::SEARCH_CLASS.comments_document_count).to eq(Comment.count)
- expect(User::SEARCH_CLASS.document_count).to eq(User.count)
- end
-
- def index_real_and_mock_documents(article, comment, user)
- sidekiq_perform_enqueued_jobs
- Article::SEARCH_CLASS.index("article_#{article.id + 100}", class_name: "Article")
- Comment::SEARCH_CLASS.index("comment_#{comment.id + 100}", class_name: "Comment")
- User::SEARCH_CLASS.index(user.id + 100, name: "User")
- refresh_indexes
- end
-
- def refresh_indexes
- User::SEARCH_CLASS.refresh_index
- Article::SEARCH_CLASS.refresh_index
- end
-end
diff --git a/spec/lib/data_update_scripts/resync_unpublished_articles_comments_elasticsearch_document_spec.rb b/spec/lib/data_update_scripts/resync_unpublished_articles_comments_elasticsearch_document_spec.rb
deleted file mode 100644
index 60c5705f3..000000000
--- a/spec/lib/data_update_scripts/resync_unpublished_articles_comments_elasticsearch_document_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require "rails_helper"
-require Rails.root.join(
- "lib/data_update_scripts/20210118194138_resync_unpublished_articles_comments_elasticsearch_document.rb",
-)
-
-describe DataUpdateScripts::ResyncUnpublishedArticlesCommentsElasticsearchDocument do
- it "works" do
- article = create(:article)
- comment = create(:comment, commentable: article)
- sidekiq_perform_enqueued_jobs
- article.update_column(:published, false)
-
- sidekiq_assert_enqueued_with(job: Search::IndexWorker, args: ["Comment", comment.id]) do
- described_class.new.run
- end
- end
-end
diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb
index 7cfa6d9fa..df51653d2 100644
--- a/spec/models/article_spec.rb
+++ b/spec/models/article_spec.rb
@@ -137,30 +137,6 @@ RSpec.describe Article, type: :model do
end
end
- describe "#after_commit" do
- it "on update enqueues job to index article to elasticsearch" do
- article.save
- sidekiq_assert_enqueued_with(job: Search::IndexWorker, args: [described_class.to_s, article.id]) do
- article.save
- end
- end
-
- it "on destroy enqueues job to delete article from elasticsearch" do
- article = create(:article)
-
- sidekiq_assert_enqueued_with(job: Search::RemoveFromIndexWorker,
- args: [described_class::SEARCH_CLASS.to_s, article.search_id]) do
- article.destroy
- end
- end
-
- it "on update syncs elasticsearch data" do
- allow(article).to receive(:sync_related_elasticsearch_docs)
- article.save
- expect(article).to have_received(:sync_related_elasticsearch_docs)
- end
- end
-
context "when published" do
before do
# rubocop:disable RSpec/NamedSubject
@@ -1204,14 +1180,6 @@ RSpec.describe Article, type: :model do
end
end
- describe "#touch_by_reaction" do
- it "reindexes elasticsearch doc" do
- sidekiq_assert_enqueued_with(job: Search::IndexWorker, args: [described_class.to_s, article.id]) do
- article.touch_by_reaction
- end
- end
- end
-
describe "co_author_ids_list=" do
it "correctly sets co author ids from a comma separated list of ids" do
co_author1 = create(:user)
diff --git a/spec/models/chat_channel_membership_spec.rb b/spec/models/chat_channel_membership_spec.rb
index 204a30d51..1b3f60e11 100644
--- a/spec/models/chat_channel_membership_spec.rb
+++ b/spec/models/chat_channel_membership_spec.rb
@@ -34,22 +34,4 @@ RSpec.describe ChatChannelMembership, type: :model do
expect(chat_channel_membership.channel_text).to eq(expected_text)
end
end
-
- describe "#after_commit" do
- it "on update enqueues job to index chat_channel_membership to elasticsearch" do
- chat_channel_membership.save
- sidekiq_assert_enqueued_with(job: Search::IndexWorker,
- args: [described_class.to_s, chat_channel_membership.id]) do
- chat_channel_membership.save
- end
- end
-
- it "on destroy enqueues job to delete chat_channel_membership from elasticsearch" do
- chat_channel_membership.save
- sidekiq_assert_enqueued_with(job: Search::RemoveFromIndexWorker,
- args: [described_class::SEARCH_CLASS.to_s, chat_channel_membership.id]) do
- chat_channel_membership.destroy
- end
- end
- end
end
diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb
index b5063531e..049a9a484 100644
--- a/spec/models/comment_spec.rb
+++ b/spec/models/comment_spec.rb
@@ -118,23 +118,6 @@ RSpec.describe Comment, type: :model do
end
# rubocop:enable RSpec/NamedSubject
- describe "#after_commit" do
- it "on update enqueues job to index comment to elasticsearch" do
- sidekiq_assert_enqueued_with(job: Search::IndexWorker, args: [described_class.to_s, comment.id]) do
- comment.save
- end
- end
-
- it "on destroy enqueues job to delete comment from elasticsearch" do
- comment = create(:comment)
-
- sidekiq_assert_enqueued_with(job: Search::RemoveFromIndexWorker,
- args: [described_class::SEARCH_CLASS.to_s, comment.search_id]) do
- comment.destroy
- end
- end
- end
-
describe "#search_id" do
it "returns comment_ID" do
expect(comment.search_id).to eq("comment_#{comment.id}")
diff --git a/spec/models/concerns/searchable_spec.rb b/spec/models/concerns/searchable_spec.rb
deleted file mode 100644
index 6c6f77483..000000000
--- a/spec/models/concerns/searchable_spec.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-require "rails_helper"
-
-class SearchableModel
- include Searchable
- SEARCH_CLASS = Search::Tag
- SEARCH_SERIALIZER = Search::TagSerializer
-
- def id
- 1
- end
-end
-
-RSpec.describe Searchable do
- let(:model_class) { SearchableModel }
- let(:searchable_model) { model_class.new }
- let(:serialized_hash) { { data: { attributes: { id: searchable_model.search_id } } } }
-
- before do
- mock_serializer = instance_double("MockSerializer", :serializable_hash)
- allow(model_class::SEARCH_SERIALIZER).to receive(:new).and_return(mock_serializer)
- allow(mock_serializer).to receive(:serializable_hash).and_return(
- serialized_hash,
- )
- end
-
- describe "#search_id" do
- it "defaults to id" do
- expect(searchable_model.search_id).to equal(searchable_model.id)
- end
- end
-
- describe "#remove_from_elasticsearch" do
- it "enqueues job to delete model document from elasticsearch" do
- sidekiq_assert_enqueued_with(job: Search::RemoveFromIndexWorker,
- args: [SearchableModel::SEARCH_CLASS.to_s, searchable_model.search_id]) do
- searchable_model.remove_from_elasticsearch
- end
- end
- end
-
- describe "#index_to_elasticsearch" do
- it "enqueues job to index document to elasticsearch" do
- sidekiq_assert_enqueued_with(job: Search::IndexWorker, args: ["SearchableModel", searchable_model.id]) do
- searchable_model.index_to_elasticsearch
- end
- end
- end
-
- describe "#index_to_elasticsearch_inline" do
- it "indexes a document to elasticsearch inline" do
- allow(model_class::SEARCH_CLASS).to receive(:index)
- searchable_model.index_to_elasticsearch_inline
- expect(model_class::SEARCH_CLASS).to have_received(:index).with(searchable_model.search_id,
- id: searchable_model.search_id)
- end
- end
-
- describe "#serialized_search_hash" do
- it "creates a valid serialized hash to send to elasticsearch" do
- expect(searchable_model.serialized_search_hash.symbolize_keys.keys).to eq([:id])
- end
- end
-
- describe "#elasticsearch_doc" do
- it "finds document in elasticsearch" do
- allow(model_class::SEARCH_CLASS).to receive(:find_document)
- searchable_model.elasticsearch_doc
- expect(model_class::SEARCH_CLASS).to have_received(:find_document)
- end
- end
-end
diff --git a/spec/models/listing_spec.rb b/spec/models/listing_spec.rb
index 98eeb193a..248082e64 100644
--- a/spec/models/listing_spec.rb
+++ b/spec/models/listing_spec.rb
@@ -71,22 +71,4 @@ RSpec.describe Listing, type: :model do
expect(credit.reload.purchase).to be_nil
end
end
-
- describe "#after_commit" do
- it "on update enqueues worker to index tag to elasticsearch" do
- listing.save
-
- sidekiq_assert_enqueued_with(job: Search::IndexWorker, args: [described_class.to_s, listing.id]) do
- listing.save
- end
- end
-
- it "on destroy enqueues job to delete listing from elasticsearch" do
- listing.save
- sidekiq_assert_enqueued_with(job: Search::RemoveFromIndexWorker,
- args: [described_class::SEARCH_CLASS.to_s, listing.id]) do
- listing.destroy
- end
- end
- end
end
diff --git a/spec/models/message_spec.rb b/spec/models/message_spec.rb
index c58d3c807..625dfde2f 100644
--- a/spec/models/message_spec.rb
+++ b/spec/models/message_spec.rb
@@ -158,15 +158,6 @@ RSpec.describe Message, type: :model do
end
describe "#after_create" do
- it "enqueues ChatChannels::IndexesMembershipsWorker" do
- chat_channel.add_users([user])
- allow(ChatChannels::IndexesMembershipsWorker).to receive(:perform_async)
-
- create(:message, chat_channel: chat_channel, user: user)
-
- expect(ChatChannels::IndexesMembershipsWorker).to have_received(:perform_async)
- end
-
context "when chat_action is left_channel" do
it "does not update unopened message statuses" do
chat_channel.add_users([user, user2])
diff --git a/spec/models/organization_spec.rb b/spec/models/organization_spec.rb
index f9e1e44f1..bfac8f1ae 100644
--- a/spec/models/organization_spec.rb
+++ b/spec/models/organization_spec.rb
@@ -72,22 +72,9 @@ RSpec.describe Organization, type: :model do
end
context "when callbacks are triggered after commit" do
- it "on update syncs elasticsearch data" do
- article = create(:article, organization: organization)
- sidekiq_perform_enqueued_jobs
- new_org_name = "#{organization.name}+NEW"
- organization.update(name: new_org_name)
- sidekiq_perform_enqueued_jobs
- expect(article.elasticsearch_doc.dig("_source", "organization", "name")).to eq(new_org_name)
- end
-
it "on destroy updates related article data" do
article = create(:article, organization: organization)
- drain_all_sidekiq_jobs
- expect(article.elasticsearch_doc.dig("_source", "organization", "id")).to eq(organization.id)
organization.destroy
- sidekiq_perform_enqueued_jobs
- expect(article.elasticsearch_doc.dig("_source", "organization")).to be_nil
expect(article.reload.cached_organization).to be_nil
end
end
diff --git a/spec/models/podcast_episode_spec.rb b/spec/models/podcast_episode_spec.rb
index 1431a52f4..cb657b273 100644
--- a/spec/models/podcast_episode_spec.rb
+++ b/spec/models/podcast_episode_spec.rb
@@ -20,11 +20,6 @@ RSpec.describe PodcastEpisode, type: :model do
it { is_expected.to validate_presence_of(:title) }
end
- # Couldn't use shoulda matchers for these tests because:
- # Shoulda uses `save(validate: false)` which skips validations, but runs callbacks
- # So an invalid record is saved and the elasticsearch callback fails because there's no associated podcast
- # https://git.io/fjg2g
-
it "validates guid uniqueness" do
ep2 = build(:podcast_episode, guid: podcast_episode.guid)
@@ -40,23 +35,6 @@ RSpec.describe PodcastEpisode, type: :model do
end
end
- describe "#after_commit" do
- it "on update enqueues job to index podcast_episode to elasticsearch" do
- podcast_episode.save
- sidekiq_assert_enqueued_with(job: Search::IndexWorker, args: [described_class.to_s, podcast_episode.id]) do
- podcast_episode.save
- end
- end
-
- it "on destroy enqueues job to delete podcast_episode from elasticsearch" do
- podcast_episode.save
- sidekiq_assert_enqueued_with(job: Search::RemoveFromIndexWorker,
- args: [described_class::SEARCH_CLASS.to_s, podcast_episode.search_id]) do
- podcast_episode.destroy
- end
- end
- end
-
describe "#search_id" do
it "returns podcast_episode_ID" do
expect(podcast_episode.search_id).to eq("podcast_episode_#{podcast_episode.id}")
diff --git a/spec/models/tag_spec.rb b/spec/models/tag_spec.rb
index 0b0d7c656..b5ca689a7 100644
--- a/spec/models/tag_spec.rb
+++ b/spec/models/tag_spec.rb
@@ -128,37 +128,6 @@ RSpec.describe Tag, type: :model do
expect(tag.mod_chat_channel).to eq(channel)
end
- describe "#after_commit" do
- it "on update enqueues job to index tag to elasticsearch" do
- tag.save
- sidekiq_assert_enqueued_with(job: Search::IndexWorker, args: [described_class.to_s, tag.id]) do
- tag.save
- end
- end
-
- it "on destroy enqueues job to delete tag from elasticsearch" do
- tag.save
- sidekiq_assert_enqueued_with(job: Search::RemoveFromIndexWorker,
- args: [described_class::SEARCH_CLASS.to_s, tag.id]) do
- tag.destroy
- end
- end
-
- it "syncs related elasticsearch documents" do
- article = create(:article)
- podcast_episode = create(:podcast_episode)
- tag = described_class.find(article.tags.first.id)
- podcast_episode.tags << tag
- new_keywords = "keyword1, keyword2, keyword3"
- sidekiq_perform_enqueued_jobs
-
- tag.update(keywords_for_search: new_keywords)
- sidekiq_perform_enqueued_jobs
- expect(collect_keywords(article)).to include(new_keywords)
- expect(collect_keywords(podcast_episode)).to include(new_keywords)
- end
- end
-
describe "::aliased_name" do
it "returns the preferred alias tag" do
preferred_tag = create(:tag, name: "rails")
@@ -187,8 +156,4 @@ RSpec.describe Tag, type: :model do
expect(described_class.find_preferred_alias_for("something")).to eq("something")
end
end
-
- def collect_keywords(record)
- record.elasticsearch_doc.dig("_source", "tags").flat_map { |t| t["keywords_for_search"] }
- end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index d39b50c55..ddcf21998 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -298,29 +298,6 @@ RSpec.describe User, type: :model do
end
end
- describe "#after_commit" do
- it "on update enqueues job to index user to elasticsearch" do
- user.save
- sidekiq_assert_enqueued_with(job: Search::IndexWorker, args: [described_class.to_s, user.id]) do
- user.save
- end
- end
-
- it "on update syncs elasticsearch data" do
- allow(user).to receive(:sync_related_elasticsearch_docs)
- user.save
- expect(user).to have_received(:sync_related_elasticsearch_docs)
- end
-
- it "on destroy enqueues job to delete user from elasticsearch" do
- user.save
- sidekiq_assert_enqueued_with(job: Search::RemoveFromIndexWorker,
- args: [described_class::SEARCH_CLASS.to_s, user.id]) do
- user.destroy
- end
- end
- end
-
context "when callbacks are triggered before validation" do
let(:user) { build(:user) }
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index a48ff8378..d3b87d759 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -48,7 +48,6 @@ allowed_sites = [
"selenium-release.storage.googleapis.com",
"developer.microsoft.com/en-us/microsoft-edge/tools/webdriver",
"api.knapsackpro.com",
- "elasticsearch",
]
WebMock.disable_net_connect!(allow_localhost: true, allow: allowed_sites)
@@ -74,7 +73,6 @@ RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
config.include OmniauthHelpers
config.include SidekiqTestHelpers
- config.include ElasticsearchHelpers
config.after(:each, type: :system) do
Warden::Manager._on_request.clear
@@ -89,8 +87,6 @@ RSpec.configure do |config|
# which we can then use to properly set the browser time for Capybara specs
ENV["TZ"] = Time.zone.tzinfo.name
- Search::Cluster.recreate_indexes
-
# NOTE: @citizen428 needed while we delegate from User to Profile to keep
# spec changes limited for the time being.
csv = Rails.root.join("lib/data/dev_profile_fields.csv")
@@ -109,30 +105,10 @@ RSpec.configure do |config|
# rubocop:enable RSpec/AnyInstance
end
- config.before(:each, stub_elasticsearch: true) do |_example|
- stubbed_search_response = { "hits" => { "hits" => [] } }
- allow(Search::Client).to receive(:search).and_return(stubbed_search_response)
- allow(Search::Client).to receive(:index).and_return({ "_source" => {} })
- end
-
config.around(:each, :flaky) do |ex|
ex.run_with_retry retry: 3
end
- config.around(:each, elasticsearch_reset: true) do |example|
- Search::Cluster.recreate_indexes
- example.run
- Search::Cluster.recreate_indexes
- end
-
- config.around(:each, :elasticsearch) do |ex|
- klasses = Array.wrap(ex.metadata[:elasticsearch]).map do |search_class|
- Search.const_get(search_class)
- end
- klasses.each { |klass| clear_elasticsearch_data(klass) }
- ex.run
- end
-
config.around(:each, throttle: true) do |example|
Rack::Attack.enabled = true
example.run
diff --git a/spec/requests/api/v0/health_checks_spec.rb b/spec/requests/api/v0/health_checks_spec.rb
index b6df5a71e..6d7a5e811 100644
--- a/spec/requests/api/v0/health_checks_spec.rb
+++ b/spec/requests/api/v0/health_checks_spec.rb
@@ -22,21 +22,6 @@ RSpec.describe "HealthCheck", type: :request do
end
end
- describe "GET /api/health_checks/search" do
- it "returns json success if ping succeeds" do
- get search_api_health_checks_path, headers: headers
- expect(response.status).to eq(200)
- expect(response.parsed_body["message"]).to eq("Search ping succeeded!")
- end
-
- it "returns json failure if ping fails" do
- allow(Search::Client).to receive(:ping).and_return(false)
- get search_api_health_checks_path, headers: headers
- expect(response.status).to eq(500)
- expect(response.parsed_body["message"]).to eq("Search ping failed!")
- end
- end
-
describe "GET /api/health_checks/database" do
it "returns json success if connection check succeeds" do
get database_api_health_checks_path, headers: headers
diff --git a/spec/requests/search_spec.rb b/spec/requests/search_spec.rb
index 27d40aa33..f6bff8bdd 100644
--- a/spec/requests/search_spec.rb
+++ b/spec/requests/search_spec.rb
@@ -59,18 +59,6 @@ RSpec.describe "Search", type: :request, proper_status: true do
end
end
- describe "GET /search/users" do
- let(:mock_documents) { [{ "username" => "firstlast" }] }
-
- it "returns json" do
- allow(Search::User).to receive(:search_documents).and_return(
- mock_documents,
- )
- get "/search/users"
- expect(response.parsed_body).to eq("result" => mock_documents)
- end
- end
-
describe "GET /search/usernames" do
before do
sign_in authorized_user
diff --git a/spec/serializers/search/article_serializer_spec.rb b/spec/serializers/search/article_serializer_spec.rb
index d6b2fb08d..5cb168596 100644
--- a/spec/serializers/search/article_serializer_spec.rb
+++ b/spec/serializers/search/article_serializer_spec.rb
@@ -16,12 +16,6 @@ RSpec.describe Search::ArticleSerializer do
expect(data_hash.keys).to include(:id, :body_text, :hotness_score)
end
- it "creates valid json for Elasticsearch", elasticsearch: "FeedContent" do
- data_hash = described_class.new(article).serializable_hash.dig(:data, :attributes)
- result = Article::SEARCH_CLASS.index(article.id, data_hash)
- expect(result["result"]).to eq("created")
- end
-
it "correctly serializes video duration in minutes when video_duration_in_seconds is nil" do
data_hash = described_class.new(article).serializable_hash.dig(:data, :attributes)
expect(data_hash[:video_duration_in_minutes]).to eq(0)
diff --git a/spec/serializers/search/comment_serializer_spec.rb b/spec/serializers/search/comment_serializer_spec.rb
index 10a624e43..65b81694f 100644
--- a/spec/serializers/search/comment_serializer_spec.rb
+++ b/spec/serializers/search/comment_serializer_spec.rb
@@ -11,10 +11,4 @@ RSpec.describe Search::CommentSerializer do
expect(data_hash[:user]).to eq(user_data)
expect(data_hash.keys).to include(:id, :body_text, :hotness_score, :title)
end
-
- it "creates valid json for Elasticsearch", elasticsearch: "FeedContent" do
- data_hash = described_class.new(comment).serializable_hash.dig(:data, :attributes)
- result = Comment::SEARCH_CLASS.index(comment.id, data_hash)
- expect(result["result"]).to eq("created")
- end
end
diff --git a/spec/serializers/search/user_serializer_spec.rb b/spec/serializers/search/user_serializer_spec.rb
index 12451dd47..efa891ba8 100644
--- a/spec/serializers/search/user_serializer_spec.rb
+++ b/spec/serializers/search/user_serializer_spec.rb
@@ -7,26 +7,4 @@ RSpec.describe Search::UserSerializer do
data_hash = described_class.new(user).serializable_hash.dig(:data, :attributes)
expect(data_hash.keys).to include(:id, :name, :path, :username, :roles)
end
-
- it "creates valid json for Elasticsearch", elasticsearch: "User" do
- data_hash = described_class.new(user).serializable_hash.dig(:data, :attributes)
- result = User::SEARCH_CLASS.index(user.id, data_hash)
- expect(result["result"]).to eq("created")
- end
-
- it "indexes profile fields as a nested field", elasticsearch: "User", aggregate_failures: true do
- data_hash = described_class.new(user).serializable_hash.dig(:data, :attributes)
- result = User::SEARCH_CLASS.index(user.id, data_hash)
- expect(result["result"]).to eq("created")
- indexed_profile_fields = user.reload.elasticsearch_doc.dig("_source", "profile_fields")
- expect(indexed_profile_fields).to be_an_instance_of(Array)
- end
-
- it "indexes custom profile fields as a nested field", elasticsearch: "User", aggregate_failures: true do
- data_hash = described_class.new(user).serializable_hash.dig(:data, :attributes)
- result = User::SEARCH_CLASS.index(user.id, data_hash)
- expect(result["result"]).to eq("created")
- indexed_custom_fields = user.reload.elasticsearch_doc.dig("_source", "custom_profile_fields")
- expect(indexed_custom_fields).to be_an_instance_of(Array)
- end
end
diff --git a/spec/services/data_sync/elasticsearch/article_spec.rb b/spec/services/data_sync/elasticsearch/article_spec.rb
deleted file mode 100644
index f28ae30b8..000000000
--- a/spec/services/data_sync/elasticsearch/article_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require "rails_helper"
-
-RSpec.describe DataSync::Elasticsearch::Article, type: :service do
- it "defines necessary constants" do
- expect(described_class::RELATED_DOCS).not_to be_nil
- expect(described_class::SHARED_FIELDS).not_to be_nil
- end
-end
diff --git a/spec/services/data_sync/elasticsearch/base_spec.rb b/spec/services/data_sync/elasticsearch/base_spec.rb
deleted file mode 100644
index e965793d6..000000000
--- a/spec/services/data_sync/elasticsearch/base_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require "rails_helper"
-
-RSpec.describe DataSync::Elasticsearch::Base, type: :service do
- let!(:updated_record) { instance_double("Record", saved_changes: { name: %w[name1 name2] }) }
- let(:syncer) { described_class.new(updated_record) }
-
- describe "#call" do
- before do
- stub_const("#{described_class}::SHARED_FIELDS", %i[name])
- allow(syncer).to receive(:sync_related_documents)
- end
-
- it "syncs related_documents when sync is needed " do
- syncer.call
- expect(syncer).to have_received(:sync_related_documents)
- end
-
- it "does not sync related_documents when sync is not needed" do
- allow(updated_record).to receive(:saved_changes).and_return(twitter_url: %w[url1 url2])
- syncer.call
- expect(syncer).not_to have_received(:sync_related_documents)
- end
- end
-end
diff --git a/spec/services/data_sync/elasticsearch/organization_spec.rb b/spec/services/data_sync/elasticsearch/organization_spec.rb
deleted file mode 100644
index cab5d2e6d..000000000
--- a/spec/services/data_sync/elasticsearch/organization_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require "rails_helper"
-
-RSpec.describe DataSync::Elasticsearch::Organization, type: :service do
- it "defines necessary constants" do
- expect(described_class::RELATED_DOCS).not_to be_nil
- expect(described_class::SHARED_FIELDS).not_to be_nil
- end
-end
diff --git a/spec/services/data_sync/elasticsearch/tag_spec.rb b/spec/services/data_sync/elasticsearch/tag_spec.rb
deleted file mode 100644
index 589f39743..000000000
--- a/spec/services/data_sync/elasticsearch/tag_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require "rails_helper"
-
-RSpec.describe DataSync::Elasticsearch::Tag, type: :service do
- it "defines necessary constants" do
- expect(described_class::RELATED_DOCS).not_to be_nil
- expect(described_class::SHARED_FIELDS).not_to be_nil
- end
-end
diff --git a/spec/services/data_sync/elasticsearch/user_spec.rb b/spec/services/data_sync/elasticsearch/user_spec.rb
deleted file mode 100644
index 3320d7a93..000000000
--- a/spec/services/data_sync/elasticsearch/user_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require "rails_helper"
-
-RSpec.describe DataSync::Elasticsearch::User, type: :service do
- it "defines necessary constants" do
- expect(described_class::RELATED_DOCS).not_to be_nil
- expect(described_class::SHARED_FIELDS).not_to be_nil
- end
-end
diff --git a/spec/services/edge_cache/bust_commentable_spec.rb b/spec/services/edge_cache/bust_commentable_spec.rb
index 71e3ddfaa..2fbcc2a7f 100644
--- a/spec/services/edge_cache/bust_commentable_spec.rb
+++ b/spec/services/edge_cache/bust_commentable_spec.rb
@@ -15,10 +15,4 @@ RSpec.describe EdgeCache::BustCommentable, type: :service do
expect(EdgeCache::BustComment).to have_received(:call).with(commentable).once
expect(cache_bust).to have_received(:call).with("#{commentable.path}/comments").once
end
-
- it "indexes commentable to Elasticsearch" do
- allow(commentable).to receive(:index_to_elasticsearch_inline)
- described_class.call(commentable)
- expect(commentable).to have_received(:index_to_elasticsearch_inline).once
- end
end
diff --git a/spec/services/moderator/banish_user_spec.rb b/spec/services/moderator/banish_user_spec.rb
index 2f615417b..d2464ae82 100644
--- a/spec/services/moderator/banish_user_spec.rb
+++ b/spec/services/moderator/banish_user_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Moderator::BanishUser, type: :service do
create(:comment, user: user, commentable: article)
sidekiq_perform_enqueued_jobs
- sidekiq_perform_enqueued_jobs(except: Search::IndexWorker) do
+ sidekiq_perform_enqueued_jobs do
described_class.call(user: user, admin: admin)
end
expect(user.comments.count).to eq 0
diff --git a/spec/services/moderator/merge_user_spec.rb b/spec/services/moderator/merge_user_spec.rb
index 1d6f08498..c27c5e4a9 100644
--- a/spec/services/moderator/merge_user_spec.rb
+++ b/spec/services/moderator/merge_user_spec.rb
@@ -23,20 +23,6 @@ RSpec.describe Moderator::MergeUser, type: :service do
expect(User.find_by(id: keep_user.id)).not_to be_nil
end
- it "updates documents in Elasticsearch" do
- related_records
- drain_all_sidekiq_jobs
- expect(article.elasticsearch_doc.dig("_source", "user", "id")).to eq(delete_user_id)
- expect(comment.elasticsearch_doc.dig("_source", "user", "id")).to eq(delete_user_id)
-
- sidekiq_perform_enqueued_jobs do
- described_class.call(admin: admin, keep_user: keep_user, delete_user_id: delete_user.id)
- end
- drain_all_sidekiq_jobs
- expect(article.reload.elasticsearch_doc.dig("_source", "user", "id")).to eq(keep_user.id)
- expect(comment.reload.elasticsearch_doc.dig("_source", "user", "id")).to eq(keep_user.id)
- end
-
it "updates badge_achievements_count" do
create_list(:badge_achievement, 2, user: delete_user)
diff --git a/spec/services/podcasts/create_episode_spec.rb b/spec/services/podcasts/create_episode_spec.rb
index 58939b85d..ef2319169 100644
--- a/spec/services/podcasts/create_episode_spec.rb
+++ b/spec/services/podcasts/create_episode_spec.rb
@@ -19,11 +19,6 @@ RSpec.describe Podcasts::CreateEpisode, type: :service do
end.to change(PodcastEpisode, :count).by(1)
end
- it "indexes the episode" do
- sidekiq_perform_enqueued_jobs { described_class.call(podcast.id, item) }
- expect { podcast.podcast_episodes.each(&:elasticsearch_doc) }.not_to raise_error
- end
-
it "creates an episode with correct data" do
episode = described_class.call(podcast.id, item)
expect(episode.title).to eq("Individual Contributor Career Growth w/ Matt Klein (part 1)")
diff --git a/spec/services/search/base_spec.rb b/spec/services/search/base_spec.rb
deleted file mode 100644
index 47a971f8c..000000000
--- a/spec/services/search/base_spec.rb
+++ /dev/null
@@ -1,170 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::Base, type: :service do
- let(:document_id) { 123 }
-
- def recreate_tag_index
- Search::Tag.delete_index if described_class.index_exists?
- Search::Tag.create_index
- Search::Tag.add_alias
- Search::Tag.update_mappings
- end
-
- before do
- # Need to use an existing index name to ensure proper data cleanup
- stub_const("#{described_class}::INDEX_NAME", "tags_#{Rails.env}")
- stub_const("#{described_class}::INDEX_ALIAS", "tags_#{Rails.env}_alias")
- stub_const("#{described_class}::MAPPINGS", Search::Tag::MAPPINGS)
- Search::Tag.refresh_index
- clear_elasticsearch_data(Search::Tag)
- allow(described_class).to receive(:index_settings).and_return({})
- end
-
- describe "::index" do
- it "indexes a document to elasticsearch" do
- expect { described_class.find_document(document_id) }.to raise_error(Search::Errors::Transport::NotFound)
- described_class.index(document_id, id: document_id)
- expect(described_class.find_document(document_id)).not_to be_nil
- end
-
- it "sets last_indexed_at field" do
- Timecop.freeze(Time.current) do
- described_class.index(document_id, id: document_id)
- last_indexed_at = described_class.find_document(document_id).dig("_source", "last_indexed_at")
- expect(Time.zone.parse(last_indexed_at).to_i).to eq(Time.current.to_i)
- end
- end
- end
-
- describe "::bulk_index" do
- it "indexes a set of data hashes to Elasticsearch" do
- id_list = [123, 456, 789]
- id_list.each do |document_id|
- expect { described_class.find_document(document_id) }.to raise_error(Search::Errors::Transport::NotFound)
- end
- data_hashes = id_list.map { |id| { id: id, name: "i_am_a_tag" } }
- described_class.bulk_index(data_hashes)
-
- id_list.each do |document_id|
- doc = described_class.find_document(document_id)
- expect(doc.dig("_source", "id")).to eql(document_id)
- end
- end
-
- it "sets last_indexed_at field" do
- Timecop.freeze(Time.current) do
- described_class.bulk_index([{ id: document_id, name: "i_am_a_tag" }])
- last_indexed_at = described_class.find_document(document_id).dig("_source", "last_indexed_at")
- expect(Time.zone.parse(last_indexed_at).to_i).to eq(Time.current.to_i)
- end
- end
- end
-
- describe "::find_document" do
- it "fetches a document for a given ID from elasticsearch" do
- described_class.index(document_id, id: document_id)
- expect { described_class.find_document(document_id) }.not_to raise_error
- end
- end
-
- describe "::delete_document" do
- it "deletes a document for a given ID from elasticsearch" do
- described_class.index(document_id, id: document_id)
- expect { described_class.find_document(document_id) }.not_to raise_error
- described_class.delete_document(document_id)
- expect { described_class.find_document(document_id) }.to raise_error(Search::Errors::Transport::NotFound)
- end
- end
-
- describe "::create_index" do
- before { recreate_tag_index }
-
- after { recreate_tag_index }
-
- it "creates an elasticsearch index with INDEX_NAME" do
- described_class.delete_index
- expect(Search::Client.indices.exists(index: described_class::INDEX_NAME)).to eq(false)
- described_class.create_index
- expect(Search::Client.indices.exists(index: described_class::INDEX_NAME)).to eq(true)
- end
-
- it "creates an elasticsearch index with name argument" do
- other_name = "random"
- expect(Search::Client.indices.exists(index: other_name)).to eq(false)
- described_class.create_index(index_name: other_name)
- expect(Search::Client.indices.exists(index: other_name)).to eq(true)
-
- # Have to cleanup index since it wont automatically be handled by our cluster class bc of the unexpected name
- described_class.delete_index(index_name: other_name)
- end
- end
-
- describe "::update_index" do
- before do
- recreate_tag_index
- allow(described_class).to receive(:dynamic_index_settings).and_return(
- refresh_interval: "10s",
- )
- end
-
- after { recreate_tag_index }
-
- it "updates elasticsearch index settings with INDEX_NAME" do
- index_info = Search::Client.indices.get(index: described_class::INDEX_NAME)
- expect(index_info.values.first.dig("settings", "index", "refresh_interval")).to be_nil
- described_class.update_index
-
- new_index_info = Search::Client.indices.get(index: described_class::INDEX_NAME)
- expect(new_index_info.values.first.dig("settings", "index", "refresh_interval")).to eq("10s")
- end
- end
-
- describe "::delete_index" do
- before { recreate_tag_index }
-
- after { recreate_tag_index }
-
- it "deletes an elasticsearch index with INDEX_NAME" do
- expect(Search::Client.indices.exists(index: described_class::INDEX_NAME)).to eq(true)
- described_class.delete_index
- expect(Search::Client.indices.exists(index: described_class::INDEX_NAME)).to eq(false)
- end
-
- it "deletes an elasticsearch index with name argument" do
- other_name = "random"
- described_class.create_index(index_name: other_name)
- expect(Search::Client.indices.exists(index: other_name)).to eq(true)
-
- described_class.delete_index(index_name: other_name)
- expect(Search::Client.indices.exists(index: other_name)).to eq(false)
- end
- end
-
- describe "::add_alias" do
- it "adds alias INDEX_ALIAS to elasticsearch index with INDEX_NAME" do
- Search::Client.indices.delete_alias(index: described_class::INDEX_NAME, name: described_class::INDEX_ALIAS)
- expect(Search::Client.indices.exists(index: described_class::INDEX_ALIAS)).to eq(false)
- described_class.add_alias
- expect(Search::Client.indices.exists(index: described_class::INDEX_ALIAS)).to eq(true)
- end
-
- it "adds custom alias to elasticsearch index with INDEX_NAME" do
- other_alias = "random"
- expect(Search::Client.indices.exists(index: other_alias)).to eq(false)
- described_class.add_alias(index_name: described_class::INDEX_NAME, index_alias: other_alias)
- expect(Search::Client.indices.exists(index: other_alias)).to eq(true)
- end
- end
-
- describe "::update_mappings" do
- it "updates index mappings" do
- other_name = "index_name"
- allow(Search::Client.indices).to receive(:put_mapping)
-
- described_class.update_mappings(index_alias: other_name)
- expect(Search::Client.indices).to have_received(:put_mapping).with(
- index: other_name, body: described_class::MAPPINGS,
- )
- end
- end
-end
diff --git a/spec/services/search/chat_channel_membership_spec.rb b/spec/services/search/chat_channel_membership_spec.rb
deleted file mode 100644
index 3914ff364..000000000
--- a/spec/services/search/chat_channel_membership_spec.rb
+++ /dev/null
@@ -1,148 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::ChatChannelMembership, type: :service do
- describe "::search_documents", elasticsearch: "ChatChannelMembership" do
- let(:user) { create(:user) }
- let(:chat_channel_membership1) { create(:chat_channel_membership, user_id: user.id) }
- let(:chat_channel_membership2) { create(:chat_channel_membership, user_id: user.id) }
-
- it "parses chat_channel_membership document hits from search response" do
- mock_search_response = { "hits" => { "hits" => {} } }
- allow(described_class).to receive(:search) { mock_search_response }
- described_class.search_documents(params: { user_id: 1 })
- expect(described_class).to have_received(:search).with(body: a_kind_of(Hash))
- end
-
- context "with a query" do
- it "searches by channel_text" do
- allow(chat_channel_membership1).to receive(:channel_text).and_return("a name")
- allow(chat_channel_membership2).to receive(:channel_text).and_return("another name and slug")
- index_documents([chat_channel_membership1, chat_channel_membership2])
- name_params = { size: 5, channel_text: "name", user_id: [user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: name_params)
- expect(chat_channel_membership_docs.count).to eq(2)
- doc_ids = chat_channel_membership_docs.map { |t| t["id"] }
- expect(doc_ids).to include(chat_channel_membership1.id, chat_channel_membership2.id)
- end
- end
-
- context "with a filter" do
- it "searches by viewable_by" do
- new_user = create(:user)
- chat_channel_membership3 = create(:chat_channel_membership, user_id: new_user.id)
- index_documents([chat_channel_membership1, chat_channel_membership2, chat_channel_membership3])
- params = { size: 5, user_id: [new_user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: params)
- expect(chat_channel_membership_docs.count).to eq(1)
- expect(chat_channel_membership_docs.first["id"]).to eq(chat_channel_membership3.id)
- end
-
- it "searches by channel_status" do
- allow(chat_channel_membership1).to receive(:channel_status).and_return("popping")
- index_documents([chat_channel_membership1, chat_channel_membership2])
- params = { size: 5, channel_status: "popping", user_id: [user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: params)
- expect(chat_channel_membership_docs.count).to eq(1)
- expect(chat_channel_membership_docs.first["id"]).to eq(chat_channel_membership1.id)
- end
-
- it "searches by channel_type" do
- allow(chat_channel_membership2).to receive(:channel_type).and_return("invite_only")
- index_documents([chat_channel_membership1, chat_channel_membership2])
- params = { size: 5, channel_type: "invite_only", user_id: [user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: params)
- expect(chat_channel_membership_docs.count).to eq(1)
- expect(chat_channel_membership_docs.first["id"]).to eq(chat_channel_membership2.id)
- end
-
- it "only returns active status memberships" do
- chat_channel_membership1.update(status: "inactive")
- chat_channel_membership2.update(status: "active")
- index_documents([chat_channel_membership1, chat_channel_membership2])
- params = { size: 5, user_id: [user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: params)
- expect(chat_channel_membership_docs.count).to eq(1)
- expect(chat_channel_membership_docs.first["id"]).to eq(chat_channel_membership2.id)
- end
- end
-
- context "with a query and filter" do
- it "searches by channel_text and status" do
- allow(chat_channel_membership1).to receive(:channel_text).and_return("a name")
- allow(chat_channel_membership2).to receive(:channel_text).and_return("another name")
- chat_channel_membership1.update(status: "active")
- chat_channel_membership2.update(status: "inactive")
- index_documents([chat_channel_membership1, chat_channel_membership2])
- name_params = { size: 5, channel_text: "name", status: "active", user_id: [user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: name_params)
- expect(chat_channel_membership_docs.count).to eq(1)
- doc_ids = chat_channel_membership_docs.map { |t| t["id"] }
- expect(doc_ids).to include(chat_channel_membership1.id)
- end
- end
-
- it "sorts documents for given field" do
- allow(chat_channel_membership1).to receive(:channel_type).and_return("not_direct")
- allow(chat_channel_membership2).to receive(:channel_type).and_return("direct")
- index_documents([chat_channel_membership1, chat_channel_membership2])
- params = { size: 5, sort_by: "channel_type", sort_direction: "asc", user_id: [user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: params)
- expect(chat_channel_membership_docs.count).to eq(2)
- expect(chat_channel_membership_docs.first["id"]).to eq(chat_channel_membership2.id)
- expect(chat_channel_membership_docs.last["id"]).to eq(chat_channel_membership1.id)
- end
-
- it "sorts documents by channel_last_message_at by default" do
- allow(chat_channel_membership1).to receive(:channel_last_message_at).and_return(Time.current)
- allow(chat_channel_membership2).to receive(:channel_last_message_at).and_return(1.year.ago)
- index_documents([chat_channel_membership1, chat_channel_membership2])
- params = { size: 5, user_id: [user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: params)
- expect(chat_channel_membership_docs.count).to eq(2)
- expect(chat_channel_membership_docs.first["id"]).to eq(chat_channel_membership1.id)
- expect(chat_channel_membership_docs.last["id"]).to eq(chat_channel_membership2.id)
- end
-
- it "will return a set number of docs based on pagination params" do
- index_documents([chat_channel_membership1, chat_channel_membership2])
- params = { page: 0, per_page: 1, user_id: [user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: params)
- expect(chat_channel_membership_docs.count).to eq(1)
- end
-
- it "paginates the results" do
- allow(chat_channel_membership1).to receive(:channel_last_message_at).and_return(Time.current)
- allow(chat_channel_membership2).to receive(:channel_last_message_at).and_return(1.year.ago)
- index_documents([chat_channel_membership1, chat_channel_membership2])
- first_page_params = { page: 0, per_page: 1, sort_by: "channel_last_message_at", order: "dsc", user_id: [user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: first_page_params)
- expect(chat_channel_membership_docs.first["id"]).to eq(chat_channel_membership1.id)
-
- second_page_params = { page: 1, per_page: 1, sort_by: "channel_last_message_at", order: "dsc",
- user_id: [user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: second_page_params)
- expect(chat_channel_membership_docs.first["id"]).to eq(chat_channel_membership2.id)
- end
-
- it "returns an empty Array if no results are found" do
- allow(chat_channel_membership1).to receive(:channel_last_message_at).and_return(Time.current)
- allow(chat_channel_membership2).to receive(:channel_last_message_at).and_return(1.year.ago)
- index_documents([chat_channel_membership1, chat_channel_membership2])
- params = { page: 3, per_page: 1, user_id: [user.id] }
-
- chat_channel_membership_docs = described_class.search_documents(params: params)
- expect(chat_channel_membership_docs).to eq([])
- end
- end
-end
diff --git a/spec/services/search/cluster_spec.rb b/spec/services/search/cluster_spec.rb
deleted file mode 100644
index 6ae6433b4..000000000
--- a/spec/services/search/cluster_spec.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::Cluster, type: :service do
- describe "::recreate_indexes" do
- it "destroys and sets up indexes" do
- allow(described_class).to receive(:delete_indexes)
- allow(described_class).to receive(:setup_indexes)
-
- described_class.recreate_indexes
- expect(described_class).to have_received(:delete_indexes)
- expect(described_class).to have_received(:setup_indexes)
- end
- end
-
- describe "::setup_indexes" do
- it "creates, adds aliases and updates mappings for indexes" do
- allow(described_class).to receive(:create_indexes)
- allow(described_class).to receive(:add_aliases)
- allow(described_class).to receive(:update_mappings)
-
- described_class.setup_indexes
- expect(described_class).to have_received(:create_indexes)
- expect(described_class).to have_received(:add_aliases)
- expect(described_class).to have_received(:update_mappings)
- end
- end
-
- describe "::create_indexes" do
- it "calls create_index for each search class" do
- allow(Search::Client.indices).to receive(:exists).and_return(false)
- described_class::SEARCH_CLASSES.each do |search_class|
- allow(search_class).to receive(:create_index)
- end
- described_class.create_indexes
- expect(described_class::SEARCH_CLASSES).to all(have_received(:create_index))
- end
- end
-
- describe "::update_indexes" do
- it "calls update_index for each search class" do
- described_class::SEARCH_CLASSES.each do |search_class|
- allow(search_class).to receive(:update_index)
- end
- described_class.update_indexes
- expect(described_class::SEARCH_CLASSES).to all(have_received(:update_index))
- end
- end
-
- describe "::delete_indexes" do
- it "calls delete_index for each search class" do
- allow(Search::Client.indices).to receive(:exists).and_return(true)
- described_class::SEARCH_CLASSES.each do |search_class|
- allow(search_class).to receive(:delete_index)
- end
- described_class.delete_indexes
- expect(described_class::SEARCH_CLASSES).to all(have_received(:delete_index))
- end
- end
-
- describe "::add_aliases" do
- it "calls add_alias for each search class" do
- described_class::SEARCH_CLASSES.each do |search_class|
- allow(search_class).to receive(:add_alias)
- end
- described_class.add_aliases
- expect(described_class::SEARCH_CLASSES).to all(have_received(:add_alias))
- end
- end
-
- describe "::update_mappings" do
- it "calls update_mappings for each search class" do
- described_class::SEARCH_CLASSES.each do |search_class|
- allow(search_class).to receive(:update_mappings)
- end
- described_class.update_mappings
- expect(described_class::SEARCH_CLASSES).to all(have_received(:update_mappings))
- end
- end
-
- describe "::update_settings" do
- it "updates cluster settings" do
- described_class.update_settings
- cluster_settings = Search::Client.cluster.get_settings
- auto_create_setting = cluster_settings.dig("persistent", "action", "auto_create_index")
- expect(auto_create_setting).to eq("false")
- end
- end
-end
diff --git a/spec/services/search/feed_content_spec.rb b/spec/services/search/feed_content_spec.rb
deleted file mode 100644
index 1670603f1..000000000
--- a/spec/services/search/feed_content_spec.rb
+++ /dev/null
@@ -1,224 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::FeedContent, type: :service do
- it "defines INDEX_NAME, INDEX_ALIAS, and MAPPINGS", :aggregate_failures do
- expect(described_class::INDEX_NAME).not_to be_nil
- expect(described_class::INDEX_ALIAS).not_to be_nil
- expect(described_class::MAPPINGS).not_to be_nil
- end
-
- describe "::search_documents", elasticsearch: "FeedContent" do
- let(:article1) { create(:article, published_at: 1.day.ago) }
- let(:article2) { create(:article, published_at: 2.days.ago) }
- let(:article3) { create(:article, published_at: Time.current) }
-
- it "parses feed content document hits from search response" do
- mock_search_response = { "hits" => { "hits" => {} } }
- allow(described_class).to receive(:search) { mock_search_response }
- described_class.search_documents(params: {})
- expect(described_class).to have_received(:search).with(body: a_kind_of(Hash))
- end
-
- it "returns highlighted fields" do
- allow(article1).to receive(:body_text).and_return("I love ruby")
- allow(article2).to receive(:body_text).and_return("Ruby Tuesday is love")
- index_documents([article1, article2])
- query_params = { size: 5, search_fields: "love ruby" }
-
- feed_docs = described_class.search_documents(params: query_params)
- expect(feed_docs.count).to eq(2)
- doc_highlights = feed_docs.map { |t| t.dig("highlight", "body_text") }.flatten
- expect(doc_highlights).to include("I love ruby",
- "Ruby Tuesday is love")
- end
-
- it "returns fields necessary for the view" do
- allow(article1).to receive(:flare_tag).and_return(name: "help", bg_color_hex: nil, text_color_hex: nil)
- view_keys = %w[
- id title path class_name cloudinary_video_url comments_count flare_tag tag_list user_id user
- published_at_int published_timestamp readable_publish_date
- ]
- flare_tag_keys = %w[name bg_color_hex text_color_hex]
- user_keys = %w[username name profile_image_90]
- podcast_keys = %w[slug image_url title]
- index_documents([article1])
-
- feed_doc = described_class.search_documents(params: { size: 1 }).first
- expect(feed_doc.keys).to include(*view_keys)
- expect(feed_doc["user"].keys).to include(*user_keys)
- expect(feed_doc["flare_tag"].keys).to include(*flare_tag_keys)
- expect(feed_doc["podcast"].keys).to include(*podcast_keys)
- end
-
- context "with chronological sorting specified" do
- before do
- allow(article1).to receive(:title).and_return("Ruby Slippers")
- allow(article2).to receive(:title).and_return("Ruby Tuesday")
- allow(article3).to receive(:title).and_return("Just Ruby")
- end
-
- it "sorts articles from newest to oldest" do
- index_documents([article1, article2, article3])
- query_params = { size: 5, search_fields: "ruby", sort_by: "published_at", sort_direction: "desc" }
-
- titles_in_order = described_class.search_documents(params: query_params).map { |doc| doc["title"] }
-
- expect(titles_in_order).to eq ["Just Ruby", "Ruby Slippers", "Ruby Tuesday"]
- end
-
- it "sorts articles from oldest to newest" do
- index_documents([article1, article2, article3])
- query_params = { size: 5, search_fields: "ruby", sort_by: "published_at", sort_direction: "asc" }
-
- titles_in_order = described_class.search_documents(params: query_params).map { |doc| doc["title"] }
-
- expect(titles_in_order).to eq ["Ruby Tuesday", "Ruby Slippers", "Just Ruby"]
- end
- end
-
- context "with a query" do
- it "searches by search_fields" do
- allow(article1).to receive(:title).and_return("ruby")
- allow(article2).to receive(:body_text).and_return("Ruby Tuesday")
- index_documents([article1, article2])
- query_params = { size: 5, search_fields: "ruby" }
-
- feed_docs = described_class.search_documents(params: query_params)
- expect(feed_docs.count).to eq(2)
- doc_ids = feed_docs.map { |t| t["id"] }
- expect(doc_ids).to include(article1.id, article2.id)
- end
-
- # Skipped because this seems inconsistent
- xit "bumps scores for words closer together" do
- allow(article1).to receive(:body_text).and_return("Ruby I dont know maybe is cool")
- allow(article2).to receive(:body_text).and_return("Ruby is cool I dont know maybe")
- index_documents([article1, article2])
- query_params = { size: 5, search_fields: "ruby is cool" }
-
- feed_docs = described_class.search_documents(params: query_params)
- expect(feed_docs.count).to eq(2)
- doc_ids = feed_docs.map { |t| t["id"] }
- expect(doc_ids).to eq([article2.id, article1.id])
- end
- end
-
- context "with a filter term" do
- it "filters by tag names" do
- article1.tags << create(:tag, name: "ruby")
- article2.tags << create(:tag, name: "python")
- index_documents([article1, article2])
- query_params = { size: 5, tag_names: "ruby" }
-
- feed_docs = described_class.search_documents(params: query_params)
- expect(feed_docs.count).to eq(1)
- doc_ids = feed_docs.map { |t| t["id"] }
- expect(doc_ids).to include(article1.id)
- end
-
- it "filters by multiple tag names when tag_boolean_mode is set to all" do
- tag_one = create(:tag)
- tag_two = create(:tag)
- article1.tags << tag_one
- article2.tags << tag_two
- article2.tags << tag_one
- index_documents([article1, article2])
- query_params = {
- tag_names: [tag_one.name, tag_two.name],
- tag_boolean_mode: "all"
- }
-
- feed_docs = described_class.search_documents(params: query_params)
- expect(feed_docs.count).to eq(1)
- doc_ids = feed_docs.map { |t| t["id"] }
- expect(doc_ids).to include(article2.id)
- end
-
- it "filters by user_id" do
- index_documents([article1, article2])
- query_params = { size: 5, user_id: article1.user_id }
-
- feed_docs = described_class.search_documents(params: query_params)
- expect(feed_docs.count).to eq(1)
- doc_ids = feed_docs.map { |t| t["id"] }
- expect(doc_ids).to include(article1.id)
- end
-
- it "filters by approved" do
- article1.update(approved: false)
- article2.update(approved: true)
- index_documents([article1, article2])
- query_params = { size: 5, approved: true }
-
- feed_docs = described_class.search_documents(params: query_params)
- expect(feed_docs.count).to eq(1)
- doc_ids = feed_docs.map { |t| t["id"] }
- expect(doc_ids).to include(article2.id)
- end
-
- it "filters by class_name" do
- pde = create(:podcast_episode)
- index_documents([pde, article1, article2])
- query_params = { size: 5, class_name: "PodcastEpisode" }
-
- feed_docs = described_class.search_documents(params: query_params)
- expect(feed_docs.count).to eq(1)
- doc_ids = feed_docs.map { |t| t["id"] }
- expect(doc_ids).to include(pde.id)
- end
-
- it "filters by id" do
- index_documents([article1, article2])
- query_params = { size: 5, id: ["article_#{article1.id}"] }
-
- feed_docs = described_class.search_documents(params: query_params)
- expect(feed_docs.count).to eq(1)
- doc_ids = feed_docs.map { |t| t["id"] }
- expect(doc_ids).to include(article1.id)
- expect(doc_ids).not_to include(article2.id)
- end
- end
-
- context "with range keys" do
- it "searches by published_at" do
- article1.update(published_at: 1.year.ago)
- article2.update(published_at: 1.month.ago)
- index_documents([article1, article2])
- query_params = { size: 5, published_at: { gte: 2.months.ago.iso8601 } }
-
- feed_docs = described_class.search_documents(params: query_params)
- expect(feed_docs.count).to eq(1)
- doc_ids = feed_docs.map { |t| t["id"] }
- expect(doc_ids).to include(article2.id)
- end
- end
-
- context "with default sorting" do
- it "sorts by Elasticsearch _score which is weighted based on article score" do
- ruby_tag = create(:tag, name: "ruby")
- allow(article1).to receive(:score).and_return(200)
- article1.tags << ruby_tag
- allow(article2).to receive(:score).and_return(1500)
- article2.tags << ruby_tag
- index_documents([article1, article2])
- query_params = { size: 5, search_fields: "ruby" }
-
- feed_docs = described_class.search_documents(params: query_params)
- doc_ids = feed_docs.map { |t| t["id"] }
- expect(doc_ids).to eq([article2.id, article1.id])
- end
- end
- end
-
- describe "document counts", elasticsearch: "FeedContent" do
- it "returns counts for each document class" do
- article = create(:article)
- comment = create(:comment)
- pde = create(:podcast_episode)
- index_documents([article, comment, pde])
- described_class::INCLUDED_CLASS_NAMES.each do |class_name|
- expect(described_class.public_send("#{class_name.underscore.pluralize}_document_count")).to eq(1)
- end
- end
- end
-end
diff --git a/spec/services/search/listing_spec.rb b/spec/services/search/listing_spec.rb
deleted file mode 100644
index c19865167..000000000
--- a/spec/services/search/listing_spec.rb
+++ /dev/null
@@ -1,178 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::Listing, type: :service do
- describe "::search_documents", elasticsearch: "Listing" do
- let(:listing) { create(:listing) }
-
- it "parses listing document hits from search response" do
- mock_search_response = { "hits" => { "hits" => {} } }
- allow(described_class).to receive(:search) { mock_search_response }
- described_class.search_documents(params: {})
- expect(described_class).to have_received(:search).with(body: a_kind_of(Hash))
- end
-
- context "with a query" do
- # listing_search is a copy_to field including:
- # body_markdown, location, slug, tags, and title
- it "searches by listing_search" do
- listing1 = create(:listing, body_markdown: "# body_markdown with test")
- listing2 = create(:listing, location: "a test location")
- listing3 = create(:listing, title: "this test title is testing slug")
- listing4 = create(:listing, tag_list: ["test"])
- listing5 = create(:listing, title: "a test title")
- listings = [listing1, listing2, listing3, listing4, listing5]
- index_documents(listings)
-
- listing_docs = described_class.search_documents(params: { size: 5, listing_search: "test" })
- expect(listing_docs.count).to eq(5)
- expect(listing_docs.map { |t| t["id"] }).to match_array(listings.map(&:id))
- end
- end
-
- context "with a term filter" do
- it "searches by category" do
- new_category = create(:listing_category, :cfp)
- listing.update(listing_category_id: new_category.id)
- index_documents(listing)
- params = { size: 5, category: new_category.slug }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs.count).to eq(1)
- expect(listing_docs.first["id"]).to eq(listing.id)
- end
-
- it "searches by contact_via_connect" do
- listing.update(contact_via_connect: true)
- index_documents(listing)
- params = { size: 5, contact_via_connect: true }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs.count).to eq(1)
- expect(listing_docs.first["id"]).to eq(listing.id)
- end
-
- it "searches by location" do
- listing.update(location: "a location")
- index_documents(listing)
- params = { size: 5, location: "location" }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs.count).to eq(1)
- expect(listing_docs.first["id"]).to eq(listing.id)
- end
-
- it "searches by slug" do
- slug_listing = create(:listing, title: "A slug is created from this title in a callback")
- index_documents(slug_listing)
- params = { size: 5, slug: "slug" }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs.count).to eq(1)
- expect(listing_docs.first["id"]).to eq(slug_listing.id)
- end
-
- it "searches by tags" do
- listing.update(tag_list: %w[beginners career])
- index_documents(listing)
- params = { size: 5, tags: "career" }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs.count).to eq(1)
- expect(listing_docs.first["id"]).to eq(listing.id)
- end
-
- it "searches by title" do
- listing.update(title: "An Amazing Title")
- index_documents(listing)
- params = { size: 5, title: "amazing" }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs.count).to eq(1)
- expect(listing_docs.first["id"]).to eq(listing.id)
- end
-
- it "searches by user_id" do
- index_documents(listing)
- params = { size: 5, user_id: listing.user_id }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs.count).to eq(1)
- expect(listing_docs.first["id"]).to eq(listing.id)
- end
-
- it "searches by bumped_at" do
- listing.update(bumped_at: 1.day.from_now)
- index_documents(listing)
- params = { size: 5, bumped_at: { gt: Time.current } }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs.count).to eq(1)
- expect(listing_docs.first["id"]).to eq(listing.id)
- end
-
- it "searches by expires_at" do
- listing.update(expires_at: 1.day.ago)
- index_documents(listing)
- params = { size: 5, expires_at: { lt: Time.current } }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs.count).to eq(1)
- expect(listing_docs.first["id"]).to eq(listing.id)
- end
- end
-
- it "sorts documents for a given field" do
- listing = create(:listing)
- cfp = create(:listing_category, :cfp)
- listing2 = create(:listing, listing_category_id: cfp.id)
- index_documents([listing, listing2])
- params = { size: 5, sort_by: "category", sort_direction: "asc" }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs.count).to eq(2)
- expect(listing_docs.first["id"]).to eq(listing2.id)
- expect(listing_docs.last["id"]).to eq(listing.id)
- end
-
- it "sorts documents by bumped_at by default" do
- listing.update(bumped_at: 1.year.ago)
- listing2 = create(:listing, bumped_at: Time.current)
- index_documents([listing, listing2])
- params = { size: 5 }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs.count).to eq(2)
- expect(listing_docs.first["id"]).to eq(listing2.id)
- expect(listing_docs.last["id"]).to eq(listing.id)
- end
-
- it "paginates the results" do
- listing.update(bumped_at: 1.year.ago)
- listing2 = create(:listing, bumped_at: Time.current)
- index_documents([listing, listing2])
- first_page_params = { page: 0, per_page: 1, sort_by: "bumped_at", order: "dsc" }
-
- listing_docs = described_class.search_documents(params: first_page_params)
- expect(listing_docs.first["id"]).to eq(listing2.id)
-
- second_page_params = { page: 1, per_page: 1, sort_by: "bumped_at", order: "dsc" }
-
- listing_docs = described_class.search_documents(params: second_page_params)
- expect(listing_docs.first["id"]).to eq(listing.id)
- end
-
- it "returns an empty Array if no results are found" do
- jobs_category = create(:listing_category, :jobs)
- listing.update(listing_category: jobs_category)
-
- cfp_category = create(:listing_category, :cfp)
- listing2 = create(:listing,
- listing_category: cfp_category)
- index_documents([listing, listing2])
- params = { page: 3, per_page: 1 }
-
- listing_docs = described_class.search_documents(params: params)
- expect(listing_docs).to eq([])
- end
- end
-end
diff --git a/spec/services/search/query_builders/chat_channel_membership_spec.rb b/spec/services/search/query_builders/chat_channel_membership_spec.rb
deleted file mode 100644
index 26afaaeda..000000000
--- a/spec/services/search/query_builders/chat_channel_membership_spec.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::QueryBuilders::ChatChannelMembership, type: :service do
- describe "::initialize" do
- it "sets params" do
- filter_params = { foo: "bar" }
- filter = described_class.new(params: filter_params)
- expect(filter.params).to include(filter_params)
- end
-
- it "builds query body" do
- filter = described_class.new(params: {})
- expect(filter.body).not_to be_nil
- end
- end
-
- describe "#as_hash" do
- it "applies FILTER_KEYS from params" do
- params = { channel_status: "active", channel_type: "direct", user_id: 1 }
- filter = described_class.new(params: params)
- expected_filters = [
- { "term" => { "channel_status" => "active" } },
- { "term" => { "channel_type" => "direct" } },
- { "terms" => { "status" => %w[active joining_request] } },
- { "terms" => { "viewable_by" => 1 } },
- ]
- expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(expected_filters)
- end
-
- it "applies QUERY_KEYS from params" do
- params = { channel_text: "a_name" }
- query = described_class.new(params: params)
- expected_query = [{
- "simple_query_string" => {
- "query" => "a_name*", "fields" => [:channel_text], "lenient" => true, "analyze_wildcard" => true
- }
- }]
- expect(query.as_hash.dig("query", "bool", "must")).to match_array(expected_query)
- end
-
- it "applies QUERY_KEYS and FILTER_KEYS from params" do
- params = { channel_text: "a_name", channel_status: "active", user_id: 1 }
- query = described_class.new(params: params)
- expected_query = [{
- "simple_query_string" => {
- "query" => "a_name*", "fields" => [:channel_text], "lenient" => true, "analyze_wildcard" => true
- }
- }]
- expected_filters = [
- { "term" => { "channel_status" => "active" } },
- { "terms" => { "status" => %w[active joining_request] } },
- { "terms" => { "viewable_by" => 1 } },
- ]
- expect(query.as_hash.dig("query", "bool", "must")).to match_array(expected_query)
- expect(query.as_hash.dig("query", "bool", "filter")).to match_array(expected_filters)
- end
-
- it "always applies viewable_by and status params" do
- params = { user_id: 1 }
- filter = described_class.new(params: params)
- expected_filters = [
- { "terms" => { "status" => %w[active joining_request] } },
- { "terms" => { "viewable_by" => 1 } },
- ]
- expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(expected_filters)
- end
-
- it "always applies channel discoverable and status params" do
- allow(Settings::Mascot).to receive(:mascot_user_id).and_return(2)
-
- params = { user_id: Settings::Mascot.mascot_user_id }
- filter = described_class.new(params: params)
- expected_filters = [
- { "terms" => { "status" => %w[active joining_request] } },
- { "terms" => { "viewable_by" => Settings::Mascot.mascot_user_id } },
- ]
- expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(expected_filters)
- end
-
- it "ignores params we dont support" do
- params = { not_supported: "direct", user_id: 1 }
- filter = described_class.new(params: params)
- expected_filters = [
- { "terms" => { "status" => %w[active joining_request] } },
- { "terms" => { "viewable_by" => 1 } },
- ]
- expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(expected_filters)
- end
-
- it "sets default params when not present" do
- filter = described_class.new(params: {})
- expect(filter.as_hash["sort"]).to eq("channel_last_message_at" => "desc")
- expect(filter.as_hash["size"]).to eq(0)
- end
-
- it "allows default params to be overriden" do
- params = { sort_by: "status", sort_direction: "asc", size: 20 }
- filter = described_class.new(params: params)
- expect(filter.as_hash["sort"]).to eq("status" => "asc")
- expect(filter.as_hash["size"]).to eq(20)
- end
- end
-end
diff --git a/spec/services/search/query_builders/feed_content_spec.rb b/spec/services/search/query_builders/feed_content_spec.rb
deleted file mode 100644
index 57bdf848e..000000000
--- a/spec/services/search/query_builders/feed_content_spec.rb
+++ /dev/null
@@ -1,130 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::QueryBuilders::FeedContent, type: :service do
- describe "::initialize" do
- it "sets params" do
- filter_params = { foo: "bar" }
- filter = described_class.new(params: filter_params)
- expect(filter.params).to include(filter_params)
- end
-
- it "builds query body" do
- filter = described_class.new(params: {})
- expect(filter.body).not_to be_nil
- end
-
- it "builds query body with html encoder" do
- filter = described_class.new(params: {})
- expect(filter.body).to include("highlight" => hash_including("encoder" => "html"))
- end
-
- it "sets published to true" do
- filter = described_class.new(params: {})
- expect(filter.params).to include(published: true)
- end
- end
-
- describe "#as_hash" do
- let(:query_fields) { described_class::QUERY_KEYS[:search_fields] }
- let(:expected_query) do
- [{
- "simple_query_string" => {
- "query" => "test",
- "fields" => query_fields,
- "lenient" => true,
- "analyze_wildcard" => true,
- "minimum_should_match" => 2
- }
- }]
- end
- let(:expected_match_phrase) do
- [{
- "match_phrase" => {
- "search_fields" => {
- "query" => "test",
- "slop" => 0
- }
- }
- }]
- end
-
- it "applies QUERY_KEYS from params" do
- params = { search_fields: "test" }
- filter = described_class.new(params: params)
- expect(search_bool_clause(filter)["must"]).to match_array(expected_query)
- expect(search_bool_clause(filter)["should"]).to match_array(expected_match_phrase)
- expect(search_bool_clause(filter)["minimum_should_match"]).to eq(0)
- end
-
- it "applies TERM_KEYS from params" do
- params = { approved: true, tag_names: "beginner", user_id: 777, class_name: "Article" }
- filter = described_class.new(params: params)
- expected_filters = [
- { "terms" => { "approved" => [true] } },
- { "terms" => { "tags.name" => ["beginner"] } },
- { "terms" => { "user.id" => [777] } },
- { "terms" => { "class_name" => ["Article"] } },
- { "terms" => { "published" => [true] } },
- ]
- expect(search_bool_clause(filter)["filter"]).to match_array(expected_filters)
- end
-
- it "applies RANGE_KEYS from params" do
- Timecop.freeze(Time.current) do
- params = { published_at: { lte: Time.current } }
- filter = described_class.new(params: params)
- expected_filters = [
- { "range" => { "published_at" => { lte: Time.current } } },
- { "terms" => { "published" => [true] } },
- ]
- expect(search_bool_clause(filter)["filter"]).to match_array(expected_filters)
- end
- end
-
- it "applies QUERY_KEYS, TERM_KEYS, and RANGE_KEYS from params" do
- Timecop.freeze(Time.current) do
- params = { search_fields: "ruby", published_at: { lte: Time.current }, tag_names: "cfp" }
- filter = described_class.new(params: params)
- expected_query = [{
- "simple_query_string" => { "query" => "ruby", "fields" => query_fields, "lenient" => true,
- "analyze_wildcard" => true, "minimum_should_match" => 2 }
- }]
- expected_filters = [
- { "range" => { "published_at" => { lte: Time.current } } },
- { "terms" => { "tags.name" => ["cfp"] } },
- { "terms" => { "published" => [true] } },
- ]
- expect(search_bool_clause(filter)["must"]).to match_array(expected_query)
- expect(search_bool_clause(filter)["filter"]).to match_array(expected_filters)
- end
- end
-
- it "ignores params we don't support" do
- params = { not_supported: "trash", search_fields: "cfp" }
- filter = described_class.new(params: params)
- expected_query = [{
- "simple_query_string" => {
- "query" => "cfp", "fields" => query_fields, "lenient" => true,
- "analyze_wildcard" => true, "minimum_should_match" => 2
- }
- }]
- expect(search_bool_clause(filter)["must"]).to match_array(expected_query)
- end
-
- it "allows default params to be overriden" do
- params = { sort_by: "published_at", sort_direction: "asc", size: 20 }
- filter = described_class.new(params: params).as_hash
- expect(filter["sort"]).to eq("published_at" => "asc")
- expect(filter["size"]).to eq(20)
- end
-
- it "correctly sets default sort" do
- filter = described_class.new(params: {}).as_hash
- expect(filter["sort"]).to eq(described_class::DEFAULT_PARAMS[:sort])
- end
- end
-
- def search_bool_clause(query_builder)
- query_builder.as_hash.dig("query", "function_score", "query", "bool")
- end
-end
diff --git a/spec/services/search/query_builders/listing_spec.rb b/spec/services/search/query_builders/listing_spec.rb
deleted file mode 100644
index 911d50ec0..000000000
--- a/spec/services/search/query_builders/listing_spec.rb
+++ /dev/null
@@ -1,114 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::QueryBuilders::Listing, type: :service do
- describe "::intialize" do
- it "sets params" do
- filter_params = { foo: "bar" }
- filter = described_class.new(params: filter_params)
- expect(filter.params).to include(filter_params)
- end
-
- it "builds query body" do
- filter = described_class.new(params: {})
- expect(filter.body).not_to be_nil
- end
- end
-
- describe "#as_hash" do
- it "applies TERM_KEYS from params" do
- params = { category: "cfp", tags: %w[beginner intermediate professional], contact_via_connect: false }
- filter = described_class.new(params: params)
- exepcted_filters = [
- { "terms" => { "category" => ["cfp"] } },
- { "terms" => { "tags" => %w[beginner intermediate professional] } },
- { "terms" => { "contact_via_connect" => [false] } },
- { "terms" => { "published" => [true] } },
- ]
- expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(exepcted_filters)
- end
-
- it "applies TERM_KEYS from params with boolean mode" do
- params = { category: "cfp", tags: %w[beginner intermediate professional], contact_via_connect: false,
- tag_boolean_mode: "all" }
- filter = described_class.new(params: params)
- expected_filters = [
- { "terms" => { "category" => ["cfp"] } },
- { "terms" => { "tags" => ["beginner"] } },
- { "terms" => { "tags" => ["intermediate"] } },
- { "terms" => { "tags" => ["professional"] } },
- { "terms" => { "contact_via_connect" => [false] } },
- { "terms" => { "published" => [true] } },
- ]
- expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(expected_filters)
- end
-
- it "applies RANGE_KEYS from params" do
- Timecop.freeze(Time.current) do
- params = { bumped_at: Time.current, expires_at: 1.day.from_now }
- filter = described_class.new(params: params)
- expected_filters = [
- { "range" => { "bumped_at" => Time.current } },
- { "range" => { "expires_at" => 1.day.from_now } },
- { "terms" => { "published" => [true] } },
- ]
- expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(expected_filters)
- end
- end
-
- it "applies QUERY_KEYS from params" do
- params = { listing_search: "test" }
- filter = described_class.new(params: params)
- expected_query = [{
- "simple_query_string" => {
- "query" => "test*",
- "fields" => [:listing_search],
- "lenient" => true,
- "analyze_wildcard" => true
- }
- }]
- expect(filter.as_hash.dig("query", "bool", "must")).to match_array(expected_query)
- end
-
- it "applies QUERY_KEYS, TERM_KEYS, and RANGE_KEYS from params" do
- Timecop.freeze(Time.current) do
- params = { listing_search: "test", bumped_at: Time.current, category: "cfp" }
- filter = described_class.new(params: params)
- expected_query = [{
- "simple_query_string" => { "query" => "test*", "fields" => [:listing_search], "lenient" => true,
- "analyze_wildcard" => true }
- }]
- expected_filters = [
- { "range" => { "bumped_at" => Time.current } },
- { "terms" => { "category" => ["cfp"] } },
- { "terms" => { "published" => [true] } },
- ]
- expect(filter.as_hash.dig("query", "bool", "must")).to match_array(expected_query)
- expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(expected_filters)
- end
- end
-
- it "ignores params we don't support" do
- params = { not_supported: "trash", category: "cfp" }
- filter = described_class.new(params: params)
- expected_filters = [
- { "terms" => { "category" => ["cfp"] } },
- { "terms" => { "published" => [true] } },
- ]
- expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(expected_filters)
- end
-
- it "sets default params when not present" do
- filter = described_class.new(params: {}).as_hash
- expect(filter["sort"]).to eq("bumped_at" => "desc")
- expect(filter["size"]).to eq(0)
- expect(filter.dig("query", "bool", "filter")).to match_array([{ "terms" => { "published" => [true] } }])
- end
-
- it "allows default params to be overriden" do
- params = { sort_by: "category", sort_direction: "asc", size: 20 }
- filter = described_class.new(params: params).as_hash
- expect(filter["sort"]).to eq("category" => "asc")
- expect(filter["size"]).to eq(20)
- end
- end
-end
diff --git a/spec/services/search/query_builders/user_spec.rb b/spec/services/search/query_builders/user_spec.rb
deleted file mode 100644
index 363aa907e..000000000
--- a/spec/services/search/query_builders/user_spec.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::QueryBuilders::User, type: :service do
- describe "::intialize" do
- it "sets params" do
- filter_params = { foo: "bar" }
- filter = described_class.new(params: filter_params)
- expect(filter.params).to include(filter_params)
- end
-
- it "builds query body" do
- filter = described_class.new(params: {})
- expect(filter.body).not_to be_nil
- end
- end
-
- describe "#as_hash" do
- it "applies QUERY_KEYS from params" do
- params = { search_fields: "test" }
- filter = described_class.new(params: params)
- expected_query = [{
- "simple_query_string" => {
- "query" => "test*", "fields" => [:search_fields], "lenient" => true, "analyze_wildcard" => true
- }
- }]
- expect(filter.as_hash.dig("query", "bool", "must")).to match_array(expected_query)
- end
-
- it "applies EXCLUDED_TERM_KEYS by default" do
- filter = described_class.new(params: {})
- expected_filters = [
- { "terms" => { "roles" => %w[suspended banned] } },
- ]
- expect(filter.as_hash.dig("query", "bool", "must_not")).to match_array(expected_filters)
- end
-
- it "applies EXCLUDED_TERM_KEYS and QUERY_KEYS" do
- params = { search_fields: "test" }
- filter = described_class.new(params: params)
- expected_query = [{
- "simple_query_string" => {
- "query" => "test*", "fields" => [:search_fields], "lenient" => true, "analyze_wildcard" => true
- }
- }]
- expected_filters = [
- { "terms" => { "roles" => %w[suspended banned] } },
- ]
- expect(filter.as_hash.dig("query", "bool", "must_not")).to match_array(expected_filters)
- expect(filter.as_hash.dig("query", "bool", "must")).to match_array(expected_query)
- end
-
- it "ignores params we don't support" do
- params = { not_supported: "trash", search_fields: "cfp" }
- filter = described_class.new(params: params)
- expected_query = [{
- "simple_query_string" => {
- "query" => "cfp*", "fields" => [:search_fields], "lenient" => true, "analyze_wildcard" => true
- }
- }]
- expect(filter.as_hash.dig("query", "bool", "must")).to match_array(expected_query)
- end
-
- it "allows default params to be overriden" do
- params = { sort_by: "name", sort_direction: "asc", size: 20 }
- filter = described_class.new(params: params).as_hash
- expect(filter["sort"]).to eq("name" => "asc")
- expect(filter["size"]).to eq(20)
- end
- end
-end
diff --git a/spec/services/search/reading_list_spec.rb b/spec/services/search/reading_list_spec.rb
deleted file mode 100644
index 2295199a5..000000000
--- a/spec/services/search/reading_list_spec.rb
+++ /dev/null
@@ -1,115 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::ReadingList, type: :service do
- describe "::search_documents", elasticsearch: "FeedContent" do
- let(:user) { create(:user) }
- let(:article0) { create(:article) }
- let(:article1) { create(:article) }
- let(:article2) { create(:article) }
- let(:reaction1) { create(:reaction, user: user, category: "readinglist", reactable: article1) }
- let(:reaction2) { create(:reaction, user: user, category: "readinglist", reactable: article2) }
- let(:reaction3) { create(:reaction, user: user, category: "readinglist", reactable: article0) }
- let(:query_params) { {} }
-
- before do
- reaction1
- reaction2
- end
-
- def index_documents(docs)
- index_documents_for_search_class(Array.wrap(docs), Search::FeedContent)
- end
-
- it "returns fields necessary for the view" do
- view_keys = %w[id reactable user_id]
- reactable_keys = %w[title path readable_publish_date_string tags user]
- user_keys = %w[username name profile_image_90]
- index_documents(article1)
-
- result = described_class.search_documents(params: {}, user: user)
- reaction_doc = result["reactions"].first
- expect(result["total"]).to be_present
- expect(reaction_doc.keys).to include(*view_keys)
- expect(reaction_doc["reactable"].keys).to include(*reactable_keys)
- expect(reaction_doc.dig("reactable", "user").keys).to include(*user_keys)
- end
-
- context "with a query" do
- it "searches by search_fields" do
- allow(article1).to receive(:title).and_return("ruby")
- allow(article2).to receive(:body_text).and_return("Ruby Tuesday")
- index_documents([article1, article2])
- query_params[:search_fields] = "ruby"
-
- reaction_docs = described_class.search_documents(params: query_params, user: user)["reactions"]
- expect(reaction_docs.count).to eq(2)
- doc_ids = reaction_docs.map { |t| t["id"] }
- expect(doc_ids).to include(reaction1.id, reaction2.id)
- end
- end
-
- context "with a filter term" do
- let(:tag_one) { create(:tag) }
- let(:tag_two) { create(:tag) }
-
- it "filters by tag names" do
- article1.tags << tag_one
- article2.tags << tag_two
- index_documents([article1, article2])
- query_params[:tag_names] = [tag_one.name]
-
- reaction_docs = described_class.search_documents(params: query_params, user: user)["reactions"]
- expect(reaction_docs.count).to eq(1)
- doc_ids = reaction_docs.map { |t| t["id"] }
- expect(doc_ids).to include(reaction1.id)
- expect(doc_ids).not_to include(reaction2.id)
- end
-
- it "filters by multiple tag names when tag_boolean_mode is set to all" do
- article1.tags << tag_one
- article2.tags << tag_two
- article2.tags << tag_one
- index_documents([article1, article2])
- query_params[:tag_names] = [tag_one.name, tag_two.name]
- query_params[:tag_boolean_mode] = "all"
-
- reaction_docs = described_class.search_documents(params: query_params, user: user)["reactions"]
- expect(reaction_docs.count).to eq(1)
- doc_ids = reaction_docs.map { |t| t["id"] }
- expect(doc_ids).to include(reaction2.id)
- expect(doc_ids).not_to include(reaction1.id)
- end
-
- it "filters by status" do
- reaction1.update(status: "invalid")
- index_documents([article1, article2])
- query_params[:status] = %w[valid confirmed]
-
- reaction_docs = described_class.search_documents(params: query_params, user: user)["reactions"]
- expect(reaction_docs.count).to eq(1)
- doc_ids = reaction_docs.map { |t| t["id"] }
- expect(doc_ids).to include(reaction2.id)
- end
-
- it "only returns readinglist reactions" do
- reaction1.update(category: "like")
- index_documents([article1, article2])
-
- reaction_docs = described_class.search_documents(params: query_params, user: user)["reactions"]
- expect(reaction_docs.count).to eq(1)
- doc_ids = reaction_docs.map { |t| t["id"] }
- expect(doc_ids).to include(reaction2.id)
- expect(doc_ids).not_to include(reaction1.id)
- end
- end
-
- it "sorts by reaction ID DESC" do
- reaction3
- index_documents([article0, article1, article2])
-
- reaction_docs = described_class.search_documents(params: query_params, user: user)["reactions"]
- doc_ids = reaction_docs.map { |t| t["id"] }
- expect(doc_ids).to eq([reaction3.id, reaction2.id, reaction1.id])
- end
- end
-end
diff --git a/spec/services/search/tag_spec.rb b/spec/services/search/tag_spec.rb
deleted file mode 100644
index 753b98424..000000000
--- a/spec/services/search/tag_spec.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::Tag, type: :service do
- describe "::search_documents", elasticsearch: "Tag" do
- let(:tag_doc_1) { { "name" => "tag1" } }
- let(:tag_doc_2) { { "name" => "tag2" } }
- let(:mock_search_response) do
- {
- "hits" => {
- "hits" => [
- { "_source" => tag_doc_1 },
- { "_source" => tag_doc_2 },
- ]
- }
- }
- end
-
- it "searches with name:tag" do
- tag = create(:tag, :search_indexed, name: "tag1")
-
- described_class.refresh_index
- tag_docs = described_class.search_documents("name:#{tag.name}")
- expect(tag_docs.count).to eq(1)
- expect(tag_docs).to match([
- a_hash_including("name" => tag.name),
- ])
- end
-
- it "analyzes wildcards" do
- tag1 = create(:tag, :search_indexed, name: "tag1")
- tag2 = create(:tag, :search_indexed, name: "tag2")
- tag3 = create(:tag, :search_indexed, name: "3tag")
-
- described_class.refresh_index
-
- tag_docs = described_class.search_documents("name:tag*")
- expect(tag_docs).to match([
- a_hash_including("name" => tag1.name),
- a_hash_including("name" => tag2.name),
- ])
- expect(tag_docs).not_to match(a_hash_including("name" => tag3.name))
- end
-
- it "parses tag document hits from search response" do
- allow(Search::Client).to receive(:search) { mock_search_response }
- tag_docs = described_class.search_documents("query")
- expect(tag_docs.count).to eq(2)
- expect(tag_docs).to include(tag_doc_1, tag_doc_2)
- end
-
- it "does not allow leading wildcards" do
- expect { described_class.search_documents("name:*tag") }.to raise_error(Search::Errors::Transport::BadRequest)
- end
- end
-end
diff --git a/spec/services/search/user_spec.rb b/spec/services/search/user_spec.rb
deleted file mode 100644
index 731142747..000000000
--- a/spec/services/search/user_spec.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-require "rails_helper"
-
-RSpec.describe Search::User, type: :service do
- it "defines INDEX_NAME, INDEX_ALIAS, and MAPPINGS", :aggregate_failures do
- expect(described_class::INDEX_NAME).not_to be_nil
- expect(described_class::INDEX_ALIAS).not_to be_nil
- expect(described_class::MAPPINGS).not_to be_nil
- end
-
- describe "::search_documents", elasticsearch: "User" do
- let(:user1) { create(:user) }
- let(:user2) { create(:user) }
-
- it "parses user document hits from search response" do
- mock_search_response = { "hits" => { "hits" => {} } }
- allow(described_class).to receive(:search) { mock_search_response }
- described_class.search_documents(params: {})
- expect(described_class).to have_received(:search).with(body: a_kind_of(Hash))
- end
-
- context "with a query" do
- it "searches by search_fields" do
- allow(user1).to receive(:available_for).and_return("ruby")
- allow(user2).to receive(:employer_name).and_return("Ruby Tuesday")
- index_documents([user1, user2])
- query_params = { size: 5, search_fields: "ruby" }
-
- user_docs = described_class.search_documents(params: query_params)
- expect(user_docs.count).to eq(2)
- doc_ids = user_docs.map { |t| t["id"] }
- expect(doc_ids).to include(user1.id, user2.id)
- end
-
- it "searches by a username" do
- allow(user1).to receive(:username).and_return("kyloren")
- index_documents([user1])
- query_params = { size: 5, search_fields: "kyloren" }
-
- user_docs = described_class.search_documents(params: query_params)
- expect(user_docs.count).to eq(1)
- doc_ids = user_docs.map { |t| t["id"] }
- expect(doc_ids).to include(user1.id)
- end
- end
-
- context "with a filter" do
- it "searches by excluding roles" do
- user1.add_role(:admin)
- user2.add_role(:suspended)
- index_documents([user1, user2])
- query_params = { size: 5, exclude_roles: %w[suspended banned] }
-
- user_docs = described_class.search_documents(params: query_params)
- expect(user_docs.count).to eq(1)
- doc_ids = user_docs.map { |t| t["id"] }
- expect(doc_ids).to match_array([user1.id])
- end
- end
- end
-
- describe "::search_usernames", elasticsearch: "User" do
- let(:user1) { create(:user, username: "star_wars_is_the_best") }
- let(:user2) { create(:user, username: "star_trek_is_the_best") }
-
- before do
- index_documents([user1, user2])
- end
-
- it "searches with username" do
- usernames = described_class.search_usernames(user1.username)
- expect(usernames.count).to eq(1)
- expect(usernames.map { |u| u["username"] }).to match([user1.username])
- end
-
- it "analyzes wildcards" do
- user3 = create(:user, username: "does_not_start_with_a_star")
- index_documents([user3])
-
- usernames = described_class.search_usernames("star*")
- expect(usernames.map { |u| u["username"] }).to match(
- [user1.username, user2.username],
- )
- expect(usernames.map { |u| u["username"] }).not_to include(user3.username)
- end
-
- it "does not allow leading wildcards" do
- expect { described_class.search_usernames("*star") }.to raise_error(Search::Errors::Transport::BadRequest)
- end
-
- it "limits the number of results to the value of MAX_RESULTS" do
- max_results = 1
- stub_const("Search::Postgres::Username::MAX_RESULTS", max_results)
-
- usernames = described_class.search_usernames("star*")
- expect(usernames.size).to eq(max_results)
- expect([user1.username, user2.username]).to include(usernames.first["username"])
- end
- end
-end
diff --git a/spec/services/users/delete_articles_spec.rb b/spec/services/users/delete_articles_spec.rb
index dc2ff7156..60d4584f9 100644
--- a/spec/services/users/delete_articles_spec.rb
+++ b/spec/services/users/delete_articles_spec.rb
@@ -14,14 +14,6 @@ RSpec.describe Users::DeleteArticles, type: :service do
expect(Article.find(article3.id)).to be_present
end
- it "removes article from Elasticsearch" do
- sidekiq_perform_enqueued_jobs
- expect(article.elasticsearch_doc).not_to be_nil
-
- sidekiq_perform_enqueued_jobs { described_class.call(user) }
- expect { article.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
- end
-
context "with comments" do
before do
allow(EdgeCache::BustComment).to receive(:call)
@@ -42,18 +34,5 @@ RSpec.describe Users::DeleteArticles, type: :service do
expect(EdgeCache::BustUser).to have_received(:call).with(user2).at_least(:once)
expect(EdgeCache::BustArticle).to have_received(:call).with(article)
end
-
- it "removes comments from Elasticsearch", :aggregate_failures do
- sidekiq_perform_enqueued_jobs
- comments = article.comments
- comments.each { |comment| expect(comment.elasticsearch_doc).not_to be_nil }
- sidekiq_perform_enqueued_jobs(only: Search::RemoveFromIndexWorker) do
- described_class.call(user)
- end
-
- comments.each do |comment|
- expect { comment.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
- end
- end
end
end
diff --git a/spec/services/users/delete_comments_spec.rb b/spec/services/users/delete_comments_spec.rb
index 9d1090f8b..438b39618 100644
--- a/spec/services/users/delete_comments_spec.rb
+++ b/spec/services/users/delete_comments_spec.rb
@@ -19,14 +19,6 @@ RSpec.describe Users::DeleteComments, type: :service do
expect(Comment.where(user_id: user.id).any?).to be false
end
- it "removes comments from Elasticsearch" do
- comment
- sidekiq_perform_enqueued_jobs
- expect(comment.elasticsearch_doc).not_to be_nil
- sidekiq_perform_enqueued_jobs { described_class.call(user) }
- expect { comment.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
- end
-
it "busts cache" do
described_class.call(user)
expect(EdgeCache::BustComment).to have_received(:call).with(article).at_least(:once)
diff --git a/spec/services/users/delete_spec.rb b/spec/services/users/delete_spec.rb
index 10e093cec..2f2f2a9e5 100644
--- a/spec/services/users/delete_spec.rb
+++ b/spec/services/users/delete_spec.rb
@@ -60,25 +60,6 @@ RSpec.describe Users::Delete, type: :service do
expect(audit_log.reload.user_id).to be(nil)
end
- it "removes user from Elasticsearch" do
- sidekiq_perform_enqueued_jobs { user }
- expect(user.elasticsearch_doc).not_to be_nil
- sidekiq_perform_enqueued_jobs do
- described_class.call(user)
- end
- expect { user.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
- end
-
- it "removes articles from Elasticsearch" do
- article = create(:article, user: user)
- sidekiq_perform_enqueued_jobs
- expect(article.elasticsearch_doc).not_to be_nil
- sidekiq_perform_enqueued_jobs do
- described_class.call(user)
- end
- expect { article.elasticsearch_doc }.to raise_error(Search::Errors::Transport::NotFound)
- end
-
it "deletes field tests memberships" do
create(:field_test_membership, participant_id: user.id)
diff --git a/spec/support/elasticsearch_helpers.rb b/spec/support/elasticsearch_helpers.rb
deleted file mode 100644
index 128eb05b2..000000000
--- a/spec/support/elasticsearch_helpers.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# Only included in specs with elasticsearch: true
-module ElasticsearchHelpers
- def index_documents(resources)
- index_documents_for_search_class(Array.wrap(resources), described_class)
- end
-
- def index_documents_for_search_class(records, search_class)
- records.each(&:index_to_elasticsearch_inline)
- search_class.refresh_index
- end
-
- def clear_elasticsearch_data(search_class)
- search_class.refresh_index
- Search::Client.delete_by_query(
- index: search_class::INDEX_ALIAS, body: { query: { match_all: {} } },
- )
- search_class.refresh_index
- end
-end
diff --git a/spec/support/initializers/vcr.rb b/spec/support/initializers/vcr.rb
index 164bbae94..1802e6fe7 100644
--- a/spec/support/initializers/vcr.rb
+++ b/spec/support/initializers/vcr.rb
@@ -13,8 +13,7 @@ VCR.configure do |config|
"github.com/mozilla/geckodriver/releases",
"selenium-release.storage.googleapis.com",
"developer.microsoft.com/en-us/microsoft-edge/tools/webdriver",
- "api.knapsackpro.com", "localhost", "127.0.0.1", "0.0.0.0",
- "elasticsearch"
+ "api.knapsackpro.com", "localhost", "127.0.0.1", "0.0.0.0"
)
# Removes all private data (Basic Auth, Set-Cookie headers...)
diff --git a/spec/system/articles/user_visits_articles_by_tag_spec.rb b/spec/system/articles/user_visits_articles_by_tag_spec.rb
index 9ffd0d4ab..1547f2bc4 100644
--- a/spec/system/articles/user_visits_articles_by_tag_spec.rb
+++ b/spec/system/articles/user_visits_articles_by_tag_spec.rb
@@ -18,16 +18,16 @@ RSpec.describe "User visits articles by tag", type: :system do
visit "/t/javascript"
end
- it "shows the header", js: true, stub_elasticsearch: true do
+ it "shows the header", js: true do
within("h1") { expect(page).to have_text("javascript") }
end
- it "shows the follow button", js: true, stub_elasticsearch: true do
+ it "shows the follow button", js: true do
within("header.tag-header") { expect(page).to have_button("Follow") }
end
# Regression test for https://github.com/forem/forem/pull/12724
- it "does not display a comment count of 0", js: true, stub_elasticsearch: true do
+ it "does not display a comment count of 0", js: true do
expect(page).to have_text("Add Comment")
expect(page).not_to have_text("0 comments")
end
@@ -62,7 +62,7 @@ RSpec.describe "User visits articles by tag", type: :system do
visit "/t/functional"
end
- it "shows the following button", js: true, stub_elasticsearch: true do
+ it "shows the following button", js: true do
wait_for_javascript
within("header.tag-header") { expect(page).to have_button("Following") }
diff --git a/spec/system/articles/user_visits_articles_by_timeframe_spec.rb b/spec/system/articles/user_visits_articles_by_timeframe_spec.rb
index e0f84c18b..944ec8926 100644
--- a/spec/system/articles/user_visits_articles_by_timeframe_spec.rb
+++ b/spec/system/articles/user_visits_articles_by_timeframe_spec.rb
@@ -105,7 +105,7 @@ RSpec.describe "User visits articles by timeframe", type: :system do
end
end
- context "when user has logged in", js: true, stub_elasticsearch: true do
+ context "when user has logged in", js: true do
let(:user) { create(:user) }
before do
diff --git a/spec/system/comments/user_delete_a_comment_spec.rb b/spec/system/comments/user_delete_a_comment_spec.rb
index 1758e88bd..0b3feb23a 100644
--- a/spec/system/comments/user_delete_a_comment_spec.rb
+++ b/spec/system/comments/user_delete_a_comment_spec.rb
@@ -1,6 +1,6 @@
require "rails_helper"
-RSpec.describe "Deleting Comment", type: :system, js: true, elasticsearch: "FeedContent" do
+RSpec.describe "Deleting Comment", type: :system, js: true do
let(:user) { create(:user) }
let(:raw_comment) { Faker::Lorem.paragraph }
let(:article) do
diff --git a/spec/system/homepage/user_visits_homepage_articles_spec.rb b/spec/system/homepage/user_visits_homepage_articles_spec.rb
index b701d2526..a88967a5c 100644
--- a/spec/system/homepage/user_visits_homepage_articles_spec.rb
+++ b/spec/system/homepage/user_visits_homepage_articles_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe "User visits a homepage", type: :system do
end
# Regression test for https://github.com/forem/forem/pull/12724
- it "does not display a comment count of 0", js: true, stub_elasticsearch: true do
+ it "does not display a comment count of 0", js: true do
expect(page).to have_text("Add Comment")
expect(page).not_to have_text("0 comments")
article.update_column(:comments_count, 50)
@@ -28,7 +28,7 @@ RSpec.describe "User visits a homepage", type: :system do
expect(page).to have_text(/50\s*comments/)
end
- it "shows the main article readable date and time", js: true, stub_elasticsearch: true do
+ it "shows the main article readable date and time", js: true do
expect(page).to have_selector(".crayons-story--featured time", text: published_date)
selector = ".crayons-story--featured time[datetime='#{timestamp}']"
expect(page).to have_selector(selector)
@@ -48,7 +48,7 @@ RSpec.describe "User visits a homepage", type: :system do
expect(page).to have_text(article2.title)
end
- it "shows all articles' dates and times", js: true, stub_elasticsearch: true do
+ it "shows all articles' dates and times", js: true do
expect(page).to have_selector(".crayons-story time", text: published_date, count: 2)
selector = ".crayons-story time[datetime='#{timestamp}']"
expect(page).to have_selector(selector, count: 2)
diff --git a/spec/system/homepage/user_visits_homepage_spec.rb b/spec/system/homepage/user_visits_homepage_spec.rb
index d7fa07416..6832f5cf7 100644
--- a/spec/system/homepage/user_visits_homepage_spec.rb
+++ b/spec/system/homepage/user_visits_homepage_spec.rb
@@ -105,7 +105,7 @@ RSpec.describe "User visits a homepage", type: :system do
end
end
- it "shows followed tags ordered by weight and name", js: true, elasticsearch: "FeedContent" do
+ it "shows followed tags ordered by weight and name", js: true do
# Need to ensure the user data is loaded before doing any checks
find("body")["data-user"]
diff --git a/spec/system/homepage/user_visits_homepage_with_announcement_spec.rb b/spec/system/homepage/user_visits_homepage_with_announcement_spec.rb
index a9cf6df17..d7ac189a9 100644
--- a/spec/system/homepage/user_visits_homepage_with_announcement_spec.rb
+++ b/spec/system/homepage/user_visits_homepage_with_announcement_spec.rb
@@ -13,7 +13,7 @@ def expect_no_broadcast_data(page)
expect(page).not_to have_text("Hello, World!")
end
-RSpec.describe "User visits a homepage", stub_elasticsearch: true, type: :system do
+RSpec.describe "User visits a homepage", type: :system do
context "when user hasn't logged in" do
context "with an active announcement" do
before do
diff --git a/spec/system/organization/user_views_an_organization_spec.rb b/spec/system/organization/user_views_an_organization_spec.rb
index cffec23a0..0f6f3dc48 100644
--- a/spec/system/organization/user_views_an_organization_spec.rb
+++ b/spec/system/organization/user_views_an_organization_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe "Organization index", type: :system do
context "when 2 articles" do
before { visit "/#{organization.slug}" }
- it "shows the header", js: true, stub_elasticsearch: true do
+ it "shows the header", js: true do
within("h1") { expect(page).to have_content(organization.name) }
within("div.profile-header__actions") do
expect(page).to have_button("Follow")
@@ -36,7 +36,7 @@ RSpec.describe "Organization index", type: :system do
end
context "when more articles" do
- it "visits ok", js: true, stub_elasticsearch: true do
+ it "visits ok", js: true do
create_list(:article, 3, organization: organization)
visit "/#{organization.slug}"
end
@@ -51,7 +51,7 @@ RSpec.describe "Organization index", type: :system do
user.follows.create(followable: organization)
end
- it "shows the correct button", js: true, stub_elasticsearch: true do
+ it "shows the correct button", js: true do
visit "/#{organization.slug}"
within(".profile-header__actions") do
diff --git a/spec/system/search/display_articles_search_spec.rb b/spec/system/search/display_articles_search_spec.rb
index 9570e6afb..f8bfdc19c 100644
--- a/spec/system/search/display_articles_search_spec.rb
+++ b/spec/system/search/display_articles_search_spec.rb
@@ -1,6 +1,6 @@
require "rails_helper"
-RSpec.describe "Display articles search spec", type: :system, js: true, elasticsearch: "FeedContent" do
+RSpec.describe "Display articles search spec", type: :system, js: true do
it "returns correct results for a search" do
found_article_one = create(:article)
found_article_one.update_columns(cached_tag_list: "ruby")
diff --git a/spec/system/search/display_comments_search_spec.rb b/spec/system/search/display_comments_search_spec.rb
index 72ff64037..37e850aea 100644
--- a/spec/system/search/display_comments_search_spec.rb
+++ b/spec/system/search/display_comments_search_spec.rb
@@ -1,6 +1,6 @@
require "rails_helper"
-RSpec.describe "Display articles search spec", type: :system, js: true, elasticsearch: "FeedContent" do
+RSpec.describe "Display articles search spec", type: :system, js: true do
it "returns correct results for a search" do
query = "