Problem/Motivation
We have a couple older sites where a Search API Database is used, and it seems attacks (potential AI based) are getting around Cloudflare/other server level bans sometimes and causing longer-running database queries which in parallel when attacked from multiple IPs, can easier overload the database. This is because if e.g. 50 words are entered, the query generated is quite long (WHERE word LIKE word1 OR word LIKE word2, etc). The maxlength does not help when allowing query string variables, and really its the number of words here that matters not the string length.
Of course optional as a modern site will often have a e.g. vector database where someone searching in sentence/question form is more likely/valid; however, I still think this would be a useful feature to have for sites still lingering on more traditional several keywords + database backend.
Steps to reproduce
- Use Search API Database
- Configure a fulltext exposed filter like 'keywords'
- Use a module like Views Ajax History to have query string variable based URLs
- Enter a long keyword string like ?keywords=one+two+three....etc+50
- Observe the SQL query
Proposed resolution
Allow restricting max words, aborting query before it runs when exceeded (similar to how invalid utf8 aborts)

And:

Remaining tasks
MR
| Comment | File | Size | Author |
|---|---|---|---|
| #3 | output-example.png | 15.93 KB | scott_euser |
| #3 | configuration.png | 106.29 KB | scott_euser |
Issue fork search_api-3546439
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
scott_euser commentedComment #4
scott_euser commentedComment #5
scott_euser commentedComment #6
scott_euser commentedCouldn't see a good option in Core for word splitting, opted to borrow the one used in the Search API Database backend and therefore suggesting to move it into Utility class as a result, but feel free to disagree of course
Comment #7
scott_euser commentedProbably needs update hook as well to set default empty value, but will wait for feedback as to whether this direction is acceptable first or not
Comment #8
drunken monkeyThanks a lot for proposing this new feature! This does sound potentially useful, and simple enough to implement, so we can definitely go ahead with this.
However, I do have a few remarks:
splitIntoWords()is necessary here. There is in fact already a$wordsdefined inSearchApiFulltext::validateExposed(), a few lines further down. Just moving that up should be enough.The DB backend will only use
splitIntoWords()if the “Tokenizer” processor is not active, which is a bad idea anyways, so a the simplepreg_split()already used in the method should be fine. Just move the definition of$wordsup a few rows.Unicode::validateUtf8()check, it’s too early in the method currently. Right before// Only continue if there is a minimum word length set.seems good.defineOptions()change should be enough to keep existing views from breaking.ViewsTest::testSearchView()– just adapt the used view accordingly and then add a request with too many keywords.In any case, thanks a lot again!
Comment #9
scott_euser commentedSure sounds like a good plan, thanks for the thorough review!
Comment #10
scott_euser commentedThanks again for the review, I think that covers it; much smaller MR now + added test coverage
Comment #12
drunken monkeyGreat, thanks a lot!
I just made minimal changes and then merged.
Thanks again!
Comment #14
scott_euser commentedGreat thank you!