diff --git a/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/searching.dotnet.markdown b/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/searching.dotnet.markdown index fecfd0e564..b70903e162 100644 --- a/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/searching.dotnet.markdown +++ b/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/searching.dotnet.markdown @@ -3,7 +3,7 @@ {NOTE: } -* __Prior to this article__, please refer to article [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) +* __Prior to this article__, please refer to [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) to learn about the `Search` method. * __All capabilities__ provided by `Search` with a dynamic query can also be used when querying a static-index. diff --git a/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/searching.js.markdown b/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/searching.js.markdown index 04e278af1f..e3a54d6d3e 100644 --- a/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/searching.js.markdown +++ b/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/searching.js.markdown @@ -3,7 +3,7 @@ {NOTE: } -* __Prior to this article__, please refer to article [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) +* __Prior to this article__, please refer to [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) to learn about the `search` method. * __All capabilities__ provided by `search` with a dynamic query can also be used when querying a static-index. diff --git a/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/suggestions.dotnet.markdown b/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/suggestions.dotnet.markdown index bf2d7620cc..054df3709f 100644 --- a/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/suggestions.dotnet.markdown +++ b/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/suggestions.dotnet.markdown @@ -4,7 +4,7 @@ {NOTE: } -* Prior to this article, please refer to article [Query for Suggestions](../../client-api/session/querying/how-to-work-with-suggestions) +* Prior to this article, please refer to [Query for Suggestions](../../client-api/session/querying/how-to-work-with-suggestions) for general knowledge about Suggestions, and for dynamic-queries examples. * In addition to getting suggested terms when making a dynamic-query, diff --git a/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/suggestions.js.markdown b/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/suggestions.js.markdown index 23de769efc..b36a084f59 100644 --- a/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/suggestions.js.markdown +++ b/Documentation/5.2/Raven.Documentation.Pages/indexes/querying/suggestions.js.markdown @@ -4,7 +4,7 @@ {NOTE: } -* Prior to this article, please refer to article [Query for Suggestions](../../client-api/session/querying/how-to-work-with-suggestions) +* Prior to this article, please refer to [Query for Suggestions](../../client-api/session/querying/how-to-work-with-suggestions) for general knowledge about Suggestions, and for dynamic-queries examples. * In addition to getting suggested terms when making a dynamic-query, diff --git a/Documentation/5.2/Samples/csharp/Raven.Documentation.Samples/ClientApi/Session/Querying/TextSearch/FullTextSearch.cs b/Documentation/5.2/Samples/csharp/Raven.Documentation.Samples/ClientApi/Session/Querying/TextSearch/FullTextSearch.cs index e93899553e..428026faf9 100644 --- a/Documentation/5.2/Samples/csharp/Raven.Documentation.Samples/ClientApi/Session/Querying/TextSearch/FullTextSearch.cs +++ b/Documentation/5.2/Samples/csharp/Raven.Documentation.Samples/ClientApi/Session/Querying/TextSearch/FullTextSearch.cs @@ -598,7 +598,7 @@ public async Task Examples() #region fts_33 List employees = session .Query() - // Use '*' to replace one ore more characters + // Use '*' to replace one or more characters .Search(x => x.Notes, "art*") .Search(x => x.Notes, "*logy") .Search(x => x.Notes, "*mark*") @@ -618,7 +618,7 @@ public async Task Examples() #region fts_34 List employees = await asyncSession .Query() - // Use '*' to replace one ore more characters + // Use '*' to replace one or more characters .Search(x => x.Notes, "art*") .Search(x => x.Notes, "*logy") .Search(x => x.Notes, "*mark*") @@ -638,7 +638,7 @@ public async Task Examples() #region fts_35 List employees = session.Advanced .DocumentQuery() - // Use '*' to replace one ore more characters + // Use '*' to replace one or more characters .Search(x => x.Notes, "art*") .Search(x => x.Notes, "*logy") .Search(x => x.Notes, "*mark*") diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.dotnet.markdown index 3d9fee8aa3..709b3960e3 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.dotnet.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.dotnet.markdown @@ -8,9 +8,8 @@ also request to get a list of text fragments that highlight the searched terms. * This article provides examples of highlighting search results when querying a static-index. - Prior to reading this article, it is recommended to take a look at the - [Highlight search results](../../client-api/session/querying/text-search/highlight-query-results) - article for general knowledge about Highlighting and for dynamic-queries examples. + Prior to reading this article, please refer to [Highlight search results](../../client-api/session/querying/text-search/highlight-query-results) + for general knowledge about Highlighting and for dynamic-queries examples. * To search and get fragments with highlighted terms when querying a static-index, the index field on which you search must be configured for highlighting. See examples below. diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.js.markdown index 16a1452cd1..9e0cf9148e 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.js.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.js.markdown @@ -8,9 +8,8 @@ also request to get a list of text fragments that highlight the searched terms. * This article provides examples of highlighting search results when querying a static-index. - Prior to reading this article, it is recommended to take a look at the - [Highlight search results](../../client-api/session/querying/text-search/highlight-query-results) - article for general knowledge about Highlighting and for dynamic-queries examples. + Prior to reading this article, please refer to [Highlight search results](../../client-api/session/querying/text-search/highlight-query-results) + for general knowledge about Highlighting and for dynamic-queries examples. * To search and get fragments with highlighted terms when querying a static-index, the index field on which you search must be configured for highlighting. See examples below. diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.python.markdown index bac226098c..fe206193dd 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.python.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/highlighting.python.markdown @@ -8,9 +8,8 @@ also request to get a list of text fragments that highlight the searched terms. * This article provides examples of highlighting search results when querying a static-index. - Prior to reading this article, it is recommended to take a look at the - [Highlight search results](../../client-api/session/querying/text-search/highlight-query-results) - article for general knowledge about Highlighting and for dynamic-queries examples. + Prior to reading this article, please refer to [Highlight search results](../../client-api/session/querying/text-search/highlight-query-results) + for general knowledge about Highlighting and for dynamic-queries examples. * To search and get fragments with highlighted terms when querying a static-index, the index field on which you search must be configured for highlighting. See examples below. diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/projections.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/projections.python.markdown index fbc3ff2877..3f7362c4d1 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/projections.python.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/projections.python.markdown @@ -5,8 +5,7 @@ * This article provides examples of projecting query results when querying a **static-index**. -* Prior to reading this article, it is recommended to take a look at the - [query results projection Overview](../../client-api/session/querying/how-to-project-query-results) +* Prior to reading this article, please refer to [query results projection overview](../../client-api/session/querying/how-to-project-query-results) for general knowledge about Projections and for dynamic-queries examples. * Projections can be applied using the `select_fields` and `select_fields_query_data` methods. diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.dotnet.markdown index 8c02866cd6..73d3fb4d50 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.dotnet.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.dotnet.markdown @@ -4,8 +4,7 @@ {NOTE: } -* Prior to reading this article, it is recommended to take a look at the - [Query Overview](../../client-api/session/querying/how-to-query). +* Prior to this article, it is recommended that you first read this [Query Overview](../../client-api/session/querying/how-to-query). * For a basic indexes overview, see the [Indexes Overview](../../studio/database/indexes/indexes-overview). diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.js.markdown index 5a8cb02a29..aff21c18ab 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.js.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.js.markdown @@ -4,9 +4,8 @@ {NOTE: } -* Prior to reading this article, it is recommended to take a look at the - [Query Overview](../../client-api/session/querying/how-to-query). - +* Prior to this article, it is recommended that you first read this [Query Overview](../../client-api/session/querying/how-to-query). + * For a basic indexes overview, see the [Indexes Overview](../../studio/database/indexes/indexes-overview). --- diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.python.markdown index c17490029d..03fd6d08af 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.python.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/query-index.python.markdown @@ -4,9 +4,8 @@ {NOTE: } -* Prior to reading this article, it is recommended to take a look at the - [Query Overview](../../client-api/session/querying/how-to-query). - +* Prior to this article, it is recommended that you first read this [Query Overview](../../client-api/session/querying/how-to-query). + * For a basic indexes overview, see the [Indexes Overview](../../studio/database/indexes/indexes-overview). --- diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.dotnet.markdown index 748c1670d9..89bac02e5f 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.dotnet.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.dotnet.markdown @@ -3,9 +3,7 @@ {NOTE: } -* Prior to reading this article, it is recommended to take a look at the - [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) - article to learn about the `Search` method. +* Prior to this article, please refer to [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) to learn about the `Search` method. * **All capabilities** provided by `Search` with a dynamic query can also be used when querying a static-index. diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.js.markdown index e1a46a7995..0dfc359c81 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.js.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.js.markdown @@ -3,9 +3,8 @@ {NOTE: } -* Prior to reading this article, it is recommended to take a look at the - [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) - article to learn about the `search` method. +* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) + to learn about the `search` method. * **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index. diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.python.markdown index cfc4acc13a..01beaec7d8 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.python.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/searching.python.markdown @@ -3,9 +3,8 @@ {NOTE: } -* Prior to reading this article, it is recommended to take a look at the - [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) - article to learn about the `search` method. +* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) + to learn about the `search` method. * **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index. diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.dotnet.markdown index 2b72414e3c..59deabdc35 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.dotnet.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.dotnet.markdown @@ -4,9 +4,8 @@ {NOTE: } -* Prior to reading this article, it is recommended to take a look at the - [Query for Suggestions](../../client-api/session/querying/how-to-work-with-suggestions) - article for general knowledge about Suggestions and for dynamic-queries examples. +* Prior to reading this article, please refer to [query for suggestions](../../client-api/session/querying/how-to-work-with-suggestions) + for general knowledge about Suggestions and for dynamic-queries examples. * In addition to getting suggested terms when making a dynamic-query, you can query for similar terms when querying an index. diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.js.markdown index 883e04a8ce..56151556e8 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.js.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.js.markdown @@ -4,9 +4,8 @@ {NOTE: } -* Prior to reading this article, it is recommended to take a look at the - [Query for Suggestions](../../client-api/session/querying/how-to-work-with-suggestions) - article for general knowledge about Suggestions and for dynamic-queries examples. +* Prior to reading this article, please refer to [query for suggestions](../../client-api/session/querying/how-to-work-with-suggestions) + for general knowledge about Suggestions and for dynamic-queries examples. * In addition to getting suggested terms when making a dynamic-query, you can query for similar terms when querying an index. diff --git a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.python.markdown index f27c37d319..1014002496 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.python.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/indexes/querying/suggestions.python.markdown @@ -4,9 +4,8 @@ {NOTE: } -* Prior to reading this article, it is recommended to take a look at the - [Query for Suggestions](../../client-api/session/querying/how-to-work-with-suggestions) - article for general knowledge about Suggestions and for dynamic-queries examples. +* Prior to reading this article, please refer to [query for suggestions](../../client-api/session/querying/how-to-work-with-suggestions) + for general knowledge about Suggestions and for dynamic-queries examples. * In addition to getting suggested terms when making a dynamic-query, you can query for similar terms when querying an index. diff --git a/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/ClientApi/Session/Querying/TextSearch/FullTextSearch.cs b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/ClientApi/Session/Querying/TextSearch/FullTextSearch.cs index e93899553e..428026faf9 100644 --- a/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/ClientApi/Session/Querying/TextSearch/FullTextSearch.cs +++ b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/ClientApi/Session/Querying/TextSearch/FullTextSearch.cs @@ -598,7 +598,7 @@ public async Task Examples() #region fts_33 List employees = session .Query() - // Use '*' to replace one ore more characters + // Use '*' to replace one or more characters .Search(x => x.Notes, "art*") .Search(x => x.Notes, "*logy") .Search(x => x.Notes, "*mark*") @@ -618,7 +618,7 @@ public async Task Examples() #region fts_34 List employees = await asyncSession .Query() - // Use '*' to replace one ore more characters + // Use '*' to replace one or more characters .Search(x => x.Notes, "art*") .Search(x => x.Notes, "*logy") .Search(x => x.Notes, "*mark*") @@ -638,7 +638,7 @@ public async Task Examples() #region fts_35 List employees = session.Advanced .DocumentQuery() - // Use '*' to replace one ore more characters + // Use '*' to replace one or more characters .Search(x => x.Notes, "art*") .Search(x => x.Notes, "*logy") .Search(x => x.Notes, "*mark*") diff --git a/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/projections.dotnet.markdown b/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/projections.dotnet.markdown index 2f5a602cee..0f264f77c9 100644 --- a/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/projections.dotnet.markdown +++ b/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/projections.dotnet.markdown @@ -5,8 +5,7 @@ * This article provides examples of projecting query results when querying a **static-index**. -* Prior to reading this article, it is recommended to take a look at the - [query results projection Overview](../../client-api/session/querying/how-to-project-query-results) +* Prior to reading this article, please refer to [query results projection overview](../../client-api/session/querying/how-to-project-query-results) for general knowledge about Projections and for dynamic-queries examples. * In this page: diff --git a/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/projections.js.markdown b/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/projections.js.markdown index 58e25e536f..7fad35330f 100644 --- a/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/projections.js.markdown +++ b/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/projections.js.markdown @@ -5,8 +5,7 @@ * This article provides examples of projecting query results when querying a **static-index**. -* Prior to reading this article, it is recommended to take a look at the - [query results projection Overview](../../client-api/session/querying/how-to-project-query-results) +* Prior to reading this article, please refer to [query results projection overview](../../client-api/session/querying/how-to-project-query-results) for general knowledge about Projections and for dynamic-queries examples. * In this page: diff --git a/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/searching.dotnet.markdown b/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/searching.dotnet.markdown new file mode 100644 index 0000000000..28ee65d1ed --- /dev/null +++ b/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/searching.dotnet.markdown @@ -0,0 +1,210 @@ +# Full-Text Search with Index +--- + +{NOTE: } + +* Prior to this article, please refer to [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) to learn about the `Search` method. + +* **All capabilities** provided by `Search` with a dynamic query can also be used when querying a static-index. + +* However, as opposed to making a dynamic search query where an auto-index is created for you, + when using a **static-index**: + + * You must configure the index-field in which you want to search. + See examples below. + + * You can configure which analyzer will be used to tokenize this field. + See [selecting an analyzer](../../indexes/using-analyzers#selecting-an-analyzer-for-a-field). + +--- + +* In this page: + * [Indexing single field for FTS](../../indexes/querying/searching#indexing-single-field-for-fts) + * [Indexing multiple fields for FTS](../../indexes/querying/searching#indexing-multiple-fields-for-fts) + * [Boosting search results](../../indexes/querying/searching#boosting-search-results) + * [Searching with wildcards](../../indexes/querying/searching#searching-with-wildcards) + * [When using StandardAnalyzer or NGramAnalyzer](../../indexes/querying/searching#when-usingor) + * [When using a custom analyzer](../../indexes/querying/searching#when-using-a-custom-analyzer) + * [When using the Exact analyzer](../../indexes/querying/searching#when-using-the-exact-analyzer) + +{NOTE/} + +--- + +{PANEL: Indexing single field for FTS} + +#### The index: + +{CODE:csharp index_1@Indexes\Querying\Searching.cs/} + +--- + +#### Query with Search: + +* Use `Search` to make a full-text search when querying the index. + +* Refer to [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) for all available **Search options**, + such as using wildcards, searching for multiple terms, etc. + +{CODE-TABS} +{CODE-TAB:csharp:Query search_1@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:Query_async search_2@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:DocumentQuery search_3@Indexes\Querying\Searching.cs /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByNotes" +where search(EmployeeNotes, "French") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: Indexing multiple fields for FTS} + +#### The index: + +{CODE:csharp index_2@Indexes\Querying\Searching.cs/} + +--- + +#### Sample query: + +{CODE-TABS} +{CODE-TAB:csharp:Query search_4@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:Query_async search_5@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:DocumentQuery search_6@Indexes\Querying\Searching.cs /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByEmployeeData" +where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish", and)) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: Boosting search results} + +* In order to prioritize results, you can provide a boost value to the searched terms. + This can be applied by either of the following: + + * Add a boost value to the relevant index-field **inside the index definition**. + Refer to article [indexes - boosting](../../indexes/boosting). + + * Add a boost value to the queried terms **at query time**. + Refer to article [Boost search results](../../client-api/session/querying/text-search/boost-search-results). + +{PANEL/} + +{PANEL: Searching with wildcards} + +* When making a full-text search with wildcards in the search terms, + the presence of wildcards (`*`) in the terms sent to the search engine is determined by the transformations applied by the + [analyzer](../../indexes/using-analyzers) used in the index. + +* Note the different behavior in the following cases, as described below: + * [When using StandardAnalyzer or NGramAnalyzer](../../indexes/querying/searching#when-usingor) + * [When using a custom analyzer](../../indexes/querying/searching#when-using-a-custom-analyzer) + * [When using the Exact analyzer](../../indexes/querying/searching#when-using-the-exact-analyzer) + +* When using [Corax](../../indexes/search-engine/corax) as the search engine, + this behavior will only apply to indexes that are newly created or have been reset. + +--- + +{NOTE: } + +##### When using `StandardAnalyzer` or `NGramAnalyzer`: +--- + +Usually, the same analyzer used to tokenize field content at **indexing time** is also used to process the terms provided in the **full-text search query** +before they are sent to the search engine to retrieve matching documents. + +**However, in the following cases**: + +* When making a [dynamic search query](../../client-api/session/querying/text-search/full-text-search) +* or when querying a static index that uses the default `StandardAnalyzer` +* or when querying a static index that uses the `NGramAnalyzer` + +the queried terms in the _Search_ method are processed with the **`LowerCaseKeywordAnalyzer`** before being sent to the search engine. + +This analyzer does Not remove the `*`, so the terms are sent with `*`, as provided in the search terms. +For example: + +{CODE-TABS} +{CODE-TAB:csharp:Index index_3@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:Query search_7@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:Query_async search_8@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:DocumentQuery search_9@Indexes\Querying\Searching.cs /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByNotes/usingDefaultAnalyzer" +where search(EmployeeNotes, "*rench") +include explanations() +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} +{NOTE: } + +##### When using a custom analyzer: +--- + +* When setting a [custom analyzer](../../indexes/using-analyzers#creating-custom-analyzers) in your index to tokenize field content, + then when querying the index, the search terms in the query will be processed according to the **custom analyzer's logic**. + +* The `*` will remain in the terms if the custom analyzer allows it. + It is the user’s responsibility to ensure that wildcards are not removed by the custom analyzer if they should be included in the query. + +* Note: + An exception to the above is when the wildcard is used as a suffix in the search term (e.g. `Fren*`). + In this case the wildcard will be included in the query regardless of the analyzer's logic. + +For example: + +{CODE-TABS} +{CODE-TAB:csharp:Index index_4@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:Custom_analyzer analyzer_1@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:Query search_10@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:Query_async search_11@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:DocumentQuery search_12@Indexes\Querying\Searching.cs /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByNotes/UsingCustomAnalyzer" +where search(EmployeeNotes, "*French*") +include explanations() +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} +{NOTE: } + +##### When using the Exact analyzer: +--- + +When using the default Exact analyzer in your index (which is `KeywordAnalyzer`), +then when querying the index, the wildcards in your search terms remain untouched. +The terms are sent to the search engine exactly as produced by the analyzer. + +For example: + +{CODE-TABS} +{CODE-TAB:csharp:Index index_5@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:Query search_13@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:Query_async search_14@Indexes\Querying\Searching.cs /} +{CODE-TAB:csharp:DocumentQuery search_15@Indexes\Querying\Searching.cs /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByFirstName/usingExactAnalyzer" +where search(FirstName, "Mich*") +include explanations() +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} +{PANEL/} + +## Related Articles + +### Client API + +- [Full-Text search](../../client-api/session/querying/text-search/full-text-search) + +### Indexes + +- [Analyzers](../../indexes/using-analyzers) +- [Boosting](../../indexes/boosting) diff --git a/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/searching.js.markdown b/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/searching.js.markdown new file mode 100644 index 0000000000..0227ab11e2 --- /dev/null +++ b/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/searching.js.markdown @@ -0,0 +1,201 @@ +# Full-Text Search with Index +--- + +{NOTE: } + +* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) + to learn about the `search` method. + +* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index. + +* However, as opposed to making a dynamic search query where an auto-index is created for you, + when using a **static-index**: + + * You must configure the index-field in which you want to search. + See examples below. + + * You can configure which analyzer will be used to tokenize this field. + See [selecting an analyzer](../../indexes/using-analyzers#selecting-an-analyzer-for-a-field). + +--- + +* In this page: + * [Indexing single field for FTS](../../indexes/querying/searching#indexing-single-field-for-fts) + * [Indexing multiple fields for FTS](../../indexes/querying/searching#indexing-multiple-fields-for-fts) + * [Boosting search results](../../indexes/querying/searching#boosting-search-results) + * [Searching with wildcards](../../indexes/querying/searching#searching-with-wildcards) + * [When using StandardAnalyzer or NGramAnalyzer](../../indexes/querying/searching#when-usingor) + * [When using a custom analyzer](../../indexes/querying/searching#when-using-a-custom-analyzer) + * [When using the Exact analyzer](../../indexes/querying/searching#when-using-the-exact-analyzer) + +{NOTE/} + +--- + +{PANEL: Indexing single field for FTS} + +#### The index: + +{CODE:nodejs index_1@Indexes\Querying\searching.js/} + +--- + +#### Query with Search: + +* Using the `search` method has the advantage of using any of its functionalities, + such as using wildcards, searching for multiple terms, etc. + +* Refer to [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) for all available **Search options**. + +{CODE-TABS} +{CODE-TAB:nodejs:Query search_1@Indexes\Querying\searching.js /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByNotes" +where search(employeeNotes, "French") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: Indexing multiple fields for FTS} + +#### The index: + +{CODE:nodejs index_2@Indexes\Querying\searching.js/} + +--- + +#### Sample query: + +{CODE-TABS} +{CODE-TAB:nodejs:Query search_2@Indexes\Querying\searching.js /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByEmployeeData" +where (search(employeeData, "Manager") or search(employeeData, "French Spanish", and)) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: Boosting search results} + +* In order to prioritize results, you can provide a boost value to the searched terms. + This can be applied by either of the following: + + * Add a boost value to the relevant index-field **inside the index definition**. + Refer to article [indexes - boosting](../../indexes/boosting). + + * Add a boost value to the queried terms **at query time**. + Refer to article [Boost search results](../../client-api/session/querying/text-search/boost-search-results). + +{PANEL/} + +{PANEL: Searching with wildcards} + +* When making a full-text search with wildcards in the search terms, + the presence of wildcards (`*`) in the terms sent to the search engine is determined by the transformations applied by the + [analyzer](../../indexes/using-analyzers) used in the index. + +* Note the different behavior in the following cases, as described below: + * [When using StandardAnalyzer or NGramAnalyzer](../../indexes/querying/searching#when-usingor) + * [When using a custom analyzer](../../indexes/querying/searching#when-using-a-custom-analyzer) + * [When using the Exact analyzer](../../indexes/querying/searching#when-using-the-exact-analyzer) + +* When using [Corax](../../indexes/search-engine/corax) as the search engine, + this behavior will only apply to indexes that are newly created or have been reset. + +--- + +{NOTE: } + +##### When using `StandardAnalyzer` or `NGramAnalyzer`: +--- + +Usually, the same analyzer used to tokenize field content at **indexing time** is also used to process the terms provided in the **full-text search query** +before they are sent to the search engine to retrieve matching documents. + +**However, in the following cases**: + +* When making a [dynamic search query](../../client-api/session/querying/text-search/full-text-search) +* or when querying a static index that uses the default `StandardAnalyzer` +* or when querying a static index that uses the `NGramAnalyzer` + +the queried terms in the _search_ method are processed with the **`LowerCaseKeywordAnalyzer`** before being sent to the search engine. + +This analyzer does Not remove the `*`, so the terms are sent with `*`, as provided in the search terms. +For example: + +{CODE-TABS} +{CODE-TAB:nodejs:Index index_3@Indexes\Querying\searching.js /} +{CODE-TAB:nodejs:Query search_3@Indexes\Querying\searching.js /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByNotes/usingDefaultAnalyzer" +where search(EmployeeNotes, "*rench") +include explanations() +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} +{NOTE: } + +##### When using a custom analyzer: +--- + +* When setting a [custom analyzer](../../indexes/using-analyzers#creating-custom-analyzers) in your index to tokenize field content, + then when querying the index, the search terms in the query will be processed according to the custom analyzer's logic. + +* The `*` will remain in the terms if the custom analyzer allows it. + It is the user’s responsibility to ensure that wildcards are not removed by the custom analyzer if they should be included in the query. + +* Note: + An exception to the above is when the wildcard is used as a suffix in the search term (e.g. `Fren*`). + In this case the wildcard will be included in the query regardless of the analyzer's logic. + +For example: + +{CODE-TABS} +{CODE-TAB:nodejs:Index index_4@Indexes\Querying\searching.js /} +{CODE-TAB:nodejs:Custom_analyzer analyzer_1@Indexes\Querying\searching.js /} +{CODE-TAB:nodejs:Query search_4@Indexes\Querying\searching.js /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByNotes/UsingCustomAnalyzer" +where search(EmployeeNotes, "*French*") +include explanations() +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} +{NOTE: } + +##### When using the Exact analyzer: +--- + +When using the default Exact analyzer in your index (which is `KeywordAnalyzer`), +then when querying the index, the wildcards in your search terms remain untouched. +The terms are sent to the search engine exactly as produced by the analyzer. + +For example: + +{CODE-TABS} +{CODE-TAB:nodejs:Index index_5@Indexes\Querying\searching.js /} +{CODE-TAB:nodejs:Query search_5@Indexes\Querying\searching.js /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByFirstName/usingExactAnalyzer" +where search(FirstName, "Mich*") +include explanations() +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} +{PANEL/} + +## Related Articles + +### Client API + +- [Full-Text search](../../client-api/session/querying/text-search/full-text-search) + +### Indexes + +- [Analyzers](../../indexes/using-analyzers) +- [Boosting](../../indexes/boosting) diff --git a/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/searching.python.markdown b/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/searching.python.markdown new file mode 100644 index 0000000000..01beaec7d8 --- /dev/null +++ b/Documentation/6.0/Raven.Documentation.Pages/indexes/querying/searching.python.markdown @@ -0,0 +1,98 @@ +# Full-Text Search with Index +--- + +{NOTE: } + +* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) + to learn about the `search` method. + +* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index. + +* However, as opposed to making a dynamic search query where an auto-index is created for you, + when using a **static-index**: + + * You must configure the index-field in which you want to search. + See examples below. + + * You can configure which analyzer will be used to tokenize this field. + See [selecting an analyzer](../../indexes/using-analyzers#selecting-an-analyzer-for-a-field). + +--- + +* In this page: + * [Indexing single field for FTS](../../indexes/querying/searching#indexing-single-field-for-fts) + * [Indexing multiple fields for FTS](../../indexes/querying/searching#indexing-multiple-fields-for-fts) + * [Boosting search results](../../indexes/querying/searching#boosting-search-results) + +{NOTE/} + +--- + +{PANEL: Indexing single field for FTS} + +#### The index: + +{CODE:python index_1@Indexes\Querying\Searching.py/} + +--- + +#### Query with Search: + +* Use `Search` to make a full-text search when querying the index. + +* Refer to [Full-Text search with dynamic queries](../../client-api/session/querying/text-search/full-text-search) for all available **Search options**, + such as using wildcards, searching for multiple terms, etc. + +{CODE-TABS} +{CODE-TAB:python:Query search_1@Indexes\Querying\Searching.py /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByNotes" +where search(EmployeeNotes, "French") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: Indexing multiple fields for FTS} + +#### The index: + +{CODE:python index_2@Indexes\Querying\Searching.py/} + +--- + +#### Sample query: + +{CODE-TABS} +{CODE-TAB:python:Query search_4@Indexes\Querying\Searching.py /} +{CODE-TAB-BLOCK:sql:RQL} +from index "Employees/ByEmployeeData" +where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish", and)) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: Boosting search results} + +* In order to prioritize results, you can provide a boost value to the searched terms. + This can be applied by either of the following: + + * Add a boost value to the relevant index-field **inside the index definition**. + Refer to article [indexes - boosting](../../indexes/boosting). + + * Add a boost value to the queried terms **at query time**. + Refer to article [Boost search results](../../client-api/session/querying/text-search/boost-search-results). + +{PANEL/} + +## Related Articles + +### Client API + +- [Full-Text search](../../client-api/session/querying/text-search/full-text-search) + +### Indexes + +- [Analyzers](../../indexes/using-analyzers) +- [Boosting](../../indexes/boosting) diff --git a/Documentation/6.0/Raven.Documentation.Pages/migration/server/server-breaking-changes.markdown b/Documentation/6.0/Raven.Documentation.Pages/migration/server/server-breaking-changes.markdown index b193a5eb41..8eefcfadff 100644 --- a/Documentation/6.0/Raven.Documentation.Pages/migration/server/server-breaking-changes.markdown +++ b/Documentation/6.0/Raven.Documentation.Pages/migration/server/server-breaking-changes.markdown @@ -1,24 +1,102 @@ # Migration: Server Breaking Changes +--- -The following features, that were available in former RavenDB versions, -are unavailable under RavenDB `6.x` or incompatible with their previous versions. - -* **License Keys** - License keys for versions lower than `6.0` are **not supported** by RavenDB `6.0`. - If you own a valid license key for RavenDB `5.x` or lower, please upgrade it using - the quick online interface [described here](../../start/licensing/replace-license#upgrade-a-license-key-for-ravendb-6.x). -* **RavenDB for Docker** - RavenDB now applies an improved security model, and uses a **dedicated user** rather than `root`. - Read more about this change [here](../../migration/server/docker). -* **Unsupported sharding features** - RavenDB 6.0 introduces [sharding](../../sharding/overview). Server and Client features - that are currently unavailable under a sharded database (but remain available in regular - databases) are listed [here](../../sharding/unsupported). -* [Graph Queries](https://ravendb.net/docs/article-page/5.4/csharp/indexes/querying/graph/graph-queries-overview) - Graph queries support, available in RavenDB versions `4.2` to `5.x`, is removed from - RavenDB `6.x` server and client API. -* **ETL** - SQL ETL no longer tolerates errors on `Load`: load errors are thrown immediately, to distinguish - partial load errors that are used in SQL ETL from, for example, commit errors that may happen - during load. (Prior to this change ETL would just advance instead of retrying.) -* `DateOnly` and `TimeOnly` are now supported for every new auto index. +{NOTE: } + +* The following features and behaviors that were available in previous versions of RavenDB + are either unavailable in RavenDB `6.x` or incompatible with those earlier versions. + +* In this page: + * [License keys](../../migration/server/server-breaking-changes#license-keys) + * [RavenDB for Docker](../../migration/server/server-breaking-changes#ravendb-for-docker) + * [Unsupported sharding features](../../migration/server/server-breaking-changes#unsupported-sharding-features) + * [Graph queries](../../migration/server/server-breaking-changes#graph-queries) + * [SQL ETL](../../migration/server/server-breaking-changes#sql-etl) + * [DateOnly & TimeOnly](../../migration/server/server-breaking-changes#dateonly-&-timeonly) + * [Full-text search with wildcards](../../migration/server/server-breaking-changes#full-text-search-with-wildcards) + +{NOTE/} + +--- + +{PANEL: License keys} + +License keys for versions lower than `6.0` are **not supported** by RavenDB `6.0`. +If you own a valid license key for RavenDB `5.x` or lower, please upgrade it using +the quick online interface described [here](../../start/licensing/replace-license#upgrade-a-license-key-for-ravendb-6.x). + +{PANEL/} + +{PANEL: RavenDB for Docker} + +RavenDB now applies an improved security model, and uses a **dedicated user** rather than `root`. +Read more about this change [here](../../migration/server/docker). + +{PANEL/} + +{PANEL: Unsupported sharding features} + +RavenDB `6.0` introduces [sharding](../../sharding/overview). +Server and client features that are currently unavailable in a sharded database (but remain available in regular databases) are listed [here](../../sharding/unsupported). + +{PANEL/} + +{PANEL: Graph queries} + +[Graph Queries](https://ravendb.net/docs/article-page/5.4/csharp/indexes/querying/graph/graph-queries-overview) support, +available in RavenDB versions `4.2` to `5.x`, has been removed from the RavenDB `6.x` server and client API. + +{PANEL/} + +{PANEL: SQL ETL} + +SQL ETL no longer tolerates errors on `Load`, load errors are thrown immediately. +This is done to distinguish partial load errors that are used in SQL ETL from, for example, commit errors that may happen during load. +(Prior to this change, the ETL would just advance instead of retrying.) + +{PANEL/} + +{PANEL: DateOnly & TimeOnly} + +[DateOnly and TimeOnly](../../client-api/how-to/using-timeonly-and-dateonly) types are now supported for every new auto index. + +{PANEL/} + +{PANEL: Full-text search with wildcards} + +Starting with `6.0` we have changed how the [Search method](../../indexes/querying/searching) handles wildcards when they are included in search terms: + +{NOTE: } + +##### Behavior for versions lower than `6.0`: + +After the analyzer stripped wildcards from the search term, +RavenDB would attempt to restore the `*` to their original positions before sending the term to the search engine (Lucene or Corax). + +{NOTE/} + +{NOTE: } + +##### Behavior for `6.0` and up: + +Once wildcards are stripped by the analyzer, we no longer add them back before sending the term to the search engine. +The search terms sent to the search engine are solely based on the transformations applied by the analyzer used in the index. + +Note the different behavior in the following cases: + +* **When using `StandardAnalyzer` or `NGramAnalyzer`**: + The queried terms in the _Search_ method are processed with the `LowerCaseKeywordAnalyzer` before being sent to the search engine. +* **When using a custom analyzer**: + The queried terms in the _Search_ method are processed according to the custom analyzer's logic. +* **When using the Exact analyzer**: + The queried terms in the _Search_ method remain untouched as produced by the exact analyzer. + +{INFO: } +When using **Corax** as the search engine, +this behavior will only apply to indexes that are newly created or have been reset. +{INFO/} + +See detailed examples in: [Searching with wildcards](../../indexes/querying/searching#searching-with-wildcards). + +{NOTE/} +{PANEL/} diff --git a/Documentation/6.0/Samples/csharp/Raven.Documentation.Samples/Indexes/Querying/Searching.cs b/Documentation/6.0/Samples/csharp/Raven.Documentation.Samples/Indexes/Querying/Searching.cs new file mode 100644 index 0000000000..516274acd6 --- /dev/null +++ b/Documentation/6.0/Samples/csharp/Raven.Documentation.Samples/Indexes/Querying/Searching.cs @@ -0,0 +1,585 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Raven.Client.Documents; +using Raven.Client.Documents.Indexes; +using Raven.Client.Documents.Indexes.Analysis; +using Raven.Client.Documents.Operations.Analyzers; +using Raven.Client.Documents.Queries; +using Raven.Documentation.Samples.Orders; +using Xunit; + +namespace Raven.Documentation.Samples.Indexes.Querying +{ + public class Searching + { + #region index_1 + public class Employees_ByNotes : + AbstractIndexCreationTask + { + // The IndexEntry class defines the index-fields + public class IndexEntry + { + public string EmployeeNotes { get; set; } + } + + public Employees_ByNotes() + { + // The 'Map' function defines the content of the index-fields + Map = employees => from employee in employees + select new IndexEntry() + { + EmployeeNotes = employee.Notes[0] + }; + + // Configure the index-field for FTS: + // Set 'FieldIndexing.Search' on index-field 'EmployeeNotes' + Index(x => x.EmployeeNotes, FieldIndexing.Search); + + // Optionally: Set your choice of analyzer for the index-field. + // Here the text from index-field 'EmployeeNotes' will be tokenized by 'WhitespaceAnalyzer'. + Analyze(x => x.EmployeeNotes, "WhitespaceAnalyzer"); + + // Note: + // If no analyzer is set then the default 'RavenStandardAnalyzer' is used. + } + } + #endregion + + #region index_2 + public class Employees_ByEmployeeData : + AbstractIndexCreationTask + { + public class IndexEntry + { + public object[] EmployeeData { get; set; } + } + + public Employees_ByEmployeeData() + { + Map = employees => from employee in employees + select new IndexEntry() + { + EmployeeData = new object[] + { + // Multiple document-fields can be indexed + // into the single index-field 'EmployeeData' + employee.FirstName, + employee.LastName, + employee.Title, + employee.Notes + } + }; + + // Configure the index-field for FTS: + // Set 'FieldIndexing.Search' on index-field 'EmployeeData' + Index(x => x.EmployeeData, FieldIndexing.Search); + + // Note: + // Since no analyzer is set then the default 'RavenStandardAnalyzer' is used. + } + } + #endregion + + #region index_3 + public class Employees_ByNotes_usingDefaultAnalyzer : + AbstractIndexCreationTask + { + public class IndexEntry + { + public string EmployeeNotes { get; set; } + } + + public Employees_ByNotes_usingDefaultAnalyzer() + { + Map = employees => from employee in employees + select new IndexEntry() + { + EmployeeNotes = employee.Notes[0] + }; + + // Configure the index-field for FTS: + Index(x => x.EmployeeNotes, FieldIndexing.Search); + + // Since no analyzer is explicitly set + // then the default 'RavenStandardAnalyzer' will be used at indexing time. + + // However, when making a search query with wildcards, + // the 'LowerCaseKeywordAnalyzer' will be used to process the search terms + // prior to sending them to the search engine. + } + } + #endregion + + #region index_4 + public class Employees_ByNotes_usingCustomAnalyzer : + AbstractIndexCreationTask + { + public class IndexEntry + { + public string EmployeeNotes { get; set; } + } + + public Employees_ByNotes_usingCustomAnalyzer() + { + Map = employees => from employee in employees + select new IndexEntry() + { + EmployeeNotes = employee.Notes[0] + }; + + // Configure the index-field for FTS: + Index(x => x.EmployeeNotes, FieldIndexing.Search); + + // Set a custom analyzer for the index-field: + Analyze(x => x.EmployeeNotes, "CustomAnalyzers.RemoveWildcardsAnalyzer"); + } + } + #endregion + + #region index_5 + public class Employees_ByFirstName_usingExactAnalyzer : + AbstractIndexCreationTask + { + public class IndexEntry + { + public string FirstName { get; set; } + } + + public Employees_ByFirstName_usingExactAnalyzer() + { + Map = employees => from employee in employees + select new IndexEntry() + { + FirstName = employee.FirstName + }; + + // Set the Exact analyzer for the index-field: + // (The field will not be tokenized) + Indexes.Add(x => x.FirstName, FieldIndexing.Exact); + } + } + #endregion + + public async Task Examples() + { + using (var store = new DocumentStore()) + { + using (var session = store.OpenSession()) + { + #region search_1 + List employees = session + // Query the index + .Query() + // Call 'Search': + // pass the index field that was configured for FTS and the term to search for. + .Search(x => x.EmployeeNotes, "French") + .OfType() + .ToList(); + + // * Results will contain all Employee documents that have 'French' in their 'Notes' field. + // + // * Search is case-sensitive since field was indexed using the 'WhitespaceAnalyzer' + // which preserves casing. + #endregion + } + + using (var asyncSession = store.OpenAsyncSession()) + { + #region search_2 + List employees = await asyncSession + // Query the index + .Query() + // Call 'Search': + // pass the index field that was configured for FTS and the term to search for. + .Search(x => x.EmployeeNotes, "French") + .OfType() + .ToListAsync(); + + // * Results will contain all Employee documents that have 'French' in their 'Notes' field. + // + // * Search is case-sensitive since field was indexed using the 'WhitespaceAnalyzer' + // which preserves casing. + #endregion + } + + using (var session = store.OpenSession()) + { + #region search_3 + List employees = session.Advanced + // Query the index + .DocumentQuery() + // Call 'Search': + // pass the index field that was configured for FTS and the term to search for. + .Search(x => x.EmployeeNotes, "French") + .OfType() + .ToList(); + + // * Results will contain all Employee documents that have 'French' in their 'Notes' field. + // + // * Search is case-sensitive since field was indexed using the 'WhitespaceAnalyzer' + // which preserves casing. + #endregion + } + + using (var session = store.OpenSession()) + { + #region search_4 + List employees = session + // Query the static-index + .Query() + // A logical OR is applied between the following two Search calls: + .Search(x => x.EmployeeData, "Manager") + // A logical AND is applied between the following two terms: + .Search(x => x.EmployeeData, "French Spanish", @operator: SearchOperator.And) + .OfType() + .ToList(); + + // * Results will contain all Employee documents that have: + // ('Manager' in any of the 4 document-fields that were indexed) + // OR + // ('French' AND 'Spanish' in any of the 4 document-fields that were indexed) + // + // * Search is case-insensitive since the default analyzer is used + #endregion + } + + using (var asyncSession = store.OpenAsyncSession()) + { + #region search_5 + List employees = await asyncSession + // Query the static-index + .Query() + // A logical OR is applied between the following two Search calls: + .Search(x => x.EmployeeData, "Manager") + // A logical AND is applied between the following two terms: + .Search(x => x.EmployeeData, "French Spanish", @operator: SearchOperator.And) + .OfType() + .ToListAsync(); + + // * Results will contain all Employee documents that have: + // ('Manager' in any of the 4 document-fields that were indexed) + // OR + // ('French' AND 'Spanish' in any of the 4 document-fields that were indexed) + // + // * Search is case-insensitive since the default analyzer is used + #endregion + } + + using (var session = store.OpenSession()) + { + #region search_6 + List employees = session.Advanced + // Query the static-index + .DocumentQuery() + .OpenSubclause() + // A logical OR is applied between the following two Search calls: + .Search(x => x.EmployeeData, "Manager") + // A logical AND is applied between the following two terms: + .Search(x => x.EmployeeData, "French Spanish", @operator: SearchOperator.And) + .CloseSubclause() + .OfType() + .ToList(); + + // * Results will contain all Employee documents that have: + // ('Manager' in any of the 4 document-fields that were indexed) + // OR + // ('French' AND 'Spanish' in any of the 4 document-fields that were indexed) + // + // * Search is case-insensitive since the default analyzer is used + #endregion + } + + using (var session = store.OpenSession()) + { + #region search_7 + List employees = session + .Query() + + // If you request to include explanations, + // you can see the exact term that was sent to the search engine. + .ToDocumentQuery() + .IncludeExplanations(out var explanations) + .ToQueryable() + + // Provide a term with a wildcard to the Search method: + .Search(x => x.EmployeeNotes, "*rench") + .OfType() + .ToList(); + + // Results will contain all Employee documents that have terms that end with 'rench' + // (e.g. French). + + // Checking the explanations, you can see that the search term 'rench' + // was sent to the search engine WITH the leading wildcard, i.e. '*rench' + // since the 'LowerCaseKeywordAnalyzer' is used in this case. + var explanation = explanations.GetExplanations(employees[0].Id)[0]; + Assert.Contains($"EmployeeNotes:*rench", explanation); + #endregion + } + + using (var asyncSession = store.OpenAsyncSession()) + { + #region search_8 + List employees = await asyncSession + .Query() + + // If you request to include explanations, + // you can see the exact term that was sent to the search engine. + .ToDocumentQuery() + .IncludeExplanations(out var explanations) + .ToQueryable() + + // Provide a term with a wildcard to the Search method: + .Search(x => x.EmployeeNotes, "*rench") + .OfType() + .ToListAsync(); + + // Results will contain all Employee documents that have terms that end with 'rench' + // (e.g. French). + + // Checking the explanations, you can see that the search term 'rench' + // was sent to the search engine WITH the leading wildcard, i.e. '*rench' + // since the 'LowerCaseKeywordAnalyzer' is used in this case. + var explanation = explanations.GetExplanations(employees[0].Id)[0]; + Assert.Contains($"EmployeeNotes:*rench", explanation); + #endregion + } + + using (var session = store.OpenSession()) + { + #region search_9 + List employees = session.Advanced + .DocumentQuery() + + // If you request to include explanations, + // you can see the exact term that was sent to the search engine. + .IncludeExplanations(out var explanations) + + // Provide a term with a wildcard to the Search method: + .Search(x => x.EmployeeNotes, "*rench") + .OfType() + .ToList(); + + // Results will contain all Employee documents that have terms that end with 'rench' + // (e.g. French). + + // Checking the explanations, you can see that the search term 'rench' + // was sent to the search engine WITH the leading wildcard, i.e. '*rench' + // since the 'LowerCaseKeywordAnalyzer' is used in this case. + var explanation = explanations.GetExplanations(employees[0].Id)[0]; + Assert.Contains($"EmployeeNotes:*rench", explanation); + #endregion + } + + using (var session = store.OpenSession()) + { + #region search_10 + List employees = session + .Query() + + .ToDocumentQuery() + .IncludeExplanations(out var explanations) + .ToQueryable() + + // Provide a term with wildcards to the Search method: + .Search(x => x.EmployeeNotes, "*French*") + .OfType() + .ToList(); + + // Even though a wildcard was provided, + // the results will contain only Employee documents that contain the exact term 'French'. + + // The search term was sent to the search engine WITHOUT the wildcard, + // as the custom analyzer's logic strips them out. + + // This can be verified by checking the explanations: + var explanation = explanations.GetExplanations(employees[0].Id)[0]; + Assert.Contains($"EmployeeNotes:french", explanation); + Assert.DoesNotContain($"EmployeeNotes:*french", explanation); + #endregion + } + + using (var asyncSession = store.OpenAsyncSession()) + { + #region search_11 + List employees = await asyncSession + .Query() + + .ToDocumentQuery() + .IncludeExplanations(out var explanations) + .ToQueryable() + + // Provide a term with wildcards to the Search method: + .Search(x => x.EmployeeNotes, "*French*") + .OfType() + .ToListAsync(); + + // Even though a wildcard was provided, + // the results will contain only Employee documents that contain the exact term 'French'. + + // The search term was sent to the search engine WITHOUT the wildcard, + // as the custom analyzer's logic strips them out. + + // This can be verified by checking the explanations: + var explanation = explanations.GetExplanations(employees[0].Id)[0]; + Assert.Contains($"EmployeeNotes:french", explanation); + Assert.DoesNotContain($"EmployeeNotes:*french", explanation); + #endregion + } + + using (var session = store.OpenSession()) + { + #region search_12 + List employees = session.Advanced + .DocumentQuery() + .IncludeExplanations(out var explanations) + // Provide a term with wildcards to the Search method: + .Search(x => x.EmployeeNotes, "*French*") + .OfType() + .ToList(); + + // Even though a wildcard was provided, + // the results will contain only Employee documents that contain the exact term 'French'. + + // The search term was sent to the search engine WITHOUT the wildcard, + // as the custom analyzer's logic strips them out. + + // This can be verified by checking the explanations: + var explanation = explanations.GetExplanations(employees[0].Id)[0]; + Assert.Contains($"EmployeeNotes:french", explanation); + Assert.DoesNotContain($"EmployeeNotes:*french", explanation); + #endregion + } + + using (var session = store.OpenSession()) + { + #region search_13 + List employees = session + .Query() + + .ToDocumentQuery() + .IncludeExplanations(out var explanations) + .ToQueryable() + + // Provide a term with a wildcard to the Search method: + .Search(x => x.FirstName, "Mich*") + .OfType() + .ToList(); + + // Results will contain all Employee documents with FirstName that starts with 'Mich' + // (e.g. Michael). + + // The search term, 'Mich*', is sent to the search engine + // exactly as was provided to the Search method, WITH the wildcard. + + var explanation = explanations.GetExplanations(employees[0].Id)[0]; + Assert.Contains($"FirstName:Mich*", explanation); + #endregion + } + + using (var asyncSession = store.OpenAsyncSession()) + { + #region search_14 + List employees = await asyncSession + .Query() + + .ToDocumentQuery() + .IncludeExplanations(out var explanations) + .ToQueryable() + + // Provide a term with a wildcard to the Search method: + .Search(x => x.FirstName, "Mich*") + .OfType() + .ToListAsync(); + + // Results will contain all Employee documents with FirstName that starts with 'Mich' + // (e.g. Michael). + + // The search term, 'Mich*', is sent to the search engine + // exactly as was provided to the Search method, WITH the wildcard. + + var explanation = explanations.GetExplanations(employees[0].Id)[0]; + Assert.Contains($"FirstName:Mich*", explanation); + #endregion + } + + using (var session = store.OpenSession()) + { + #region search_15 + List employees = session.Advanced + .DocumentQuery() + .IncludeExplanations(out var explanations) + // Provide a term with a wildcard to the Search method: + .Search(x => x.FirstName, "Mich*") + .OfType() + .ToList(); + + // Results will contain all Employee documents with FirstName that starts with 'Mich' + // (e.g. Michael). + + // The search term, 'Mich*', is sent to the search engine + // exactly as was provided to the Search method, WITH the wildcard. + + var explanation = explanations.GetExplanations(employees[0].Id)[0]; + Assert.Contains($"FirstName:Mich*", explanation); + #endregion + } + + #region analyzer_1 + // The custom analyzer: + // ==================== + + const string RemoveWildcardsAnalyzer = + @" + using System.IO; + using Lucene.Net.Analysis; + using Lucene.Net.Analysis.Standard; + namespace CustomAnalyzers + { + public class RemoveWildcardsAnalyzer : StandardAnalyzer + { + public RemoveWildcardsAnalyzer() : base(Lucene.Net.Util.Version.LUCENE_30) + { + } + + public override TokenStream TokenStream(string fieldName, System.IO.TextReader reader) + { + // Read input stream and remove wildcards (*) + string text = reader.ReadToEnd(); + string processedText = RemoveWildcards(text); + StringReader newReader = new StringReader(processedText); + + return base.TokenStream(fieldName, newReader); + } + + private string RemoveWildcards(string input) + { + // Replace wildcard characters with an empty string + return input.Replace(""*"", """"); + } + } + }"; + + // Deploying the custom analyzer: + // ============================== + + store.Maintenance.Send(new PutAnalyzersOperation(new AnalyzerDefinition() + { + Name = "CustomAnalyzers.RemoveWildcardsAnalyzer", + Code = RemoveWildcardsAnalyzer, + })); + #endregion + } + } + } +} diff --git a/Documentation/6.0/Samples/nodejs/indexes/querying/searching.js b/Documentation/6.0/Samples/nodejs/indexes/querying/searching.js new file mode 100644 index 0000000000..5d2ab0c445 --- /dev/null +++ b/Documentation/6.0/Samples/nodejs/indexes/querying/searching.js @@ -0,0 +1,288 @@ +import { DocumentStore, AbstractIndexCreationTask } from "ravendb"; +import assert from "assert"; + +const store = new DocumentStore(); +const session = store.openSession(); + +class Employee { } + +//region index_1 +class Employees_ByNotes extends AbstractJavaScriptIndexCreationTask { + + constructor() { + super(); + + // Define the index-fields + this.map("Employees", e => ({ + employeeNotes: e.Notes + })); + + // Configure the index-field for FTS: + // Set 'Search' on index-field 'employeeNotes' + this.index("employeeNotes", "Search"); + + // Optionally: Set your choice of analyzer for the index-field. + // Here the text from index-field 'employeeNotes' will be tokenized by 'WhitespaceAnalyzer'. + this.analyze("employeeNotes", "WhitespaceAnalyzer"); + + // Note: + // If no analyzer is set then the default 'RavenStandardAnalyzer' is used. + } +} +//endregion + +//region index_2 +class Employees_ByEmployeeData extends AbstractJavaScriptIndexCreationTask { + + constructor() { + super(); + + // Define the index-fields + this.map("Employees", e => ({ + // Multiple document-fields can be indexed + // into the single index-field 'employeeData' + employeeData: [e.FirstName, e.LastName, e.Title, e.Notes] + })); + + // Configure the index-field for FTS: + // Set 'Search' on index-field 'employeeNotes' + this.index("employeeNotes", "Search"); + + // Note: + // Since no analyzer is set then the default 'RavenStandardAnalyzer' is used. + } +} +//endregion + +//region index_3 +class Employees_ByNotes_usingDefaultAnalyzer extends AbstractJavaScriptIndexCreationTask { + + constructor() { + super(); + + // Define the index-fields + this.map("Employees", e => ({ + employeeNotes: e.Notes + })); + + // Configure the index-field for FTS: + this.index("employeeNotes", "Search"); + + // Since no analyzer is explicitly set + // then the default 'RavenStandardAnalyzer' will be used at indexing time. + + // However, when making a search query with wildcards, + // the 'LowerCaseKeywordAnalyzer' will be used to process the search terms + // prior to sending them to the search engine. + } +} +//endregion + +//region index_4 +class Employees_ByNotes_usingCustomAnalyzer extends AbstractJavaScriptIndexCreationTask { + + constructor() { + super(); + + this.map("Employees", e => ({ + employeeNotes: e.Notes + })); + + // Configure the index-field for FTS: + this.index("employeeNotes", "Search"); + + // Set a custom analyzer for the index-field: + this.analyze("employeeNotes", "RemoveWildcardsAnalyzer"); + } +} +//endregion + +//region index_5 +class Employees_ByFirstName_usingExactAnalyzer extends AbstractJavaScriptIndexCreationTask { + + constructor() { + super(); + + this.map("Employees", e => ({ + firstName: e.FirstName + })); + + // Set the Exact analyzer for the index-field: + // (The field will not be tokenized) + this.index("firstName", "Exact"); + } +} +//endregion + +async function searching() { + const session = store.openSession(); + + { + //region search_1 + const employees = await session + // Query the index + .query({ indexName: "Employees/ByNotes" }) + // Call 'search': + // pass the index field name that was configured for FTS and the term to search for. + .search("employeeNotes", "French") + .all(); + + // * Results will contain all Employee documents that have 'French' in their 'Notes' field. + // + // * Search is case-sensitive since field was indexed using the 'WhitespaceAnalyzer' + // which preserves casing. + //endregion + } + + { + //region search_2 + const employees = await session + // Query the static-index + .query({ indexName: "Employees/ByEmployeeData" }) + .openSubclause() + // A logical OR is applied between the following two Search calls: + .search("employeeData", "Manager") + // A logical AND is applied between the following two terms: + .search("employeeData", "French Spanish", "AND") + .closeSubclause() + .all(); + + // * Results will contain all Employee documents that have: + // ('Manager' in any of the 4 document-fields that were indexed) + // OR + // ('French' AND 'Spanish' in any of the 4 document-fields that were indexed) + // + // * Search is case-insensitive since the default analyzer is used + //endregion + } + + { + //region search_3 + let explanations; + + const employees = await session + .query({ indexName: "Employees/ByNotes/usingDefaultAnalyzer" }) + // If you request to include explanations, + // you can see the exact term that was sent to the search engine. + .includeExplanations(e => explanations = e) + // Provide a term with a wildcard to the search method: + .search("employeeNotes", "*rench") + .all(); + + // Results will contain all Employee documents that have terms that end with 'rench' + // (e.g. French). + + // Checking the explanations, you can see that the search term 'rench' + // was sent to the search engine WITH the leading wildcard, i.e. '*rench' + // since the 'LowerCaseKeywordAnalyzer' is used in this case. + const explanation = explanations.explanations[employees[0].id][0]; + const expectedVal = "employeeNotes:*rench"; + + assert.ok(explanation.includes(expectedVal), + `'${explanation}' does not contain '${expectedVal}.'`); + //endregion + } + + { + //region search_4 + let explanations; + + const employees = await session + .query({ indexName: "Employees/ByNotes/usingCustomAnalyzer" }) + .includeExplanations(e => explanations = e) + // Provide a term with wildcards to the Search method: + .search("employeeNotes", "*French*") + .all(); + + // Even though a wildcard was provided, + // the results will contain only Employee documents that contain the exact term 'French'. + + // The search term was sent to the search engine WITHOUT the wildcard, + // as the custom analyzer's logic strips them out. + + // This can be verified by checking the explanations: + const explanation = explanations.explanations[employees[0].id][0]; + + const expectedVal = "employeeNotes:french"; + assert.ok(explanation.includes(expectedVal), + `'${explanation}' does not contain '${expectedVal}.'`); + + const notExpectedVal = "employeeNotes:*french"; + assert.ok(!explanation.includes(notExpectedVal), + `'${explanation}' does not contain '${notExpectedVal}.'`); + //endregion + } + + { + //region search_5 + let explanations; + + const employees = await session + .query({ indexName: "Employees/ByFirstName/usingExactAnalyzer" }) + .includeExplanations(e => explanations = e) + // Provide a term with a wildcard to the Search method: + .search("firstName", "Mich*") + .all(); + + // Results will contain all Employee documents with FirstName that starts with 'Mich' + // (e.g. Michael). + + // The search term, 'Mich*', is sent to the search engine + // exactly as was provided to the Search method, WITH the wildcard. + + const explanation = explanations.explanations[employees[0].id][0]; + const expectedVal = "firstName:Mich*"; + + assert.ok(explanation.includes(expectedVal), + `'${explanation}' does not contain '${expectedVal}.'`); + //endregion + } + + { + //region analyzer_1 + // The custom analyzer: + // ==================== + + const removeWildcardsanalyzer = ` + using System.IO; + using Lucene.Net.Analysis; + using Lucene.Net.Analysis.Standard; + namespace CustomAnalyzers + { + public class RemoveWildcardsAnalyzer : StandardAnalyzer + { + public RemoveWildcardsAnalyzer() : base(Lucene.Net.Util.Version.LUCENE_30) + { + } + + public override TokenStream TokenStream(string fieldName, System.IO.TextReader reader) + { + // Read input stream and remove wildcards (*) + string text = reader.ReadToEnd(); + string processedText = RemoveWildcards(text); + StringReader newReader = new StringReader(processedText); + + return base.TokenStream(fieldName, newReader); + } + + private string RemoveWildcards(string input) + { + // Replace wildcard characters with an empty string + return input.Replace("*", ""); + } + } + }`; + + // Deploying the custom analyzer: + // ============================== + + const analyzerDefinition = { + name: "RemoveWildcardsAnalyzer", + code: RemoveWildcardsAnalyzer + }; + + await documentStore.maintenance.send(new PutAnalyzersOperation(analyzerDefinition)); + //endregion + } +} + diff --git a/Documentation/6.0/Samples/python/Indexes/Querying/Searching.py b/Documentation/6.0/Samples/python/Indexes/Querying/Searching.py new file mode 100644 index 0000000000..983e1e884f --- /dev/null +++ b/Documentation/6.0/Samples/python/Indexes/Querying/Searching.py @@ -0,0 +1,110 @@ +from typing import Any, Dict, List + +from ravendb import AbstractIndexCreationTask, SearchOperator +from ravendb.documents.indexes.definitions import FieldIndexing + +from examples_base import ExampleBase, Employee + + +# region index_1 +class Employees_ByNotes(AbstractIndexCreationTask): + # The IndexEntry class defines the index-fields + class IndexEntry: + def __init__(self, employee_notes: str = None): + self.employee_notes = employee_notes + + def __init__(self): + super().__init__() + # The 'Map' function defines the content of the index-fields + self.map = "from employee in docs.Employees " "select new " "{ " " employee_notes = employee.Notes[0]" "}" + + # Configure the index-field for FTS: + # Set 'FieldIndexing.Search' on index-field 'employee_notes' + self._index("employee_notes", FieldIndexing.SEARCH) + + # Optionally: Set your choice of analyzer for the index-field: + # Here the text from index-field 'EmployeeNotes' will be tokenized by 'WhitespaceAnalyzer'. + self._analyze("employee_notes", "WhitespaceAnalyzer") + + # Note: + # If no analyzer is set then the default 'RavenStandardAnalyzer' is used. + + +# endregion +# region index_2 +class Employees_ByEmployeeData(AbstractIndexCreationTask): + class IndexEntry: + def __init__(self, employee_data: List = None): + self.employee_data = employee_data + + def __init__(self): + super().__init__() + self.map = ( + "from employee in docs.Employees " + "select new {" + " employee_data = " + " {" + # Multiple document-fields can be indexed + # into the single index-field 'employee_data' + " employee.FirstName," + " employee.LastName," + " employee.Title," + " employee.Notes" + " }" + "}" + ) + # Configure the index-field for FTS: + # Set 'FieldIndexing.SEARCH' on index-field 'employee_data' + self._index("employee_data", FieldIndexing.SEARCH) + + # Note: + # Since no analyzer is set then the default 'RavenStandardAnalyzer' is used. + + +# endregion + + +class Searching(ExampleBase): + def setUp(self): + super().setUp() + + def test_searching(self): + with self.embedded_server.get_document_store() as store: + with store.open_session() as session: + # region search_1 + employees = list( + session + # Query the index + .query_index_type(Employees_ByNotes, Employees_ByNotes.IndexEntry) + # Call 'search': + # pass the index field that was configured for FTS and the term to search for. + .search("employee_notes", "French").of_type(Employee) + ) + # * Results will contain all Employee documents that have 'French' in their 'Notes' field. + + # * Search is case-sensitive since field was indexed using the 'WhitespaceAnalyzer' + # which preserves casing. + # endregion + + # region search_4 + employees = list( + session + # Query the static-index + .query_index_type(Employees_ByEmployeeData, Employees_ByEmployeeData.IndexEntry) + .open_subclause() + # A logical OR is applied between the following two search calls + .search("employee_data", "Manager") + # A logical AND is applied between the following two terms + .search("employee_data", "French Spanish", operator=SearchOperator.AND) + .close_subclause() + .of_type(Employee) + ) + + # * Results will contain all Employee documents that have: + # ('Manager' in any of the 4 document-fields that were indexed) + # OR + # ('French' AND 'Spanish' in any of the 4 document-fields that were indexed) + + # * Search is case-insensitive since the default analyzer is used + + # endregion