Skip to content

Commit c2edb1c

Browse files
stsewdCopilot
andauthored
Post: Faster search (#371)
Closes #370 <!-- readthedocs-preview readthedocs-about start --> ---- πŸ“š Documentation preview πŸ“š: https://readthedocs-about--371.org.readthedocs.build/ <!-- readthedocs-preview readthedocs-about end --> --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: stsewd <4975310+stsewd@users.noreply.github.com>
1 parent 3995e93 commit c2edb1c

File tree

6 files changed

+210
-0
lines changed

6 files changed

+210
-0
lines changed
48 KB
Loading
23.5 KB
Loading
23.8 KB
Loading
19.5 KB
Loading
19.6 KB
Loading
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
title: Making search faster for all projects
2+
date: February 5, 2026
3+
description: We made several improvements to make search faster for all projects on Read the Docs.
4+
category: Engineering
5+
tags: performance, search
6+
authors: Santos Gallegos
7+
status: published
8+
image: /images/faster-search.jpg
9+
image_credit: Photo by <a href="https://unsplash.com/@julianhochgesang?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Julian Hochgesang</a> on <a href="https://unsplash.com/photos/time-lapse-photography-of-vehicles-3-y9vq8uoxk?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
10+
11+
Search is a fundamental feature for documentation projects,
12+
helping users to find the information they need quickly.
13+
That's why Read the Docs includes a powerful [search engine](https://docs.readthedocs.com/platform/stable/server-side-search/index.html) for all hosted projects powered by Elasticsearch.
14+
15+
Since its launch, we have continuously worked to enhance the search experience by adding new features,
16+
but performance has remained a challenge due to the growing number of projects and users on the platform.
17+
Over the last few months, we have focused on improving search performance for all projects,
18+
achieving significant gains in speed and responsiveness.
19+
20+
We reduced the average response time from **210ms to 97ms** on Read the Docs Community,
21+
and from **570ms to 205ms** on Read the Docs Business (excluding network latency).
22+
23+
![Search performance improvements graph on Read the Docs Community](/images/search-improvements-community.png)
24+
25+
_Average response time for search requests on Read the Docs Community from the last 3 months._
26+
27+
![Search performance improvements graph on Read the Docs Business](/images/search-improvements-business.png)
28+
29+
_Average response time for search requests on Read the Docs Business from the last 3 months._
30+
31+
## What we did
32+
33+
When looking for ways to improve search performance,
34+
we identified three main areas of focus:
35+
36+
1. Reducing the volume of data being searched.
37+
2. Optimizing Elasticsearch configuration and queries.
38+
3. Optimizing our application logic.
39+
40+
## Reducing the volume of data
41+
42+
The more data we search through, the longer it takes to return results.
43+
It also impacts our infrastructure costs; Elastic Cloud requires upgrading the instance type (adding CPU and RAM) to increase storage.
44+
We were approaching 85% of our current plan's storage limit.
45+
46+
We started by removing projects marked as spam from our index,
47+
followed by inactive projects (those with no builds or searches in the last 90 days).
48+
49+
While this didn't yield a massive performance boost immediately,
50+
it kept us within our storage limits without an emergency plan upgrade
51+
and prepared the index for our next step: increasing the number of shards.
52+
53+
## Optimizing Elasticsearch queries
54+
55+
We analyzed our queries for inefficiencies and found several opportunities for improvement:
56+
57+
- **Result limits:** We were returning 50 results by default,
58+
but most users rarely look past the first few.
59+
We reduced the default count to 15.
60+
- **Fuzzy search:** Some search terms containing `~` (like shell prompts or UNIX paths)
61+
were triggering expensive [fuzzy searches](https://docs.readthedocs.com/platform/stable/server-side-search/syntax.html#special-queries) unintentionally.
62+
We changed the maximum number of expansions from 50 to 10 and increased the prefix length from 0 to 1.
63+
See the [Elasticsearch documentation](https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-simple-query-string-query) for more information about these parameters.
64+
65+
## Optimizing Elasticsearch configuration
66+
67+
As we exhausted query-level optimizations,
68+
we found a couple of alerts from Elastic Cloud's [AutoOps](https://www.elastic.co/platform/autoops) regarding shard size.
69+
70+
We had a single shard for the entire index.
71+
As the index grew to 630GB, performance degraded.
72+
Elasticsearch thrives on parallelizing requests across multiple shards;
73+
the recommended size is around 30GB per shard.
74+
When Elasticsearch was first integrated into Read the Docs, our index was much smaller,
75+
so a single shard made sense at the time.
76+
77+
Because the number of shards cannot be changed on an existing index, we performed a full re-index.
78+
To ensure minimal downtime during the process, we followed these steps:
79+
80+
1. **Cleanup:** Deleted unnecessary data to minimize the transfer.
81+
2. **Scaling:** Temporarily upgraded instances to handle the storage of both indexes and speed up the migration.
82+
3. **Re-indexing:** Created a new index with 20 shards (based on the ~570GB post-cleanup size)
83+
and used the [reindex API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-reindex) to migrate data.
84+
4. **Cutover:** Updated our index alias and deleted the old index.
85+
5. **Catch-up:** Indexed any new or updated documents added during re-indexing.
86+
87+
The process took a couple of hours, and search remained available during the whole time.
88+
This improved Elasticsearch query averages from **90ms to 60ms** on Community and **80ms to 60ms** on Business.
89+
It also significantly sped up document indexing and deletions.
90+
91+
**Note:** For Read the Docs Business, our index was smaller (around 100GB),
92+
but we still needed to increase the number of shards to improve performance,
93+
so we created a new index with 4 shards.
94+
95+
## Optimizing application logic
96+
97+
We discovered that significant time was spent querying the database to serialize results (fetching project details, resolving URLs),
98+
and on Read the Docs Business performing permission checks.
99+
100+
This got worse as we enabled searching for subprojects by default,
101+
as searching on projects with many subprojects triggered multiple database queries per search.
102+
103+
We resolved several N+1 issues using `select_related` and `prefetch_related`,
104+
implemented caching where possible, re-used previously fetched data/instances, and did operations in bulk.
105+
106+
This saved approximately **12ms** on Community and **105ms** on Business.
107+
108+
## Optimizing the Elasticsearch client
109+
110+
Years ago, we disabled connection pooling in the Python client due to stability issues,
111+
this resulted in creating a new connection for each request.
112+
We revisited this, and enabled connection pooling without issues.
113+
114+
We also used the recommended way to connect to Elastic Cloud using the `cloud_id` parameter,
115+
this enables [HTTP compression and other optimizations](https://www.elastic.co/guide/en/elasticsearch/client/python-api/8.19/connecting.html#connect-ec).
116+
117+
Elasticsearch query times dropped from **60ms to 25ms** on Community and **60ms to 40ms** on Business.
118+
119+
**Note:** The difference in improvement between Community and Business is likely due to the difference in the instance types used in each platform.
120+
On Community, we use more powerful instances due to the higher storage needs.
121+
122+
## Conclusions
123+
124+
After implementing these changes, we saw a significant improvement in search performance across all projects hosted on Read the Docs.
125+
Search as you type is now much more responsive, especially on Community. We still have work to do on Business,
126+
but we are happy with the progress we have made so far.
127+
128+
You can see the improvements in the graphs below.
129+
There are three main drops in the graphs that correspond to the main changes we made:
130+
131+
- The first drop corresponds to the optimizations made to our Elasticsearch queries.
132+
- The second drop corresponds to the increase in the number of shards.
133+
- The third drop corresponds to the change in our Elasticsearch client to use connection pooling.
134+
135+
Of course, there are other optimizations that contributed to the overall improvement that were included in the same time frame,
136+
but these were the most significant ones regarding Elasticsearch performance.
137+
138+
![Search performance improvements graph on Read the Docs Community](/images/search-improvements-community.png)
139+
140+
_Average response time for search requests on Read the Docs Community from the last 3 months._
141+
142+
![Search performance improvements graph on Read the Docs Community](/images/search-improvements-query-time-community.png)
143+
144+
_Average Elasticsearch query time on Read the Docs Community from the last 3 months._
145+
146+
![Search performance improvements graph on Read the Docs Business](/images/search-improvements-business.png)
147+
148+
_Average response time for search requests on Read the Docs Business from the last 3 months._
149+
150+
![Search performance improvements graph on Read the Docs Business](/images/search-improvements-query-time-business.png)
151+
152+
_Average Elasticsearch query time on Read the Docs Business from the last 3 months._
153+
154+
Some reasons why Read the Docs Business is still slower than Read the Docs Community:
155+
156+
- **More complex permission checks.**
157+
Since we host private projects, we need to ensure that users only see results from versions they have access to.
158+
This requires checking each version's permissions before including it in the search results.
159+
- **No caching of search results.**
160+
Due to the nature of private projects, we can't cache search results,
161+
as they may change based on user permissions.
162+
163+
## Recommendations
164+
165+
Here are some recommendations for other teams looking to improve their Elasticsearch search performance:
166+
167+
- Monitor shard size and number of documents per shard.
168+
As your index grows, it's important to ensure that shards don't become too large.
169+
- If you are using Elastic Cloud, check [AutoOps](https://www.elastic.co/platform/autoops) alerts regularly.
170+
You can setup email/slack notifications for new alerts.
171+
- Delete unnecessary data from your index.
172+
This will help reduce storage costs and further reduce your number of shards needed.
173+
- Make sure your Elasticsearch client is using connection pooling and other optimizations.
174+
- Implement restrictions on the number of results returned by default, and the use of expensive search features like fuzzy search.
175+
- Check for optimizations in your application logic, if it interacts with the results from Elasticsearch.
176+
177+
## Next steps
178+
179+
While we are happy with the improvements we have made so far, there is still room for further optimizations:
180+
181+
- Revisit the number of shards.
182+
We decided on the number of shards based on the size of the index before re-indexing,
183+
but the resulting index was smaller than we expected (there was maybe some fragmentation on the old index).
184+
Reducing the number of shards could improve performance, but it's not clear by how much.
185+
As this requires re-indexing again, we won't do this unless we need to re-index for other reasons.
186+
- Further optimize database queries.
187+
This is an ongoing effort, and we will continue to look for ways to reduce the number of queries and improve their efficiency,
188+
especially on Read the Docs Business, where we run these queries everywhere a resource is accessed.
189+
190+
## Acknowledgements
191+
192+
[Elastic](https://www.elastic.co/) sponsors Read the Docs Community with a free [Elastic Cloud](https://www.elastic.co/cloud) plan.
193+
We are grateful for their support in helping us provide search functionality to all our users,
194+
their support is key to keeping search fast and accessible for the whole community.
195+
196+
## Changes
197+
198+
If you are interested in the specific changes we made,
199+
here is the list of relevant pull requests.
200+
Note that some changes were made in private repositories,
201+
so they are not included here.
202+
203+
- <https://github.com/readthedocs/readthedocs.org/pull/12695>
204+
- <https://github.com/readthedocs/readthedocs.org/pull/12666>
205+
- <https://github.com/readthedocs/readthedocs.org/pull/12660>
206+
- <https://github.com/readthedocs/readthedocs.org/pull/12635>
207+
- <https://github.com/readthedocs/readthedocs.org/pull/12588>
208+
- <https://github.com/readthedocs/readthedocs.org/pull/12569>
209+
- <https://github.com/readthedocs/readthedocs.org/pull/12560>
210+
- <https://github.com/readthedocs/readthedocs.org/pull/12549>

0 commit comments

Comments
Β (0)