In every system I've ever designed, search and autocomplete are run through a secondary system such as ElasticSearch, Apache Solr, Sphinx, etc. Generally your application accepts the request with search parameters and passes those off to the secondary system. The reason is because databases have their limits for search-related things. For instance, PostgreSQL native text search doesn't support stemming in all languages, i.e. Japanese or Chinese, which makes text search in those languages less accurate than it could be. Dedicated search systems like those I mentioned have very specific dedication to perfecting search. This concerns not only language-specific issues, but performance optimization as well.
For example, my Ruby on Rails application accepts a number of parameters such as
collection. If it is an autocomplete request, the server passes the request onto ElasticSearch and only returns results where
word_start in a particular
collection (filtered by the collection's unique id). You can think of this as searching film titles for the drama genre. The results are then sent back to my server as an array of ids - at this point, my server performs a SQL query like:
WHERE id IN (LIST_OF_ELASTICSEARCH_IDS)
The ids ElasticSearch returns are the ids of the records in the table that is being queried.
For a full search, ElasticSearch does the exact same thing, but with more parameters available in the search (think the filters you have available on Amazon after you do a text search).
The point is, the only thing that the application server is doing is:
- Accepting an HTTP request with parameters
- Passing that request along to an ElasticSearch server
- Accepting the HTTP ElasticSearch response
- Doing a very simple SQL with the condition
WHERE id IN (LIST_OF_IDS)
So the actual search functionality is passed off to a secondary system with its own scalability, monitoring, statistics, configuration, etc. If my application server can handle 5x the web requests compared to searches based on response time, I can have 1 application server instance and 5 ElasticSearch instances for proper load balancing.
I believe that this is how most web applications like Amazon scale - they know what the throughput is for their web servers, and know the throughput of the search, and balance the resources accordingly.
Additionally, I have seen a few systems where search is pulled out into a microservice as a REST API. Basically, all search-related queries go through a standard REST API which connects to the provisioned "search engine" (ElasticSearch, Solr, etc.). Then, the system is more logically separated and can be more finely tuned to meet whatever throughput requirements are in play.
Now, I'm not sure what best practice is here, as I've never designed something as complex or high capacity as a site like Amazon's, but I think there are a lot more things to think about than separation of concerns and request throughput... i.e. if you have multiple applications using the search functionality or you want to expose it as a public API, having search as a microservice might make a lot of sense. But, at that point it's a business concern and not necessarily a technical one.