diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/include-explanations.php.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/include-explanations.php.markdown new file mode 100644 index 0000000000..a14556ce23 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/include-explanations.php.markdown @@ -0,0 +1,64 @@ +# Include Query Explanations + +--- + +{NOTE: } + +* When making a query, each document in the query results is assigned a **score**. + This score determines the order by which the documents come back in the results when requesting + to [order by score](../../../../client-api/session/querying/sort-query-results#order-by-score). + +* Each document in the results includes this score under the `@index-score` property in its metadata. + +* Use `includeExplanations` to get the score details and see how it was calculated. + +* In this page: + * [Include explanations in a query](../../../../client-api/session/querying/debugging/include-explanations#include-explanations-in-a-query) + * [View explanations](../../../../client-api/session/querying/debugging/include-explanations#view-explanations) + * [Syntax](../../../../client-api/session/querying/debugging/include-explanations#syntax) +{NOTE/} + +--- + +{PANEL: Include explanations in a query} + +{CODE-TABS} +{CODE-TAB:php:query explain@ClientApi\Session\Querying\Debugging\IncludeExplanations.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Products" +where search(Name, "Syrup") or search(Name, "Lager") +include explanations() +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE: } +Please note that the First parameter is optional. +If you intend to use the default options, just paste `null` instead of the options object. +{NOTE/} + +{PANEL/} + +{PANEL: View explanations} + +* The detailed explanations can be viewed from the **Query view** in Studio. + +* Running a query with `includeExplanations` will show an additional **Explanations Tab**. + +![Figure 1. Explanations in the Studio](images/include-explanations-1.png "Include explanations") + +* Sample score details: + +![Figure 2. View explanations](images/include-explanations-2.png "View explanation") + +{PANEL/} + +{PANEL: Syntax} + +{CODE:php syntax@ClientApi\Session\Querying\Debugging\IncludeExplanations.php /} + +| Parameters | Data type | Description | +| - | - | - | +| **$options** | `?ExplanationOptions` | This object is optional.
If you intend to use the default options, place `null` here. | +| **&$explanations** | `Explanations` | | + +{PANEL/} diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/include-explanations.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/include-explanations.python.markdown index 9fe1c15ec7..2ed7c3f27d 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/include-explanations.python.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/include-explanations.python.markdown @@ -10,8 +10,7 @@ * Each document in the results includes this score under the `@index-score` property in its metadata. -* **To get the score details** and see how it was calculated, - you can use `include_explanations` when querying with a [document_query](../../../../client-api/session/querying/document-query/what-is-document-query). +* Use `include_explanations` to get the score details** and see how it was calculated. * In this page: * [Include explanations in a query](../../../../client-api/session/querying/debugging/include-explanations#include-explanations-in-a-query) diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.dotnet.markdown index 64045e875a..04630f4920 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.dotnet.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.dotnet.markdown @@ -10,7 +10,7 @@ * By default, the timings stats are Not included in the query results, to avoid the measuring overhead. -* __To include the query timings__ in the query results: +* **To include the query timings** in the query results: add a call to `Timings()` in your query code, or add `include timings()` to an RQL query. See examples below. @@ -41,9 +41,9 @@ include timings() {PANEL: View timings} -* The detailed timings can be viewed from the [Query view](../../../../studio/database/queries/query-view) in the Studio. +* The detailed timings can be viewed from Studio's [Query view](../../../../studio/database/queries/query-view). -* Running an RQL query with `include timings()` will show an additional __Timings Tab__ +* Running an RQL query with `include timings()` will show an additional **Timings Tab** with a graphical representation of the time spent in each query part. ![Figure 1. Include timings graphical results](images/include-timings.png "Include timings results") @@ -56,11 +56,11 @@ include timings() | Parameter | Type | Description | |-------------|----------------|-------------------------------------------------------------| -| __timings__ | `QueryTimings` | An _out_ param that will be filled with the timings results | +| ****timings** | `QueryTimings` | An _out_ param that will be filled with the timings results | | `QueryTimings` | | | |------------------|-------------------------------------|---------------------------------------------------| -| __DurationInMs__ | `long` | Total duration | -| __Timings__ | `IDictionary` | Dictionary with `QueryTimings` info per time part | +| **DurationInMs** | `long` | Total duration | +| **Timings** | `IDictionary` | Dictionary with `QueryTimings` info per time part | {PANEL/} diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.js.markdown index 98394d4a86..36c213a74d 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.js.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.js.markdown @@ -10,7 +10,7 @@ * By default, the timings stats are Not included in the query results, to avoid the measuring overhead. -* __To include the query timings__ in the query results: +* **To include the query timings** in the query results: add a call to `timings()` in your query code, or add `include timings()` to an RQL query. See examples below. @@ -38,9 +38,9 @@ include timings() {PANEL: View timings} -* The detailed timings can be viewed from the [Query view](../../../../studio/database/queries/query-view) in the Studio. +* The detailed timings can be viewed from Studio's [Query view](../../../../studio/database/queries/query-view). -* Running an RQL query with `include timings()` will show an additional __Timings Tab__ +* Running an RQL query with `include timings()` will show an additional **Timings Tab** with a graphical representation of the time spent in each query part. ![Figure 1. Include timings graphical results](images/include-timings.png "Include timings results") @@ -53,11 +53,11 @@ include timings() | Parameter | Type | Description | |---------------------|-----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| __timingsCallback__ | `(timingsCallback) => void` | | +| **timingsCallback** | `(timingsCallback) => void` | | | `QueryTimings` | | | |------------------|--------------------------------|---------------------------------------------------| -| __durationInMs__ | `number` | Total duration | -| __timings__ | `Record` | Dictionary with `QueryTimings` info per time part | +| **durationInMs** | `number` | Total duration | +| **timings** | `Record` | Dictionary with `QueryTimings` info per time part | {PANEL/} diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.php.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.php.markdown new file mode 100644 index 0000000000..08024f3ad5 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.php.markdown @@ -0,0 +1,58 @@ +# Include Query Timings + +--- + +{NOTE: } + +* When making a query, + you can request to get detailed stats of the time spent by RavenDB on each part of the query. + E.g. duration of search, loading documents, transforming results, total duration, etc. + +* By default, the timings stats are Not included in the query results, to avoid the measuring overhead. + +* **To include the query timings** in the query results: + add a call to the `timings()` method in your query code, or add `include timings()` to an RQL query. + See examples below. + +* In this page: + * [Include timings in a query](../../../../client-api/session/querying/debugging/query-timings#include-timings-in-a-query) + * [View timings](../../../../client-api/session/querying/debugging/query-timings#view-timings) + * [Syntax](../../../../client-api/session/querying/debugging/query-timings#syntax) + +{NOTE/} + +--- + +{PANEL: Include timings in a query} + +{CODE-TABS} +{CODE-TAB:php:query timing_2@ClientApi\Session\Querying\Debugging\IncludeQueryTimings.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Products" +where search(Name, "Syrup") or search(Name, "Lager") +include timings() +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: View timings} + +* The detailed timings can be viewed from Studio's [Query view](../../../../studio/database/queries/query-view). + +* Running an RQL query with `include timings()` will show an additional **Timings Tab** + with a graphical representation of the time spent in each query part. + +![Figure 1. Include timings graphical results](images/include-timings.png "Include timings results") + +{PANEL/} + +{PANEL: Syntax} + +{CODE:php syntax@ClientApi\Session\Querying\Debugging\IncludeQueryTimings.php /} + +| Parameter | Type | Description | +|-------------|----------------|---------------| +| **&$timings** | `QueryTimings` | A callback function (action) that takes `QueryTimings` as an argument. It will be called by the client with the resulting `QueryTimings`. You can interact with the resulting `QueryTimings` inside your callback. | + +{PANEL/} diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.python.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.python.markdown index deee58f446..342098abe7 100644 --- a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.python.markdown +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.python.markdown @@ -38,7 +38,7 @@ include timings() {PANEL: View timings} -* The detailed timings can be viewed from the [Query view](../../../../studio/database/queries/query-view) in the Studio. +* The detailed timings can be viewed from Studio's [Query view](../../../../studio/database/queries/query-view). * Running an RQL query with `include timings()` will show an additional **Timings Tab** with a graphical representation of the time spent in each query part. diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/boost-search-results.php.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/boost-search-results.php.markdown new file mode 100644 index 0000000000..16efa6f16d --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/boost-search-results.php.markdown @@ -0,0 +1,78 @@ +# Boost Search Results + +--- + +{NOTE: } + +* When querying with some filtering conditions, + a basic score is calculated for each document in the results by the underlying engine. + +* Providing a boost value to some fields allows you to prioritize the resulting documents. + The boost value is integrated with the basic score, making the document rank higher. + +* Boosting can be achieved in the following ways: + + * **At query time**: + Apply a boost factor to searched terms at query time - as described in this article. + + * **Via index definition**: + Apply a boost factor in your index definition - see this [boosting](../../../../indexes/boosting) indexing article. + +* The automatic ordering of the results by the score is configurable. + Learn more here: [automatic score-based ordering](../../../../indexes/boosting#automatic-score-based-ordering) + +* The calculated score details of the results can be retrieved if needed. + Learn more here: [get resulting score](../../../../client-api/session/querying/sort-query-results#get-resulting-score) + +* In this page: + + * [Boost results - when making a full-text search](../../../../client-api/session/querying/text-search/boost-search-results#boost-results---when-making-a-full-text-search) + * [Boost results - when querying with where clause](../../../../client-api/session/querying/text-search/boost-search-results#boost-results---when-querying-with-where-clause) + +{NOTE/} + +--- + +{PANEL: Boost results - when making a full-text search} + +To apply boosting while running a full-text search, use the +`boost()` method to prioritize the preceding `search()` results. + +{CODE-TABS} +{CODE-TAB:php:query boost_1@ClientApi\Session\Querying\TextSearch\BoostResults.php /} +{CODE-TAB:csharp:documentQuery boost_3@ClientApi\Session\Querying\TextSearch\BoostResults.cs /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" where +search(Notes, "English") or boost(search(Notes, "Italian"), 10) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: Boost results - when querying with where clause} + +`boost()` can be used to give different priorities to the results +returned by different `where` clauses. + +{CODE-TABS} +{CODE-TAB:php:query boost_4@ClientApi\Session\Querying\TextSearch\BoostResults.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Companies" where +boost(startsWith(Name, "O"), 10) or +boost(startsWith(Name, "P"), 50) or +boost(endsWith(Name, "OP"), 90) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +## Related Articles + +### Session + +- [Query overview](../../../../client-api/session/querying/how-to-query) +- [Full-text search](../../../../client-api/session/querying/text-search/full-text-search) + +### Indexes + +- [Full-text search with index](../../../../indexes/querying/searching) diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/ends-with-query.php.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/ends-with-query.php.markdown new file mode 100644 index 0000000000..83ce5efbf2 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/ends-with-query.php.markdown @@ -0,0 +1,74 @@ +# where_ends_with Query + +--- + +{NOTE: } + +* You can query for documents having a field that ends with some specified string. + +* Unless explicitly specified, the string comparisons are case-insensitive by default. + +* **Note**: + This postfix search causes the server to perform a full index scan. + Instead, consider using a static index that indexes the field in reverse order + and then query with a [prefix search](../../../../client-api/session/querying/text-search/starts-with-query), which is much faster. + +* In this page: + * [where_ends_with](../../../../client-api/session/querying/text-search/ends-with-query#where_ends_with) + * [where_ends_with (case-sensitive)](../../../../client-api/session/querying/text-search/ends-with-query#where_ends_with-(case-sensitive)) + * [Negate where_ends_with](../../../../client-api/session/querying/text-search/ends-with-query#negate-where_ends_with) + +{NOTE/} + +--- + +{PANEL: where_ends_with} + +{CODE-TABS} +{CODE-TAB:php:query endsWith_1@ClientApi\Session\Querying\TextSearch\EndsWith.php /} +{CODE-TAB:csharp:documentQuery endsWith_3@ClientApi\Session\Querying\TextSearch\EndsWith.cs /} +{CODE-TAB-BLOCK:sql:RQL} +from "Products" +where endsWith(Name, "Lager") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: where_ends_with (case-sensitive)} + +{CODE-TABS} +{CODE-TAB:php:query endsWith_4@ClientApi\Session\Querying\TextSearch\EndsWith.php /} +{CODE-TAB:csharp:documentQuery endsWith_6@ClientApi\Session\Querying\TextSearch\EndsWith.cs /} +{CODE-TAB-BLOCK:sql:RQL} +from "Products" +where exact(endsWith(Name, "Lager")) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: Negate where_ends_with} + +{CODE-TABS} +{CODE-TAB:php:query endsWith_7@ClientApi\Session\Querying\TextSearch\EndsWith.php /} +{CODE-TAB:csharp:documentQuery endsWith_9@ClientApi\Session\Querying\TextSearch\EndsWith.cs /} +{CODE-TAB-BLOCK:sql:RQL} +from "Products" +where (true and not endsWith(Name, "Lager")) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +## Related Articles + +### Session + +- [Query overview](../../../../client-api/session/querying/how-to-query) +- [Starts-With query](../../../../client-api/session/querying/text-search/starts-with-query) +- [Full-text search](../../../../client-api/session/querying/text-search/full-text-search) + +### Indexes + +- [map indexes](../../../../indexes/map-indexes) diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/exact-match-query.php.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/exact-match-query.php.markdown new file mode 100644 index 0000000000..a86422ac58 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/exact-match-query.php.markdown @@ -0,0 +1,92 @@ +# Exact Match Query + +--- + +{NOTE: } + +* By default, when querying strings the string comparisons are **case-insensitive**. + +* To perform a **case-sensitive** search, use the `whereEquals` or `whereNotEquals` + method with its `exact` parameter set to `true`. + +* When making a dynamic query with an exact match, the auto-index created by the server indexes + the text of the document field using the [default exact analyzer](../../../../indexes/using-analyzers#ravendb) + where the casing of the original text is unchanged. + +* In this page: + * [Query with exact match](../../../../client-api/session/querying/text-search/exact-match-query#query-with-exact-match) + * [Query with exact match - nested object](../../../../client-api/session/querying/text-search/exact-match-query#query-with-exact-match---nested-object) + * [Syntax](../../../../client-api/session/querying/text-search/exact-match-query#syntax) + +{NOTE/} + +--- + +{PANEL: Query with exact match} + +{NOTE: } + +{CODE-TABS} +{CODE-TAB:php:query exact_1@ClientApi\Session\Querying\TextSearch\ExactMatch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where exact(FirstName == "Robert") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +* Executing the above query will generate the auto-index `Auto/Employees/ByExact(FirstName)`. + +* This auto-index will contain the following two index-fields: + + * `FirstName` + Contains terms with the text from the indexed document field 'FirstName'. + Text is lower-cased and not tokenized. + + * `exact(FirstName)` + Contain terms with the original text from the indexed document field 'FirstName'. + Casing is exactly the same as in the original text, and the text is not tokenized. + Making an exact query targets these terms to find matching documents. + +{PANEL/} + +{PANEL: Query with exact match - nested object} + +{NOTE: } + +{CODE-TABS} +{CODE-TAB:php:query exact_4@ClientApi\Session\Querying\TextSearch\ExactMatch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Orders" +where exact(Lines.ProductName == "Teatime Chocolate Biscuits") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{PANEL/} + +{PANEL: Syntax} + +{CODE:php syntax@ClientApi\Session\Querying\TextSearch\ExactMatch.php /} + +| Parameter | Type | Description | +|---------------|----------------------------|-------------| +| **$fieldName** | `string` | Search-field name | +| **$value** | `string` | string to match with match condition | +| **$exact** | `bool` | `false` - search is case-insensitive
`true` - search is case-sensitive | + +| Return Type | Description | +| ------------- | ----- | +| `DocumentQueryInterface` | Query results | + +{PANEL/} + +## Related Articles + +### Session + +- [Query overview](../../../../client-api/session/querying/how-to-query) +- [Full-text search](../../../../client-api/session/querying/text-search/full-text-search) +- [How to Use Regex](../../../../client-api/session/querying/text-search/using-regex) diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/full-text-search.php.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/full-text-search.php.markdown new file mode 100644 index 0000000000..e701973532 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/full-text-search.php.markdown @@ -0,0 +1,327 @@ +# Full-Text Search + +--- + +{NOTE: } + +* This article is about running a full-text search with a **dynamic query**. + To learn how to run a full-text search using a static-index, see [full-text search with index](../../../../indexes/querying/searching). + +* Use the `search()` method to query for documents that contain specified term/s + within the text of the specified document field/s. + +* When running a full-text search with a dynamic query, the **auto-index** created by the server + breaks down the text of the searched document field using the [default search analyzer](../../../../indexes/using-analyzers#ravendb). + All generated terms are lower-cased, so the search is **case-insensitive**. + +* Gain additional control over term tokenization by running a full-text search + using a [static-index](../../../../indexes/querying/searching), where the used + analyzer is configurable. + +{INFO: } + +* A **boost** value can be set for each search to prioritize results. + Learn more in [boost search results](../../../../client-api/session/querying/text-search/boost-search-results). + +* User experience can be enhanced by requesting text fragments that **highlight** + the searched terms in the results. Learn more in [highlight search results](../../../../client-api/session/querying/text-search/highlight-query-results). +{INFO/} + +--- + +* In this page: + * [Search for single term](../../../../client-api/session/querying/text-search/full-text-search#search-for-single-term) + * [Search for multiple terms](../../../../client-api/session/querying/text-search/full-text-search#search-for-multiple-terms) + * [Search in multiple fields](../../../../client-api/session/querying/text-search/full-text-search#search-in-multiple-fields) + * [Search in complex object](../../../../client-api/session/querying/text-search/full-text-search#search-in-complex-object) + * [Search operators](../../../../client-api/session/querying/text-search/full-text-search#search-operators) + * [Search options](../../../../client-api/session/querying/text-search/full-text-search#search-options) + * [Using wildcards](../../../../client-api/session/querying/text-search/full-text-search#using-wildcards) + * [Syntax](../../../../client-api/session/querying/text-search/full-text-search#syntax) + +{NOTE/} + +--- + +{PANEL: Search for single term} + +{NOTE: } + +{CODE-TABS} +{CODE-TAB:php:query fts_1@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB:php:documentQuery fts_3@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where search(Notes, "University") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +* Executing the above query will generate the auto-index `Auto/Employees/BySearch(Notes)`. + +* This auto-index will contain the following two index-fields: + + * `Notes` + Contains terms with the original text from the indexed document field 'Notes'. + Text is lower-cased and Not tokenized. + + * `search(Notes)` + Contains **lower-cased terms** that were tokenized from the 'Notes' field by the [default search analyzer](../../../../indexes/using-analyzers#ravendb) (RavenStandardAnalyzer). + Calling the `search()` method targets these terms to find matching documents. + +{PANEL/} + +{PANEL: Search for multiple terms} + +* You can search for multiple terms in the **same field** in a single search method. + +* By default, the logical operator between these terms is 'OR'. + +* This behavior can be modified. See section [Search operators](../../../../client-api/session/querying/text-search/full-text-search#search-operators). + +{NOTE: } + +**Pass terms in a string**: + +{CODE-TABS} +{CODE-TAB:php:query fts_4@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB:php:documentQuery fts_6@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where search(Notes, "University Sales Japanese") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{NOTE: } + +**Pass terms in a list**: + +{CODE-TABS} +{CODE-TAB:php:query fts_7@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where search(Notes, "University Sales Japanese") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{PANEL/} + +{PANEL: Search in multiple fields} + +* You can search for terms in **different fields** by making multiple search calls. + +* By default, the logical operator between consecutive search methods is 'OR'. + +* This behavior can be modified. See section [Search operators](../../../../client-api/session/querying/text-search/full-text-search#search-operators). + +{NOTE: } + +{CODE-TABS} +{CODE-TAB:php:query fts_9@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB:php:documentQuery fts_11@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where (search(Notes, "French") or search(Title, "President")) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{PANEL/} + +{PANEL: Search in complex object} + +* You can search for terms within a complex object. + +* Any nested text field within the object is searchable. + +{NOTE: } + +{CODE-TABS} +{CODE-TAB:php:query fts_12@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB:php:documentQuery fts_14@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Companies" +where search(Address, "USA London") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{PANEL/} + +{PANEL: Search operators} + +* By default, the logical operator between multiple terms within the **same field** in a search call is **OR**. + +* This can be modified using the `@operator` parameter as follows: + +{NOTE: } + +**AND**: + +{CODE-TABS} +{CODE-TAB:php:query fts_15@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB:php:documentQuery fts_17@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where search(Notes, "College German", and) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{NOTE: } + +**OR**: + +{CODE-TABS} +{CODE-TAB:php:query fts_18@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB:php:documentQuery fts_20@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where search(Notes, "College German") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{PANEL/} + +{PANEL: Search options} + +Search options allow to: + +* Negate a search criteria. +* Specify the logical operator used between **consecutive search calls**. + +{NOTE: } + +**Negate search**: + +{CODE-TABS} +{CODE-TAB:php:query fts_21@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB:php:documentQuery fts_23@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Companies" +where (exists(Address) and not search(Address, "USA")) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{NOTE: } + +**Default behavior between search calls**: + +* By default, the logical operator between consecutive search methods is **OR**. + +{CODE-TABS} +{CODE-TAB:php:query fts_24@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB:php:documentQuery fts_26@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Companies" +where Contact.Title == "Owner" and +(search(Address.Country, "France") or search(Name, "Markets")) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{NOTE: } +**AND search calls**: + +{CODE-TABS} +{CODE-TAB:php:query fts_27@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB:php:documentQuery fts_29@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where search(Notes, "French") and search(Title, "Manager") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{NOTE: } + +**Use options as bit flags**: + +{CODE-TABS} +{CODE-TAB:php:query fts_30@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB:php:documentQuery fts_32@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where search(Notes, "French") and +(exists(Title) and not search(Title, "Manager")) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{PANEL/} + +{PANEL: Using wildcards} + +* Wildcards can be used to replace: + * Prefix of a searched term + * Postfix of a searched term + * Both prefix & postfix + +* Note: + + * Searching with a wildcard as the prefix of the term (e.g. `*text`) is + not advised as it will cause the server to perform a full index scan. + + * Instead, consider using a static-index that indexes the field in reverse order + and then query with a wildcard as the postfix, which is much faster. + +{NOTE: } + +{CODE-TABS} +{CODE-TAB:php:query fts_33@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB:php:documentQuery fts_35@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" where +search(Notes, "art*") or +search(Notes, "*logy") or +search(Notes, "*mark*") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{NOTE/} + +{PANEL/} + +{PANEL: Syntax} + +{CODE:php syntax@ClientApi\Session\Querying\TextSearch\FullTextSearch.php /} + +| Parameter | Type | Description | +|-----------|------|-------------| +| **$fieldName** | `string` | Name of the searched field. | +| **$searchTerms** | `string` | A string containing the term or terms (separated by spaces) to search for. | +| **$operator** | `?SearchOperator ` | Logical operator to use between multiple terms in the same Search method.
**Can be**: `SearchOperator::or` or `SearchOperator::and`
**Default**: `SearchOperator::or` | + +| Return Type | Description | +| ------------| ----------- | +| `DocumentQueryInterface` | Query results | + +{PANEL/} + +## Related Articles + +### Session + +- [Query overview](../../../../client-api/session/querying/how-to-query) +- [How to Use Regex](../../../../client-api/session/querying/text-search/using-regex) +- [How to Query With Exact Match](../../../../client-api/session/querying/text-search/exact-match-query) + +### Indexes + +- [Analyzers](../../../../indexes/using-analyzers) +- [Full-text search with index](../../../../indexes/querying/searching) diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/fuzzy-search.php.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/fuzzy-search.php.markdown new file mode 100644 index 0000000000..e38537c6fd --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/fuzzy-search.php.markdown @@ -0,0 +1,50 @@ +# Fuzzy Search + +--- + +{NOTE: } + +* A **fuzzy search** retrieves documents containing terms that closely match a given term + rather than exact matches, assisting in finding relevant results when the search term is + misspelled or has minor variations. + +* In this page: + * [Fuzzy search example](../../../../client-api/session/querying/text-search/fuzzy-search#fuzzy-search-example) + * [Syntax](../../../../client-api/session/querying/text-search/fuzzy-search#syntax) + +{NOTE/} + +--- + +{PANEL: Fuzzy search example} + +{CODE-TABS} +{CODE-TAB:php:query fuzzy_1@ClientApi\Session\Querying\TextSearch\FuzzySearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Companies" +where fuzzy(Name = "Ernts Hnadel", 0.5) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: Syntax} + +{CODE:php syntax@ClientApi\Session\Querying\TextSearch\FuzzySearch.php /} + +| Parameter | Type | Description | +|-------------|-----------|-------------| +| **$fuzzy** | `float` | A value between `0.0` and `1.0`.
With a value closer to `1.0`, terms with a higher similarity are matched. | + +| Return Type | Description | +| ----------- | ----------- | +| `DocumentQueryInterface` | Query results | + +{PANEL/} + +## Related Articles + +### Session + +- [Query overview](../../../../client-api/session/querying/how-to-query) +- [Full-text search](../../../../client-api/session/querying/text-search/full-text-search) diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/highlight-query-results.php.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/highlight-query-results.php.markdown new file mode 100644 index 0000000000..1867782027 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/highlight-query-results.php.markdown @@ -0,0 +1,187 @@ +# Highlight Search Results +--- + +{NOTE: } + +* When making a [Full-Text Search query](../../../../client-api/session/querying/text-search/full-text-search), + in addition to retrieving documents that contain the searched terms in the results, + you can also request to get a **list of text fragments that highlight the searched terms**. + +* The highlighted terms can enhance user experience when searching for documents with specific content. + +* This article shows highlighting search results when making a **dynamic-query**. + For highlighting search results when querying a **static-index** see [highlight index search results](../../../../indexes/querying/highlighting). + +--- + +* In this page: + * [Highlight - basic example](../../../../client-api/session/querying/text-search/highlight-query-results#highlight---basic-example) + * [Highlight tags](../../../../client-api/session/querying/text-search/highlight-query-results#highlight-tags) + * [Highlight results in Studio](../../../../client-api/session/querying/text-search/highlight-query-results#highlight-results-in-studio) + * [Highlight - customize tags](../../../../client-api/session/querying/text-search/highlight-query-results#highlight---customize-tags) + * [Highlight - projected results](../../../../client-api/session/querying/text-search/highlight-query-results#highlight---projected-results) + * [Syntax](../../../../client-api/session/querying/text-search/highlight-query-results#syntax) + +{NOTE/} + +--- + +{PANEL: Highlight - basic example} + +{CODE-TABS} +{CODE-TAB:php:query highlight_1@ClientApi\Session\Querying\TextSearch\HighlightQueryResults.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where search(Notes, "sales") +include highlight(Notes, 35, 4) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{CODE:php fragments_1@ClientApi\Session\Querying\TextSearch\HighlightQueryResults.php /} + +{NOTE: } + +#### Highlight tags + +* By default, the highlighted term is wrapped with the following html: + `term` + +* When requesting to highlight multiple terms, + the background color returned for each different term will be in the following order: + + -  yellow, + -  lawngreen, + -  aquamarine, + -  magenta, + -  palegreen, + -  coral, + -  wheat, + -  khaki, + -  lime, + -  deepskyblue, + -  deeppink, + -  salmon, + -  peachpuff, + -  violet, + -  mediumpurple, + -  palegoldenrod, + -  darkkhaki, + -  springgreen, + -  turquoise, + -  powderblue + +* The html tags that wrap the highlighted terms can be **customized** to any other tags. + See [customize tags](../../../../client-api/session/querying/text-search/highlight-query-results#highlight---customize-tags) below. + +{NOTE/} + +{NOTE: } + +#### Highlight results in Studio + +![Figure 1. Fragments results](images/fragmentsResults.png "View highlighted fragments in the Query View") + +1. **Auto-Index** + This is the auto-index that was created by the server to serve the dynamic-query. + +2. **Results tab** + The results tab contains the resulting **documents** that match the provided RQL query. + +3. **Highlight tab** + The highlight tab shows the resulting **fragments** that were included in the query result. + +{NOTE/} + +{PANEL/} + +{PANEL: Highlight - customize tags} + +* The html tags that wrap the highlighted terms can be **customized** to any other tags. + +{CODE-TABS} +{CODE-TAB:php:query highlight_4@ClientApi\Session\Querying\TextSearch\HighlightQueryResults.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where (search(Notes, "sales") or search(Title, "manager")) +include highlight(Notes, 35, 1, $p0), highlight(Title, 35, 1, $p1) +{ +"p0":{"PreTags":["+++","<<<"],"PostTags":["+++",">>>"]}, +"p1":{"PreTags":["+++","<<<"],"PostTags":["+++",">>>"]} +} +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{CODE:php fragments_2@ClientApi\Session\Querying\TextSearch\HighlightQueryResults.php /} + +{PANEL/} + +{PANEL: Highlight - projected results} + +* Highlighting can also be used when [projecting query results](../../../../client-api/session/querying/how-to-project-query-results). + +{CODE-TABS} +{CODE-TAB:php:query highlight_6@ClientApi\Session\Querying\TextSearch\HighlightQueryResults.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" as x +where search(x.Notes, "manager german") +select { Name : "{0} {1}".format(x.FirstName, x.LastName), Title : x.Title } +include highlight(Notes, 35, 2) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{CODE:php fragments_3@ClientApi\Session\Querying\TextSearch\HighlightQueryResults.php /} + +{PANEL/} + +{PANEL: Syntax} + +{CODE:php syntax_1@ClientApi\Session\Querying\TextSearch\HighlightQueryResults.php /} + +| Parameter | Type | Description | +|--------------------|-------------------------------|-------------------------------------| +| **$fieldName** | `?string` | Name of the field that contains the searched terms to highlight | +| **$fragmentLength** | `int` | Maximum length of a text fragment
Must be `>= 18` | +| **$fragmentCount** | `int` | Maximum number of text fragments that will be returned | +| **$options** | `?HighlightingOptions ` | Customizing options | +| **&$highlightings** | `Highlightings` | A callback function to retrieve the highlighted text fragments for each returned result | + +
+ +**Highlighting options**: + +{CODE:php syntax_2@ClientApi\Session\Querying\TextSearch\HighlightQueryResults.php /} + +| Option | Type | Description | +|--------------|-----------|--------------| +| **$groupKey** | `?string` | Grouping key for the results.
Used when highlighting query results from a [Map-Reduce index](../../../../indexes/querying/highlighting#highlight-results---map-reduce-index).
If `None` results are grouped by document ID (default).
Note: Highlighting is Not available for dynamic aggregation queries. | +| **$preTags** | `?StringArray` | Array of PRE tags used to wrap the highlighted search terms in the text fragments. | +| **$postTags** | `?StringArray` | Array of POST tags used to wrap the highlighted search terms in the text fragments. | + +
+ +**Highlightings object**: + +{CODE:php syntax_3@ClientApi\Session\Querying\TextSearch\HighlightQueryResults.php /} + +| Property | Type | Description | +|--------------------|------------|-------------| +| **$fieldName** | `?string` | Name of the field that contains the searched terms to highlight | +| **getResultIndents()** | function returning an `array` | The resulting keys (document IDs, or the map-reduce keys) | + +{CODE:php syntax_4@ClientApi\Session\Querying\TextSearch\HighlightQueryResults.php /} + +| Method | Return Type | Description | +|-------------------|-------------|-------------| +| **getFragments(?string $key)** | function returning an `array` | Returns the list of the highlighted text fragments for the passed document ID, or the map-reduce key | + +{PANEL/} + +## Related articles + +### Session + +- [Query overview](../../../../client-api/session/querying/how-to-query) + +### Indexes + +- [Highlight index search results](../../../../indexes/querying/highlighting) diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/proximity-search.php.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/proximity-search.php.markdown new file mode 100644 index 0000000000..7c3b4f2d75 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/proximity-search.php.markdown @@ -0,0 +1,122 @@ +# Proximity Search + +--- + +{NOTE: } + +* A **proximity search** retrieves documents containing search terms that are located within a specified distance from each other. + The distance is measured by the number of intermediate terms. + +* Use the `proximity` method when running a **full-text search** by the [search](../../../../client-api/session/querying/text-search/full-text-search) method. + +* In this page: + * [Why use proximity search](../../../../client-api/session/querying/text-search/proximity-search#why-use-proximity-search) + * [How proximity works](../../../../client-api/session/querying/text-search/proximity-search#how-proximity-works) + * [Proximity search examples](../../../../client-api/session/querying/text-search/proximity-search#proximity-search-examples) + * [Syntax](../../../../client-api/session/querying/text-search/proximity-search#syntax) + +{NOTE/} + +--- + +{PANEL: Why use proximity search} + +* A basic linguistic assumption is that the proximity of words implies a relationship between them. + +* Proximity search helps match phrases while avoiding scattered or spread-out terms in the text. + +* By limiting the search to only include matches where the terms are within the specified maximum proximity, + the search results can be more relevant than those with scattered terms. + +{PANEL/} + +{PANEL: How proximity works} + +* When searching with some specified distance between search terms `term1` and `term2`: + + * Retrieved documents will contain text in which `term1` and `term2` are separated by + the maximum number of terms specified or less. + + * The search terms can be separated by fewer terms, but not more than the specified distance. + + * Only the terms generated by the [search analyzer](../../../../indexes/using-analyzers#ravendb) + are considered towards the count of the maximum distance. + Words or tokens that are Not part of the generated terms are Not included in the proximity calculation. + +* Note: + + * Search criteria should contain at least 2 search terms. + + * Search terms must be simple string terms without wildcards. + +{PANEL/} + +{PANEL: Proximity search examples} + +## Proximity search (0 distance) + +{CODE-TABS} +{CODE-TAB:php:Query proximity_1@ClientApi\Session\Querying\TextSearch\ProximitySearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where proximity(search(Notes, "fluent french"), 0) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +Running the above query on the Northwind sample data returns the following Employee documents: +`employees/2-A` +`employees/5-A` +`employees/9-A` + +Each resulting document has the text 'fluent in French' in its 'Notes' field. + +The word "in" is not taken into account as it is Not part of the terms list generated +by the analyzer. (Search is case-insensitive in this case.) + +{NOTE: } +Documents containing text with the search terms appearing with no words between them +(e.g. "fluent french") will also be returned. +{NOTE/} + +## Proximity search (distance > 0) + +{CODE-TABS} +{CODE-TAB:php:Query proximity_3@ClientApi\Session\Querying\TextSearch\ProximitySearch.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Employees" +where proximity(search(Notes, "fluent french"), 5) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +Running the above query on the Northwind sample data returns the following Employee documents: +`employees/2-A` +`employees/5-A` +`employees/6-A` +`employees/9-A` + +This time document 'employees/6-A' was added to the previous results since it contains the phrase: +"fluent in Japanese and can read and write French" +where the search terms are separated by a count of 4 terms. + +"in" & "and" are not taken into account as they are not part of the terms list generated +by the analyzer.(Search is case-insensitive in this case). + +{PANEL/} + +{PANEL: Syntax} + +{CODE:php syntax@ClientApi\Session\Querying\TextSearch\ProximitySearch.php /} + +| Parameter | Type | Description | +|---------------|-------|-------------------------------------------------------------------------------| +| **$proximity** | `int` | The maximum number of terms between the search terms.
Can be `0` or more. | + +{PANEL/} + +## Related Articles + +### Session + +- [Full-text search](../../../../client-api/session/querying/text-search/full-text-search) +- [Query overview](../../../../client-api/session/querying/how-to-query) +- [What is a DocumentQuery](../../../../client-api/session/querying/document-query/what-is-document-query) diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/starts-with-query.php.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/starts-with-query.php.markdown new file mode 100644 index 0000000000..eecb706ec1 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/starts-with-query.php.markdown @@ -0,0 +1,76 @@ +# Starts-With Query + +--- + +{NOTE: } + +* You can query for documents having a field that starts with some specified string. + +* Unless explicitly specified, the string comparisons are case-insensitive by default. + +* In this page: + * [StartsWith](../../../../client-api/session/querying/text-search/starts-with-query#startswith) + * [StartsWith (case-sensitive)](../../../../client-api/session/querying/text-search/starts-with-query#startswith-(case-sensitive)) + * [Negate StartsWith](../../../../client-api/session/querying/text-search/starts-with-query#negate-startswith) + +{NOTE/} + +--- + +{PANEL: StartsWith} + +The results will contain only Product documents having a 'Name' field +that starts with any case variation of 'ch'. + +{CODE-TABS} +{CODE-TAB:php:query startsWith_1@ClientApi\Session\Querying\TextSearch\StartsWith.php /} +{CODE-TAB:php:documentQuery startsWith_3@ClientApi\Session\Querying\TextSearch\StartsWith.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Products" +where startsWith(Name, "Ch") +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: StartsWith (case-sensitive)} + +The results will contain only Product documents having a 'Name' field +that starts with 'Ch'. + +{CODE-TABS} +{CODE-TAB:php:query startsWith_4@ClientApi\Session\Querying\TextSearch\StartsWith.php /} +{CODE-TAB:php:documentQuery startsWith_6@ClientApi\Session\Querying\TextSearch\StartsWith.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Products" +where exact(startsWith(Name, "Ch")) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: Negate StartsWith} + +The results will contain only Product documents having a 'Name' field +that does NOT start with 'ch' or any other case variations of it. + +{CODE-TABS} +{CODE-TAB:php:query startsWith_7@ClientApi\Session\Querying\TextSearch\StartsWith.php /} +{CODE-TAB:php:documentQuery startsWith_9@ClientApi\Session\Querying\TextSearch\StartsWith.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Products" +where (true and not startsWith(Name, "Ch")) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +## Related Articles + +### Session + +- [Query overview](../../../../client-api/session/querying/how-to-query) +- [Ends-With query](../../../../client-api/session/querying/text-search/ends-with-query) +- [Full-text search](../../../../client-api/session/querying/text-search/full-text-search) + + diff --git a/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/using-regex.php.markdown b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/using-regex.php.markdown new file mode 100644 index 0000000000..1cd13eb4b9 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/client-api/session/querying/text-search/using-regex.php.markdown @@ -0,0 +1,35 @@ +# Using Regex + +To return only documents that match a regular expression ("regex"), +use the `whereRegex` method which enables RavenDB to perform server-side pattern matching queries. + +The supplied regular expression must be [.NET compatible](https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex?view=netframework-4.7.1). + +## Example + +Load all products whose name starts with 'N' or 'A'. + +{CODE-TABS} +{CODE-TAB:php regex_1@ClientApi\Session\Querying\TextSearch\UsingRegex.php /} +{CODE-TAB-BLOCK:sql:RQL} +from Products +where regex(Name, '^[NA]') +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +## Syntax + +{CODE:php syntax@ClientApi\Session\Querying\TextSearch\UsingRegex.php /} + +| Parameter | Type | Description | +|---------------|-------|-------------------------------------------------------------------------------| +| **$fieldName** | `?string` | Name of the field to query | +| **$pattern** | `?string` | Pattern to query for | + +## Related Articles + +### Session + +- [Query overview](../../../../client-api/session/querying/how-to-query) +- [Full-text search](../../../../client-api/session/querying/text-search/full-text-search) +- [Query with exact match](../../../../client-api/session/querying/text-search/exact-match-query) diff --git a/Documentation/5.4/Samples/php/ClientApi/session/Querying/Debugging/IncludeExplanations.php b/Documentation/5.4/Samples/php/ClientApi/session/Querying/Debugging/IncludeExplanations.php new file mode 100644 index 0000000000..68500fe003 --- /dev/null +++ b/Documentation/5.4/Samples/php/ClientApi/session/Querying/Debugging/IncludeExplanations.php @@ -0,0 +1,41 @@ +openSession(); + try { + # region explain + $explanations = new Explanations(); + + /** @var array $syrups */ + $syrups = $session->advanced()->documentQuery(Product::class) + ->includeExplanations(null, $explanations) + ->search("Name", "Syrup") + ->toList(); + + $scoreDetails = $explanations->getExplanations($syrups[0]->getId()); + # endregion + } finally { + $session->close(); + } + } finally { + $store->close(); + } + } +} diff --git a/Documentation/5.4/Samples/php/ClientApi/session/Querying/Debugging/IncludeQueryTimings.php b/Documentation/5.4/Samples/php/ClientApi/session/Querying/Debugging/IncludeQueryTimings.php new file mode 100644 index 0000000000..ff7d0a0d23 --- /dev/null +++ b/Documentation/5.4/Samples/php/ClientApi/session/Querying/Debugging/IncludeQueryTimings.php @@ -0,0 +1,42 @@ +openSession(); + try { + # region timing_2 + $timings = new QueryTimings(); + + /** @var array $resultsWithTimings */ + $resultsWithTimings = $session->advanced()->documentQuery(Product::class) + ->timings($timings) + ->search("Name", "Syrup") + ->toList(); + + /** @var array $timingsMap */ + $timingsMap = $timings->getTimings(); + # endregion + } finally { + $session->close(); + } + } finally { + $store->close(); + } + } +} diff --git a/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/BoostResults.php b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/BoostResults.php new file mode 100644 index 0000000000..a4404a7a74 --- /dev/null +++ b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/BoostResults.php @@ -0,0 +1,100 @@ +openSession(); + try { + # region boost_1 + /** @var array $employees */ + $employees = $session + // Make a dynamic full-text search Query on 'Employees' collection + ->query(Employee::class) + // This search predicate will use the default boost value of 1 + ->search("Notes", "English") + // * This search predicate will use a boost value of 10 + ->search("Notes", "Italian") + // Call 'boost()' to set the boost value of the previous 'search()' call + ->boost(10) + ->toList(); + + // * Results will contain all Employee documents that have + // EITHER 'English' OR 'Italian' in their 'Notes' field (case-insensitive). + // + // * Matching documents that contain 'Italian' will get a HIGHER score + // than those that contain 'English'. + // + // * Unless configured otherwise, the resulting documents will be ordered by their score. + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region boost_3 + /** @var array $employees */ + $employees = $session->advanced() + // Make a dynamic full-text search DocumentQuery on 'Employees' collection + ->documentQuery(Employee::class) + // This search predicate will use the default boost value of 1 + ->search("Notes", "English") + // * This search predicate will use a boost value of 10 + ->search("Notes", "Italian") + // Call 'boost()' to set the boost value of the previous 'search()' call + ->boost(10) + ->toList(); + + // * Results will contain all Employee documents that have + // EITHER 'English' OR 'Italian' in their 'Notes' field (case-insensitive). + // + // * Matching documents that contain 'Italian' will get a HIGHER score + // than those that contain 'English'. + // + // * Unless configured otherwise, the resulting documents will be ordered by their score. + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region boost_4 + /** @var array $companies */ + $companies = $session->advanced() + // Make a dynamic DocumentQuery on 'Companies' collection + ->documentQuery(Company::class) + // Define a 'Where' condition + ->WhereStartsWith("Name", "O") + // Call 'Boost' to set the boost value of the previous 'Where' predicate + ->boost(10) + // Call 'OrElse' so that OR operator will be used between statements + ->orElse() + ->whereStartsWith("Name", "P") + ->boost(50) + ->orElse() + ->whereEndsWith("Name", "OP") + ->boost(90) + ->toList(); + + // * Results will contain all Company documents that either + // (start-with 'O') OR (start-with 'P') OR (end-with 'OP') in their 'Name' field (case-insensitive). + // + // * Matching documents that end-with 'OP' will get the HIGHEST scores. + // Matching documents that start-with 'O' will get the LOWEST scores. + // + // * Unless configured otherwise, the resulting documents will be ordered by their score. + # endregion + } finally { + $session->close(); + } + } finally { + $store->close(); + } + } +} diff --git a/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/EndsWith.php b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/EndsWith.php new file mode 100644 index 0000000000..cd998870ef --- /dev/null +++ b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/EndsWith.php @@ -0,0 +1,126 @@ +openSession(); + try { + # region endsWith_1 + /** @var array $products */ + $products = $session + ->query(Product::class) + // Call 'whereEndsWith' on the field + // Pass the postfix to search by + ->whereEndsWith("Name", "Lager") + ->toList(); + + // Results will contain only Product documents having a 'Name' field + // that ends with any case variation of 'lager' + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region endsWith_3 + /** @var array $products */ + $products = $session->advanced() + ->documentQuery(Product::class) + // Call 'whereEndsWith' + // Pass the document field and the postfix to search by + ->whereEndsWith("Name", "Lager") + ->toList(); + + // Results will contain only Product documents having a 'Name' field + // that ends with any case variation of 'lager' + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region endsWith_4 + /** @var array $products */ + $products = $session + ->query(Product::class) + // Pass 'exact: true' to search for an EXACT postfix match + ->whereEndsWith("Name", "Lager", true) + ->toList(); + + // Results will contain only Product documents having a 'Name' field + // that ends with 'Lager' + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region endsWith_6 + /** @var array $products */ + $products = $session->advanced() + ->documentQuery(Product::class) + // Call 'whereEndsWith' + // Pass 'exact: true' to search for an EXACT postfix match + ->whereEndsWith("Name", "Lager", true) + ->toList(); + + // Results will contain only Product documents having a 'Name' field + // that ends with 'Lager' + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region endsWith_7 + /** @var array $products */ + $products = $session + ->query(Product::class) + // Call 'Not' to negate the next predicate + ->not() + // Call 'whereEndsWith' on the field + // Pass the postfix to search by + ->whereEndsWith("Name", "Lager") + ->toList(); + + // Results will contain only Product documents having a 'Name' field + // that does NOT end with 'lager' or any other case variations of it + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region endsWith_9 + /** @var array $products */ + $products = $session->advanced() + ->documentQuery(Product::class) + // Call 'Not' to negate the next predicate + ->not() + // Call 'whereEndsWith' + // Pass the document field and the postfix to search by + ->whereEndsWith("Name", "Lager") + ->toList(); + + // Results will contain only Product documents having a 'Name' field + // that does NOT end with 'lager' or any other case variations of it + # endregion + } finally { + $session->close(); + } + } finally { + $store->close(); + } + } +} diff --git a/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/ExactMatch.php b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/ExactMatch.php new file mode 100644 index 0000000000..7889f37176 --- /dev/null +++ b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/ExactMatch.php @@ -0,0 +1,63 @@ +openSession(); + try { + # region exact_1 + // load all entities from 'Employees' collection + // where FirstName field's contents equals 'Robert' (case sensitive match) + + /** @var array $employees */ + $employees = $session->query(Employee::class) + ->whereEquals("FirstName", "Robert", true) + ->toList(); + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region exact_4 + // return all entities from the 'Orders' collection which contain + // at least one order line with 'Teatime Chocolate Biscuits' product + // perform a case-sensitive match + /** @var array $orders */ + $orders = $session->query(Order::class) + ->whereEquals("Lines[].ProductName", "Teatime Chocolate Biscuits", true) + ->toList(); + # endregion + } finally { + $session->close(); + } + } finally { + $store->close(); + } + } +} + +class Employee +{ +} + +class Order +{ +} diff --git a/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/FullTextSearch.php b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/FullTextSearch.php new file mode 100644 index 0000000000..d5da588e9c --- /dev/null +++ b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/FullTextSearch.php @@ -0,0 +1,529 @@ +openSession(); + try { + # region fts_1 + /** @var array $employees */ + $employees = $session + // Make a dynamic query on Employees collection + ->query(Employee::class) + // * Call 'Search' to make a Full-Text search + // * Search is case-insensitive + // * Look for documents containing the term 'University' within their 'Notes' field + ->search("Notes", "University") + ->toList(); + + // Results will contain Employee documents that have + // any case variation of the term 'university' in their 'Notes' field. + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region fts_3 + /** @var array $employees */ + $employees = $session->advanced() + // Make a dynamic DocumentQuery on Employees collection + ->documentQuery(Employee::class) + // * Call 'Search' to make a Full-Text search + // * Search is case-insensitive + // * Look for documents containing the term 'University' within their 'Notes' field + ->search("Notes", "University") + ->toList(); + + // Results will contain Employee documents that have + // any case variation of the term 'university' in their 'Notes' field. + # endregion + } finally { + $session->close(); + } + + // Search for multiple terms - string + // ================================== + $session = $store->openSession(); + try { + # region fts_4 + /** @var array $employees */ + $employees = $session + ->query(Employee::class) + // * Pass multiple terms in a single string, separated by spaces. + // * Look for documents containing either 'University' OR 'Sales' OR 'Japanese' + // within their 'Notes' field + ->search("Notes", "University Sales Japanese") + ->toList(); + + // * Results will contain Employee documents that have at least one of the specified terms. + // * Search is case-insensitive. + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region fts_6 + /** @var array $employees */ + $employees = $session->advanced() + ->documentQuery(Employee::class) + // * Pass multiple terms in a single string, separated by spaces. + // * Look for documents containing either 'University' OR 'Sales' OR 'Japanese' + // within their 'Notes' field + ->search("Notes", "University Sales Japanese") + ->toList(); + + // * Results will contain Employee documents that have at least one of the specified terms. + // * Search is case-insensitive. + # endregion + } finally { + $session->close(); + } + + // Search for multiple terms - list + // ================================== + $session = $store->openSession(); + try { + # region fts_7 + /** @var array $employees */ + $employees = $session + ->query(Employee::class) + // * Pass terms in array. + // * Look for documents containing either 'University' OR 'Sales' OR 'Japanese' + // within their 'Notes' field + ->search("Notes", ["University", "Sales", "Japanese"]) + ->toList(); + + // * Results will contain Employee documents that have at least one of the specified terms. + // * Search is case-insensitive. + # endregion + } finally { + $session->close(); + } + + // Search in multiple fields + // ========================= + $session = $store->openSession(); + try { + # region fts_9 + /** @var array $employees */ + $employees = $session + ->query(Employee::class) + // * Look for documents containing: + // 'French' in their 'Notes' field OR 'President' in their 'Title' field + ->search("Notes", "French") + ->search("Title", "President") + ->toList(); + + // * Results will contain Employee documents that have + // at least one of the specified fields with the specified terms. + // * Search is case-insensitive. + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region fts_11 + /** @var array $employees */ + $employees = $session->advanced() + ->documentQuery(Employee::class) + // * Look for documents containing: + // 'French' in their 'Notes' field OR 'President' in their 'Title' field + ->search("Notes", "French") + ->search("Title", "President") + ->toList(); + + // * Results will contain Employee documents that have + // at least one of the specified fields with the specified terms. + // * Search is case-insensitive. + # endregion + } finally { + $session->close(); + } + + // Search in complex object + // ======================== + $session = $store->openSession(); + try { + # region fts_12 + /** @var array $companies */ + $companies = $session + ->query(Company::class) + // * Look for documents that contain: + // the term 'USA' OR 'London' in any field within the complex 'Address' object + ->search("Address", "USA London") + ->toList(); + + // * Results will contain Company documents that are located either in 'USA' OR in 'London'. + // * Search is case-insensitive. + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region fts_14 + /** @var array $companies */ + $companies = $session->advanced() + ->documentQuery(Company::class) + // * Look for documents that contain: + // the term 'USA' OR 'London' in any field within the complex 'Address' object + ->search("Address", "USA London") + ->toList(); + + // * Results will contain Company documents that are located either in 'USA' OR in 'London'. + // * Search is case-insensitive. + # endregion + } finally { + $session->close(); + } + + // Search operators - AND + // ====================== + $session = $store->openSession(); + try { + # region fts_15 + /** @var array $employees */ + $employees = $session + ->query(Employee::class) + // * Pass operator with SearchOperator::and() + ->search("Notes", "College German", SearchOperator::and()) + ->toList(); + + // * Results will contain Employee documents that have BOTH 'College' AND 'German' + // in their 'Notes' field. + // * Search is case-insensitive. + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region fts_17 + /** @var array $employees */ + $employees = $session->advanced() + ->documentQuery(Employee::class) + // * Pass operator with SearchOperator::and() + ->search("Notes", "College German", SearchOperator::and()) + ->toList(); + + // * Results will contain Employee documents that have BOTH 'College' AND 'German' + // in their 'Notes' field. + // * Search is case-insensitive. + # endregion + } finally { + $session->close(); + } + + // Search operators - OR + // ===================== + $session = $store->openSession(); + try { + # region fts_18 + /** @var array $employees */ + $employees = $session + ->query(Employee::class) + // * Pass operator with SearchOperator::or() + ->search("Notes", "College German", SearchOperator::or()) + ->toList(); + + // * Results will contain Employee documents that have EITHER 'College' OR 'German' + // in their 'Notes' field. + // * Search is case-insensitive. + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region fts_20 + /** @var array $employees */ + $employees = $session->advanced() + ->documentQuery(Employee::class) + // * Pass operator with SearchOperator::or() + ->search("Notes", "College German", SearchOperator::or()) + ->toList(); + + // * Results will contain Employee documents that have EITHER 'College' OR 'German' + // in their 'Notes' field. + // * Search is case-insensitive. + # endregion + } finally { + $session->close(); + } + + // Search options - Not + // ==================== + $session = $store->openSession(); + try { + # region fts_21 + /** @var array $companies */ + $companies = $session + ->query(Company::class) + # Call 'not()' to negate the next search call + ->not() + ->search("Address", "USA") + ->toList(); + + // * Results will contain Company documents are NOT located in 'USA' + // * Search is case-insensitive + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region fts_23 + /** @var array $companies */ + $companies = $session->advanced() + ->documentQuery(Company::class) + ->openSubclause() + // Call 'not()' to negate the next search call + ->not() + ->search("Address", "USA") + ->closeSubclause() + ->toList(); + + // * Results will contain Company documents are NOT located in 'USA' + // * Search is case-insensitive + # endregion + } finally { + $session->close(); + } + + // Search options - Default + // ======================== + $session = $store->openSession(); + try { + # region fts_24 + /** @var array $companies */ + $companies = $session + ->query(Company::class) + ->whereEquals("Contact.Title", "Owner") + // Operator AND will be used with previous 'Where' predicate + ->search("Address.Country", "France") + // Operator OR will be used between the two 'Search' calls by default + ->search("Name", "Markets") + ->toList(); + + // * Results will contain Company documents that have: + // ('Owner' as the 'Contact.Title') + // AND + // (are located in 'France' OR have 'Markets' in their 'Name' field) + // + // * Search is case-insensitive + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region fts_26 + /** @var array $companies */ + $companies = $session->advanced() + ->documentQuery(Company::class) + ->whereEquals("Contact.Title", "Owner") + // Operator AND will be used with previous 'Where' predicate + // Call 'openSubclause()' to open predicate block + ->openSubclause() + ->search("Address.Country", "France") + // Operator OR will be used between the two 'Search' calls by default + ->search("Name", "Markets") + // Call 'closeSubclause()' to close predicate block + ->closeSubclause() + ->toList(); + + // * Results will contain Company documents that have: + // ('Owner' as the 'Contact.Title') + // AND + // (are located in 'France' OR have 'Markets' in their 'Name' field) + // + // * Search is case-insensitive + # endregion + } finally { + $session->close(); + } + + // Search options - AND + // ==================== + $session = $store->openSession(); + try { + # region fts_27 + /** @var array $employees */ + $employees = $session + ->query(Employee::class) + ->search("Notes", "French") + // Call 'AndAlso' so that operator AND will be used with previous 'search' call + ->andAlso() + ->search("Title", "Manager") + ->toList(); + + // * Results will contain Employee documents that have: + // ('French' in their 'Notes' field) + // AND + // ('Manager' in their 'Title' field) + // + // * Search is case-insensitive + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region fts_29 + /** @var array $employees */ + $employees = $session->advanced() + ->documentQuery(Employee::class) + ->search("Notes", "French") + // Call 'andAlso()' so that operator AND will be used with previous 'search' call + ->andAlso() + ->search("Title", "Manger") + ->toList(); + + // * Results will contain Employee documents that have: + // ('French' in their 'Notes' field) + // AND + // ('Manager' in their 'Title' field) + // + // * Search is case-insensitive + # endregion + } finally { + $session->close(); + } + + // Search options - Flags + // ====================== + $session = $store->openSession(); + try { + # region fts_30 + /** @var array $employees */ + $employees = $session + ->query(Employee::class) + ->search("Notes", "French") + // Call 'andAlso()' so that operator AND will be used with previous 'search' call + ->andAlso() + ->openSubclause() + // Call 'not()' to negate the next search call + ->not() + ->search("Title", "Manager") + ->closeSubclause() + ->toList(); + + // * Results will contain Employee documents that have: + // ('French' in their 'Notes' field) + // AND + // (do NOT have 'Manager' in their 'Title' field) + // + // * Search is case-insensitive + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region fts_32 + /** @var array $employees */ + $employees = $session->advanced() + ->documentQuery(Employee::class) + ->search("Notes", "French") + // Call 'andAlso()' so that operator AND will be used with previous 'search' call + ->andAlso() + ->openSubclause() + // Call 'not()' to negate the next search call + ->not() + ->search("Title", "Manager") + ->closeSubclause() + ->toList(); + + // * Results will contain Employee documents that have: + // ('French' in their 'Notes' field) + // AND + // (do NOT have 'Manager' in their 'Title' field) + // + // * Search is case-insensitive + # endregion + } finally { + $session->close(); + } + + // Using wildcards + // =============== + $session = $store->openSession(); + try { + # region fts_33 + /** @var array $employees */ + $employees = $session + ->query(Employee::class) + // Use '*' to replace one or more characters + ->search("Notes", "art*") + ->search("Notes", "*logy") + ->search("Notes", "*mark*") + ->ToList(); + + // Results will contain Employee documents that have in their 'Notes' field: + // (terms that start with 'art') OR + // (terms that end with 'logy') OR + // (terms that have the text 'mark' in the middle) + // + // * Search is case-insensitive + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region fts_35 + /** @var array $employees */ + $employees = $session->advanced() + ->documentQuery(Employee::class) + // Use '*' to replace one ore more characters + ->search("Notes", "art*") + ->search("Notes", "*logy") + ->search("Notes", "*mark*") + ->toList(); + + // Results will contain Employee documents that have in their 'Notes' field: + // (terms that start with 'art') OR + // (terms that end with 'logy') OR + // (terms that have the text 'mark' in the middle) + // + // * Search is case-insensitive + # endregion + } finally { + $session->close(); + } + } finally { + $store->close(); + } + } +} diff --git a/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/FuzzySearch.php b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/FuzzySearch.php new file mode 100644 index 0000000000..be912e2f6c --- /dev/null +++ b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/FuzzySearch.php @@ -0,0 +1,44 @@ +openSession(); + try { + # region fuzzy_1 + /** @var array $companies */ + $companies = $session->advanced() + ->documentQuery(Company::class) + // Query with a term that is misspelled + ->whereEquals("Name", "Ernts Hnadel") + // Call 'Fuzzy' + // Pass the required similarity, a decimal param between 0.0 and 1.0 + ->fuzzy(0.5) + ->toList(); + + // Running the above query on the Northwind sample data returns document: companies/20-A + // which contains "Ernst Handel" in its Name field. + # endregion + } finally { + $session->close(); + } + + } finally { + $store->close(); + } + } +} diff --git a/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/HighlightQueryResults.php b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/HighlightQueryResults.php new file mode 100644 index 0000000000..728a09b7f3 --- /dev/null +++ b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/HighlightQueryResults.php @@ -0,0 +1,287 @@ +map = "docs.Select(doc => new { " . + " text = doc.text" . + "})"; + + $this->index("text", FieldIndexing::search()); + $this->store("text", FieldStorage::yes()); + $this->termVector("text", FieldTermVector::withPositionsAndOffsets()); + } +} + +class SearchItem +{ + private ?string $id = null; + private ?string $text = null; + + public function getId(): ?string + { + return $this->id; + } + + public function setId(?string $id): void + { + $this->id = $id; + } + + public function getText(): ?string + { + return $this->text; + } + + public function setText(?string $text): void + { + $this->text = $text; + } +} + +class EmployeeDetails +{ + private ?string $name = null; + private ?string $title = null; + + public function getName(): ?string + { + return $this->name; + } + + public function setName(?string $name): void + { + $this->name = $name; + } + + public function getTitle(): ?string + { + return $this->title; + } + + public function setTitle(?string $title): void + { + $this->title = $title; + } +} + +interface FooInterface +{ + # region syntax_1 + function highlight( + ?string $fieldName, + int $fragmentLength, + int $fragmentCount, + ?HighlightingOptions $options, + Highlightings &$highlightings + ): DocumentQueryInterface; + # endregion +} + +class Foo +{ + # region syntax_2 + private ?string $groupKey; + private ?StringArray $preTags = null; + private ?StringArray $postTags = null; + + // getters and setters + # endregion +} + + +class HighlightingsClass +{ + # region syntax_3 + private ?string $fieldName = null; + public function getResultIndents(): array; + # endregion +} + +interface FooInterface2 +{ + # region syntax_4 + public function getFragments(?string $key): array; + # endregion +} + +class HighlightQueryResults +{ + public function examples(): void + { + $store = DocumentStoreHolder::getStore(); + try { + $session = $store->openSession(); + try { + # region highlight_1 + // Make a full-text search dynamic query: + // ====================================== + + $highlightings = new Highlightings(); + + /** @var array $employeesResults */ + $employeesResults = $session + // Make a dynamic query on 'Employees' collection + ->query(Employee::class) + // Search for documents containing the term 'sales' in their 'Notes' field + ->search("Notes", "sales") + // Request to highlight the searched term by calling 'highlight()' + ->highlight( + "Notes", // The document-field name in which we search + 35, // Max length of each text fragment + 4, // Max number of fragments to return per document + null, // Put null to use default options + $highlightings) // An out param for getting the highlighted text fragments + + // Execute the query + ->toList(); + # endregion + + # region fragments_1 + // Process results: + // ================ + + // 'employeesResults' contains all Employee DOCUMENTS that have 'sales' in their 'Notes' field. + // 'salesHighlights' contains the text FRAGMENTS that highlight the 'sales' term. + + $builder = '
    '; + + /** @var SearchItem $employee */ + foreach ($employeesResults as $employee) { + // Call 'GetFragments' to get all fragments for the specified employee Id + $fragments = $highlightings->getFragments($employee->getId()); + foreach ($fragments as $fragment) { + $builder .= '
  • Doc: ' . $employee->getId() . ' Fragment: ' . $fragment . '
  • '; + } + } + + $builder .= '
'; + $fragmentsHtml = $builder; + + // The resulting fragmentsHtml: + // ============================ + + //
    + //
  • Doc: employees/2-A Fragment: company as a sales
  • + //
  • Doc: employees/2-A Fragment: promoted to sales manager in
  • + //
  • Doc: employees/2-A Fragment: president of sales in March 1993
  • + //
  • Doc: employees/2-A Fragment: member of the Sales Management
  • + //
  • Doc: employees/3-A Fragment: hired as a sales associate in
  • + //
  • Doc: employees/3-A Fragment: promoted to sales representativ
  • + //
  • Doc: employees/5-A Fragment: company as a sales representativ
  • + //
  • Doc: employees/5-A Fragment: promoted to sales manager in
  • + //
  • Doc: employees/5-A Fragment: Sales Management."
  • + //
  • Doc: employees/6-A Fragment: for the Sales Professional.
  • + //
+ # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region highlight_4 + // Define customized tags to use for highlighting the searched terms + // ================================================================= + + $salesHighlights = new Highlightings(); + $managerHighlights = new Highlightings(); + + $tagsToUse = new HighlightingOptions(); + // Provide strings of your choice to 'PreTags' & 'PostTags', e.g.: + // the first term searched for will be wrapped with '+++' + // the second term searched for will be wrapped with '<<<' & '>>>' + $tagsToUse->setPreTags(["+++", "<<<"]); + $tagsToUse->setPostTags(["+++", ">>>"]); + + // Make a full-text search dynamic query: + // ====================================== + $employeesResults = $session + ->query(Employee::class) + // Search for: + // * documents containing the term 'sales' in their 'Notes' field + // * OR for documents containing the term 'manager' in their 'Title' field + ->search("Notes", "sales") + ->search("Title", "manager") + // Call 'Highlight' for each field searched + // Pass 'tagsToUse' to OVERRIDE the default tags used + ->highlight("Notes", 35, 1, $tagsToUse, $salesHighlights) + ->highlight("Title", 35, 1, $tagsToUse, $managerHighlights) + ->toList(); + # endregion + + # region fragments_2 + // The resulting salesHighlights fragments: + // ======================================== + + // "for the +++Sales+++ Professional." + // "hired as a +++sales+++ associate in" + // "company as a +++sales+++" + // "company as a +++sales+++ representativ" + + // The resulting managerHighlights fragments: + // ========================================== + + // "Sales <<>>" + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region highlight_6 + // Make a full-text search dynamic query & project results: + // ======================================================== + $termsHighlights = new Highlightings(); + + /** @var array $employeesProjectedResults */ + $employeesProjectedResults = $session + ->query(Employee::class) + // Search for documents containing 'sales' or 'german' in their 'Notes' field + ->search("Notes", "manager german") + // Request to highlight the searched terms from the 'Notes' field + ->highlight("Notes", 35, 2, null, $termsHighlights) + // Define the projection + ->selectFields(EmployeeDetails::class, QueryData::customFunction("o", "{ name: o.FirstName + ' ' + o.LastName, title: o.Title }")) + ->toList(); + # endregion + + # region fragments_3 + // The resulting fragments from termsHighlights: + // ============================================= + + // "to sales manager in March" + // "and reads German. He joined" + // "to sales manager in January" + // "in French and German." + + // NOTE: each search term is wrapped with a different color + // 'manager' is wrapped with yellow + // 'german' is wrapped with lawngreen + # endregion + } finally { + $session->close(); + } + + } finally { + $store->close(); + } + } +} + diff --git a/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/ProximitySearch.php b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/ProximitySearch.php new file mode 100644 index 0000000000..2f149d5c35 --- /dev/null +++ b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/ProximitySearch.php @@ -0,0 +1,83 @@ +openSession(); + try { + # region proximity_2 + $session->advanced() + ->documentQuery(Fox::class) + ->search("name", "quick fox") + ->proximity(2) + ->toList(); + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region proximity_1 + /** @var array $employees */ + $employees = $session->advanced() + ->documentQuery(Employee::class) + // Make a full-text search with search terms + ->search("Notes", "fluent french") + // Call 'Proximity' with 0 distance + ->proximity(0) + ->toList(); + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region proximity_3 + /** @var array $employees */ + $employees = $session->advanced() + ->documentQuery(Employee::class) + // Make a full-text search with search terms + ->search("Notes", "fluent french") + // Call 'Proximity' with distance 5 + ->proximity(4) + ->toList(); + # endregion + } finally { + $session->close(); + } + + } finally { + $store->close(); + } + } +} + +class Fox +{ + private ?string $name = null; + + public function getName(): ?string + { + return $this->name; + } + + public function setName(?string $name): void + { + $this->name = $name; + } +} diff --git a/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/StartsWith.php b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/StartsWith.php new file mode 100644 index 0000000000..6d3ac2b467 --- /dev/null +++ b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/StartsWith.php @@ -0,0 +1,108 @@ +openSession(); + try { + # region startsWith_1 + /** @var array $products */ + $products = $session + ->query(Product::class) + // Call 'StartsWith' on the field + // Pass the prefix to search by + ->whereStartsWith("Name", "Ch") + ->toList(); + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region startsWith_3 + /** @var array $products */ + $products = $session->advanced() + ->documentQuery(Product::class) + // Call 'WhereStartsWith' + // Pass the document field and the prefix to search by + ->whereStartsWith("Name", "Ch") + ->toList(); + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region startsWith_4 + /** @var array $products */ + $products = $session->advanced() + ->query(Product::class) + // Pass 'exact: true' to search for an EXACT prefix match + ->whereStartsWith("Name", "Ch", true) + ->toList(); + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region startsWith_6 + /** @var array $products */ + $products = $session->advanced() + ->documentQuery(Product::class) + // Call 'WhereStartsWith' + // Pass 'exact: true' to search for an EXACT prefix match + ->whereStartsWith("Name", "Ch", true) + ->toList(); + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region startsWith_7 + /** @var array $products */ + $products = $session + ->query(Product::class) + # Negate next statement + ->not() + // Call 'StartsWith' on the field + // Pass the prefix to search by + ->whereStartsWith("Name", "Ch") + ->toList(); + # endregion + } finally { + $session->close(); + } + + $session = $store->openSession(); + try { + # region startsWith_9 + /** @var array $products */ + $products = $session->advanced() + ->documentQuery(Product::class) + // Call 'Not' to negate the next predicate + ->not() + // Call 'WhereStartsWith' + // Pass the document field and the prefix to search by + ->whereStartsWith("Name", "Ch") + ->toList(); + # endregion + } finally { + $session->close(); + } + } finally { + $store->close(); + } + } +} diff --git a/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/UsingRegex.php b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/UsingRegex.php new file mode 100644 index 0000000000..ac061c4b33 --- /dev/null +++ b/Documentation/5.4/Samples/php/ClientApi/session/Querying/TextSearch/UsingRegex.php @@ -0,0 +1,52 @@ +openSession(); + try { + # region regex_1 + /** @var array $products */ + $products = $session + ->query(Product::class) + ->whereRegex("Name", "^[NA]") + ->toList(); + # endregion + } finally { + $session->close(); + } + + } finally { + $store->close(); + } + } +} + +class User +{ + public ?string $firstName = null; + + public function getFirstName(): ?string + { + return $this->firstName; + } + + public function setFirstName(?string $firstName): void + { + $this->firstName = $firstName; + } +} diff --git a/Documentation/6.0/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.php.markdown b/Documentation/6.0/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.php.markdown new file mode 100644 index 0000000000..8a17eb73e8 --- /dev/null +++ b/Documentation/6.0/Raven.Documentation.Pages/client-api/session/querying/debugging/query-timings.php.markdown @@ -0,0 +1,67 @@ +# Include Query Timings + +--- + +{NOTE: } + +* When making a query, + you can request to get detailed stats of the time spent by RavenDB on each part of the query. + E.g. duration of search, loading documents, transforming results, total duration, etc. + +* By default, the timings stats are Not included in the query results, to avoid the measuring overhead. + +* **To include the query timings** in the query results: + add a call to the `timings()` method in your query code, or add `include timings()` to an RQL query. + See examples below. + +* In this page: + * [Include timings in a query](../../../../client-api/session/querying/debugging/query-timings#include-timings-in-a-query) + * [View timings](../../../../client-api/session/querying/debugging/query-timings#view-timings) + * [Syntax](../../../../client-api/session/querying/debugging/query-timings#syntax) + * [Timings in a sharded database](../../../../client-api/session/querying/debugging/query-timings#timings-in-a-sharded-database) + +{NOTE/} + +--- + +{PANEL: Include timings in a query} + +{CODE-TABS} +{CODE-TAB:php:query timing_2@ClientApi\Session\Querying\Debugging\IncludeQueryTimings.php /} +{CODE-TAB-BLOCK:sql:RQL} +from "Products" +where search(Name, "Syrup") or search(Name, "Lager") +include timings() +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: View timings} + +* The detailed timings can be viewed from Studio's [Query view](../../../../studio/database/queries/query-view). + +* Running an RQL query with `include timings()` will show an additional **Timings Tab** + with a graphical representation of the time spent in each query part. + +![Figure 1. Include timings graphical results](images/include-timings.png "Include timings results") + +{PANEL/} + +{PANEL: Syntax} + +{CODE:php syntax@ClientApi\Session\Querying\Debugging\IncludeQueryTimings.php /} + +| Parameter | Type | Description | +|-------------|----------------|---------------| +| **&$timings** | `QueryTimings` | A callback function (action) that takes `QueryTimings` as an argument. It will be called by the client with the resulting `QueryTimings`. You can interact with the resulting `QueryTimings` inside your callback. | + +{PANEL/} + +{PANEL: Timings in a sharded database} + +* In a sharded database, timings for each part are provided **per shard**. + +* Learn more in [timings in a sharded database](../../../../sharding/querying#timing-queries). + +{PANEL/} diff --git a/Documentation/6.0/Samples/php/ClientApi/session/Querying/Debugging/IncludeQueryTimings.php b/Documentation/6.0/Samples/php/ClientApi/session/Querying/Debugging/IncludeQueryTimings.php new file mode 100644 index 0000000000..ff7d0a0d23 --- /dev/null +++ b/Documentation/6.0/Samples/php/ClientApi/session/Querying/Debugging/IncludeQueryTimings.php @@ -0,0 +1,42 @@ +openSession(); + try { + # region timing_2 + $timings = new QueryTimings(); + + /** @var array $resultsWithTimings */ + $resultsWithTimings = $session->advanced()->documentQuery(Product::class) + ->timings($timings) + ->search("Name", "Syrup") + ->toList(); + + /** @var array $timingsMap */ + $timingsMap = $timings->getTimings(); + # endregion + } finally { + $session->close(); + } + } finally { + $store->close(); + } + } +}