You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
> This only applies to built-in search, other search plugins like may override this syntax.
8
+
> This only applies to the built-in search. Search plugins may override this syntax.
9
9
10
-
Search query consists of several keywords. Keyword starting with "-" is considered a negative match. Several special keywords are available:
10
+
A search query consists of one or several keywords.
11
11
12
-
*``@{date}`` - match by date. For example, @yesterday or @2011-11-03. Please note that due to incomplete implementation, special date keywords like yesterday might not match all articles if user timezone is different from tt-rss internal timezone (UTC).
13
-
*``pub:{true,false}`` - match only published or unpublished articles
14
-
*``star:{true, false}`` - same, starred articles
15
-
*``unread:{true, false}`` - self explanatory (requires trunk as of 05.03.2015)
16
-
*``note:{true, false, sometext}`` - same, for articles having an attached note or matching the specified text
17
-
*``label:Somelabel`` - articles that belong to a specified label
18
-
*``tag:mytag`` - articles which have specified tag
19
-
*``title:``, ``author:`` - self explanatory
12
+
<aid="text_keyword"></a>A keyword can be a **text keyword**. A text keyword is a single word such as `ocean`, or successive words enclosed in quotes such as `"pacific ocean"`. These keywords are searched using PostgreSQL [Full Text Search](#full_text_search) engine. This engine supports [word stemming](#word_stemming), and [logical operators](#logical_operators).
20
13
21
-
When searching by keyword with spaces, use quotes like this: `"title:string with spaces"` or `tag:"multiple words"`
14
+
<aid="namevalue_keyword"></a>A keyword can also be a **name-value keyword**:
15
+
-`star:true`, `star:false` - match starred or not starred articles
16
+
-`unread:true`, `unread:false` - match unread or read articles
17
+
-`pub:true`, `pub:false` - match published or unpublished articles
18
+
-`title:sometext`, `title:"two words"` - match articles with a title containing the specified text (sub-string match)
19
+
-`author:sometext`, `author:"two words"` - match articles with an author containing the specified text (sub-string match)
20
+
-`note:true`, `note:false`, `note:sometext`, `note:"two words"` - match articles with a note, no note, or a note containing the specified text (sub-string match)
21
+
-`label:true`, `label:false`, `label:somelabel`, `label:"two words"` - match articles with a label, no label, or belonging to the specified label (exact-string match)
22
+
-`tag:true`, `tag:false`, `tag:sometag`, `tag:"two words"` - match articles with a tag, no tag, or associated to the specified tag (exact-string match)
23
+
24
+
A keyword can also be a **date keyword**:
25
+
-`@somedate` - match by article publication [date](#date_keyword)
26
+
27
+
A keyword starting with `-` (negative sign) is considered a negative match. The `-` can be applied before any type of keyword. For example `-unwanted`, `-"unwanted words"`, `-title:unwanted`, `-tag:"unwanted words"` or `-@yesterday`.
28
+
29
+
A logical `AND` operator is applied between keywords. For example `ocean "tree flower" note:true -title:"orange color"` searches for articles containing the word _ocean_ (with [stemming](#word_stemming)) AND the sentence _"tree flower"_ (with [stemming](#word_stemming)) AND a note AND a title not containing the string _"orange color"_. This _AND_ must not be written, it is applied by default.
30
+
31
+
Other [logical operators](#logical_operators) are only supported around a [text keyword](#text_keyword), because they are processed by PostgreSQL [Full Text Search](#full_text_search) engine. A [name-value keyword](#namevalue_keyword) or [date keyword](#date_keyword) does not support those PostgreSQL [logical operators](#logical_operators).
32
+
33
+
34
+
<aid="full_text_search"></a>
35
+
# PostgreSQL Full Text Search
36
+
37
+
Tiny Tiny RSS uses a PostgreSQL database, providing a [Full Text Search engine](https://www.postgresql.org/docs/current/textsearch-intro.html) (external link).
38
+
39
+
It supports two main features:
40
+
-[Word stemming](#word_stemming)
41
+
-[Logical operators](#logical_operators)
42
+
43
+
<aid="word_stemming"></a>
44
+
## Word stemming
45
+
46
+
Word stemming is a process to find the stem (root) of a word. For example, in English the words _security_, _secure_ and _secured_ all share the same stem: _secur_. PostgreSQL names this stem a _lexeme_. A _lexeme_ is a normalized string so that different forms of the same word are made alike.
47
+
48
+
Word stemming is only available for [text keywords](#text_keyword).
49
+
50
+
Here is a full example. A RSS feed provides an article containing the word _security_. If the user has configured the language of this feed as English, then this word _security_ is stored in the database as its lexeme _secur_. Later, the user opens the search form, selects the English language, and searches for _secured_. Tiny Tiny RSS sends _secured_ to PostgreSQL, which converts this query to the lexeme _secur_. As both lexemes are identical, the article containing _security_ matches the search query _secured_.
51
+
52
+
Word stemming is powerful, but has one drawback: both languages of the feed and of the search query have to be well configured. Indeed, the word stemming process depends on the language: French and English words are not stemmed in the same way, so comparing them may lead to unexpected results.
53
+
54
+
On the Tiny Tiny RSS interface, there is a special language named _Simple_. Word stemming in the _Simple_ language is almost equivalent to exact string matching. With the _Simple_ language, only punctuation such as commas are removed. The power of word stemming is thus not applied, but it works well in usages with multiple languages.
55
+
56
+
The user can also manually set a prefix in the search query using the syntax `secu:*` which matches every word starting by `secu`.
57
+
58
+
<aid="logical_operators"></a>
59
+
## Logical operators
60
+
61
+
A [text keyword](#text_keyword) can be surrounded by logical operators provided by the PostgreSQL [Full Text Search](#full_text_search) engine.
62
+
63
+
{: .note }
64
+
> Due to current parser limitations, these logical operators cannot be applied on a [name-value keyword](#namevalue_keyword) nor on a [date keyword](#date_keyword).
65
+
66
+
PostgreSQL provides:
67
+
-`!` : logical NOT
68
+
-`&` : logical AND
69
+
-`|` : logical OR
70
+
-`(` and `)` : parentheses can be used to control nesting of operators. Without parentheses, `|` binds least tightly, then `&`, and `!` most tightly.
> Due to current parser limitations, the handling of space is important:
76
+
> - Spaces are **compulsory around words enclosed in quotes** such as `"black sea"`, otherwise the parser does not detect the quotes.
77
+
> - Spaces are **recommended around single words** such as `atlantic`, otherwise the word is not highlighted (please also see [highlighting limitations](#highlighting_limitations)).
78
+
> - Spaces are **recommended around logical operators**, otherwise highlighting may not work correctly.
79
+
80
+
{: warning }
81
+
> Due to current parser limitations, when at least one operator is detected, Tiny Tiny RSS does not apply the default _AND_ operator. Tiny Tiny RSS expects the whole query to be well formatted. For example the query `one two` works because no operator is detected, so tt-rss adds the _AND_. However, `one two & three` fails because tt-rss detects the `&` operator, so expects the whole query to be well formatted, and does not add the missing `&` between the words `one` and `two`.
82
+
83
+
{: .note }
84
+
> When a search query contains [name-value](#namevalue_keyword)/[date](#date_keyword) keywords and [text keywords](#text_keyword) using _logical operators_, it is recommended to write the [text keywords](#text_keyword) at the end (or the beginning), and to surround them with parenthesis. For example when reading `-title:submarine @yesterday ( pacific | atlantic )` one can easily understand that the parenthesis contains a complex fragment, that has to be well formatted with no missing operator.
85
+
86
+
{: .note }
87
+
> Due to current parser limitations, the `-` negation does not work before a parenthesis. It only works before a [text keyword](#text_keyword). When a parenthesis group needs to be negated, use the `!` operator. For example: `-title:submarine @yesterday ( ! ( pacific | atlantic ) )`
88
+
89
+
90
+
<aid="date_keyword"></a>
91
+
# Date keyword
92
+
93
+
A _date keyword_ can filter articles based on their publication or update date:
94
+
-`@2025-10-28` formatted as `@YYYY-MM-DD`
95
+
-`@2025/10/28` formatted as `@YYYY/MM/DD`
96
+
-`@28/10/2025` formatted as `@DD/MM/YYYY`
97
+
-`@"28 oct 2025"`
98
+
-`@"October 28"` (of the current year)
99
+
-`@today`
100
+
-`@yesterday`
101
+
-`@"2 days ago"`
102
+
-`@"last monday"`
103
+
104
+
{: .note }
105
+
> A _date keyword_ has to represent a fixed day. For example `@"last week"`, `@2023-11` or `@2024` cannot be used because they represent a range of several days.
106
+
107
+
108
+
<aid="quoting_variants"></a>
109
+
# Quoting variants
110
+
111
+
When a [text keyword](#text_keyword) contains spaces, and is negated, it can be written in two ways:
112
+
-`-"pacific ocean"` - the recommended usage because it is more readable
113
+
-`"-pacific ocean"`
114
+
115
+
When a [name-value keyword](#namevalue_keyword) contains spaces, it can be written in two ways:
116
+
-`title:"two words"` - the recommended usage because it is more readable
117
+
-`"title:two words"`
118
+
119
+
The negative expression can be written in two ways:
120
+
-`-title:"two words"` - the recommended usage because it is more readable
121
+
-`"-title:two words"`
122
+
123
+
When a [date keyword](#date_keyword) contains spaces, it can be written in two ways:
124
+
-`@"two words"` - the recommended usage because it is more readable
125
+
-`"@two words"`
126
+
127
+
The negative expression can be written in two ways:
128
+
-`-@"two words"` - the recommended usage because it is more readable
129
+
-`"-@two words"`
130
+
131
+
<aid="highlighting_limitations"></a>
132
+
# Highlighting limitations
133
+
134
+
A [text keyword](#text_keyword) can be a single word such as `ocean`. If the article contains `ocean` or `oceanographer`, the `ocean` fragment is highlighted.
135
+
A [text keyword](#text_keyword) can also be successive words enclosed in quotes such as `"pacific ocean"`. If the article contains `pacific oceanographer`, the `pacific ocean` fragment is highlighted.
136
+
{: .note }
137
+
> Due to incomplete implementation, the word is not correctly highlighted when a [stemmed](#word_stemming) variant is used. For example, if the user searches for _secured_, articles containing _security_ are displayed, however as _secured_ is not in the content, it is not highlighted.
138
+
139
+
If the searched word is prefixed by the negation `-`, it is not highlighted.
140
+
{: .note }
141
+
> Due to incomplete implementation, the negation with `!` is not detected, so words negated in a such way are still highlighted. Use the `-` sign instead.
142
+
143
+
144
+
<aid="undetected_errors"></a>
145
+
# Undetected errors
146
+
147
+
{: warning }
148
+
> Due to current parser limitations, most syntax errors are undetected. When user enters a badly formatted search query, it is incorrectly parsed, no message is displayed, and the results are unexpected.
149
+
150
+
151
+
<aid="contributions"></a>
152
+
# Contributions are welcome
153
+
154
+
The current search query parser implements a basic keyword splitting. It works in most cases, but has the disadvantages presented above.
155
+
156
+
It is maintained with best effort until someone volunteers to create a full parser with:
157
+
- logical operators and grouping around any type of keyword
158
+
- highlighting supported in all cases
159
+
- detection of invalid queries, with a warning displayed
160
+
161
+
Contributions are welcome!
22
162
23
-
If no special keywords are specified, search is done using PostgreSQL [Full Text Search](https://www.postgresql.org/docs/current/textsearch-intro.html) engine.
24
163
25
-
Pointless as it may be, you can combine negative prefix with the special keywords: `-star:true` would essentially mean `star:false`.
0 commit comments