diff --git a/docs/indexes/assets/dynamic-index-fields-1.png b/docs/indexes/assets/dynamic-index-fields-1.png
index b13d9076f8..a20adda0ec 100644
Binary files a/docs/indexes/assets/dynamic-index-fields-1.png and b/docs/indexes/assets/dynamic-index-fields-1.png differ
diff --git a/docs/indexes/assets/dynamic-index-fields-2.png b/docs/indexes/assets/dynamic-index-fields-2.png
index dd2b4082ea..c5b1bc14bc 100644
Binary files a/docs/indexes/assets/dynamic-index-fields-2.png and b/docs/indexes/assets/dynamic-index-fields-2.png differ
diff --git a/docs/indexes/content/_using-analyzers-csharp.mdx b/docs/indexes/content/_using-analyzers-csharp.mdx
index 6022cfd145..2e824fea4b 100644
--- a/docs/indexes/content/_using-analyzers-csharp.mdx
+++ b/docs/indexes/content/_using-analyzers-csharp.mdx
@@ -24,7 +24,7 @@ import CodeBlock from '@theme/CodeBlock';
* [Understanding the role of analyzers](../../indexes/using-analyzers.mdx#understanding-the-role-of-analyzers)
* [Analyzers available in RavenDB](../../indexes/using-analyzers.mdx#analyzers-available-in-ravendb)
* [Setting analyzer for index-field](../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field)
- * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendb)
+ * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendbs-default-analyzers)
* [Disabling indexing for index-field](../../indexes/using-analyzers.mdx#disabling-indexing-for-index-field)
* [Creating custom analyzers](../../indexes/using-analyzers.mdx#creating-custom-analyzers)
* [Viewing the indexed terms](../../indexes/using-analyzers.mdx#viewing-the-indexed-terms)
diff --git a/docs/indexes/content/_using-analyzers-nodejs.mdx b/docs/indexes/content/_using-analyzers-nodejs.mdx
index 6afd3b6202..20ac320455 100644
--- a/docs/indexes/content/_using-analyzers-nodejs.mdx
+++ b/docs/indexes/content/_using-analyzers-nodejs.mdx
@@ -24,7 +24,7 @@ import CodeBlock from '@theme/CodeBlock';
* [Understanding the role of analyzers](../../indexes/using-analyzers.mdx#understanding-the-role-of-analyzers)
* [Analyzers available in RavenDB](../../indexes/using-analyzers.mdx#analyzers-available-in-ravendb)
* [Setting analyzer for index-field](../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field)
- * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendb)
+ * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendbs-default-analyzers)
* [Disabling indexing for index-field](../../indexes/using-analyzers.mdx#disabling-indexing-for-index-field)
* [Creating custom analyzers](../../indexes/using-analyzers.mdx#creating-custom-analyzers)
* [Viewing the indexed terms](../../indexes/using-analyzers.mdx#viewing-the-indexed-terms)
diff --git a/docs/indexes/content/_using-dynamic-fields-csharp.mdx b/docs/indexes/content/_using-dynamic-fields-csharp.mdx
index b4c4f518df..5bf052d482 100644
--- a/docs/indexes/content/_using-dynamic-fields-csharp.mdx
+++ b/docs/indexes/content/_using-dynamic-fields-csharp.mdx
@@ -2,533 +2,923 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
-
-## Example - index any field under object
-
-
+
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // The KEYS under the Attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- public Dictionary Attributes \{ get; set; \}
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // The KEYS under the Attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ public Dictionary Attributes { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `Attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-{`public class Products_ByAttributeKey : AbstractIndexCreationTask
-{
- public Products_ByAttributeKey()
+
+
+ ```csharp
+ public class Products_ByAttributeKey : AbstractIndexCreationTask
{
- Map = products => from p in products
- select new
- {
- // Call 'CreateField' to generate dynamic-index-fields from the Attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
-
- // The actual field name will be item.Key
- // The actual field terms will be derived from item.Value
- _ = p.Attributes.Select(item => CreateField(item.Key, item.Value))
- };
+ public Products_ByAttributeKey()
+ {
+ Map = products => from p in products
+ select new
+ {
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the Attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'
+
+ // The actual field name will be 'item.Key'
+ // The actual field terms will be derived from 'item.Value'
+ _ = p.Attributes.Select(item => CreateField(item.Key, item.Value))
+ };
+ }
}
-}
-`}
-
-
-
-
-{`public class Products_ByAttributeKey_JS : AbstractJavaScriptIndexCreationTask
-{
- public Products_ByAttributeKey_JS()
+ ```
+
+
+ ```csharp
+ public class Products_ByAttributeKey_JS : AbstractJavaScriptIndexCreationTask
{
- Maps = new HashSet
+ public Products_ByAttributeKey_JS()
{
- @"map('Products', function (p) {
- return {
- _: Object.keys(p.Attributes).map(key => createField(key, p.Attributes[key],
- { indexing: 'Search', storage: true, termVector: null }))
- };
- })"
- };
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.Attributes)
+ .map(key => createField(key, p.Attributes[key]))
+ };
+ })"
+ };
+ }
}
-}
-`}
-
-
-
-
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- The `_` property is Not queryable but used only in the index definition syntax.
- * To get all documents with some 'Size' use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Size' is a dynamic-index-field that was indexed from the Attributes object
- .WhereEquals("Size", 42)
- .ToList();
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ .WhereEquals("Size", 42)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _DocumentQuery_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ A strongly typed LINQ query such as `Query().Where(p => p.Size == 42)` would not compile.
+ Use the string-based `WhereEquals("Size", 42)` or RQL `where Size = 42` instead.
+
-## Example - index any field
+
-
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- public string FirstName \{ get; set; \}
- public string LastName \{ get; set; \}
- public string Title \{ get; set; \}
- // ...
-\}
-`}
-
-
-
-
-
-{`// Sample document content
- \{
- "FirstName": "John",
- "LastName": "Doe",
- "Title": "Engineer",
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ public string FirstName { get; set; }
+ public string LastName { get; set; }
+ public string Title { get; set; }
// ...
-\}
-`}
-
-
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "FirstName": "John",
+ "LastName": "Doe",
+ "Title": "Engineer",
+ // ...
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
-
-
-
-{`public class Products_ByAnyField_JS : AbstractJavaScriptIndexCreationTask
-{
- public Products_ByAnyField_JS()
+
+
+ ```csharp
+ public class Products_ByAnyField_JS : AbstractJavaScriptIndexCreationTask
{
- // This will index EVERY FIELD under the top level of the document
- Maps = new HashSet
+ public Products_ByAnyField_JS()
{
- @"map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })"
- };
+ // This will index EVERY FIELD under the top level of the document
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ })"
+ };
+ }
}
-}
-`}
-
-
-
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'LastName' is a dynamic-index-field that was indexed from the document
- .WhereEquals("LastName", "Doe")
- .ToList();
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _LastName_ use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ .WhereEquals("LastName", "Doe")
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where LastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+### Example - basic
-## Indexing documents fields VALUES
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-## Example - basic
+* **The document**:
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // The VALUE of ProductType will be dynamically indexed
+ public string ProductType { get; set; }
+ public int PricePerUnit { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "ProductType": "Electronics",
+ "PricePerUnit": 23
+ }
+ ```
+
-
+* **The index**:
+
+ The following index will index the **value** of document field 'ProductType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```csharp
+ public class Products_ByProductType : AbstractIndexCreationTask
+ {
+ public Products_ByProductType()
+ {
+ Map = products => from p in products
+ select new
+ {
+ // Call 'CreateField' to generate the dynamic-index-fields
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _ = CreateField(p.ProductType, p.PricePerUnit)
+ };
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Products_ByProductType_JS : AbstractJavaScriptIndexCreationTask
+ {
+ public Products_ByProductType_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _: createField(p.ProductType, p.PricePerUnit)
+ };
+ })"
+ };
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ .WhereEquals("Electronics", 23)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
+### Example - list
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // The VALUE of ProductType will be dynamically indexed
- public string ProductType \{ get; set; \}
- public int PricePerUnit \{ get; set; \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+ public string Name { get; set; }
+
+ // For each element in this list,
+ // the VALUE of property 'PropName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ public List Attributes { get; set; }
+ }
+
+ public class Attribute
+ {
+ public string PropName { get; set; }
+ public string PropValue { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Name": "SomeName",
+ "Attributes": [
+ {
+ "PropName": "Color",
+ "PropValue": "Blue"
+ },
+ {
+ "PropName": "Width",
+ "PropValue": "10"
+ },
+ {
+ "PropName": "Length",
+ "PropValue": "20"
+ },
+ ...
+ ]
+ }
+ ```
+
* **The index**:
- The below index will index the **value** of document field 'ProductType'.
+
+ The following index will create a dynamic-index-field per item in the document's `Attributes` list.
+ New items added to the Attributes list after index creation time will be dynamically indexed as well.
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
+ E.g., 'PropName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```csharp
+ public class Attributes_ByName : AbstractIndexCreationTask
+ {
+ public Attributes_ByName()
+ {
+ Map = products => from a in products
+ select new
+ {
+ // Define the dynamic-index-fields by calling 'CreateField'
+ // A dynamic-index-field will be generated for each item in 'Attributes'
+
+ // For each item, the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _ = a.Attributes.Select(item =>
+ CreateField(item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name = a.Name
+ };
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Attributes_ByName_JS : AbstractJavaScriptIndexCreationTask
+ {
+ public Attributes_ByName_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _: p.Attributes.map(item => createField(
+ item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name: p.Name
+ };
+ })"
+ };
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ .WhereEquals("Width", 10)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing.Search` in `CreateFieldOptions`.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `AllFields` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `AllFields` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ public Dictionary Descriptions { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `Descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```csharp
+ public class Products_ByLocalizedDescription : AbstractIndexCreationTask
+ {
+ private const string UseSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription()
+ {
+ Map = products => from product in products
+ select new
+ {
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ // Index each generated dynamic field for FTS
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
+ };
+
+ StoreAllFields(FieldStorage.No);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ Configuration[UseSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
+ {
+ private const string UseSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (product) {
+ return {
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })"
+ };
+
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No
+ };
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ Configuration[UseSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```csharp
+ List results = session.Advanced
+ .DocumentQuery()
+ .Search("Description_English", "north wind")
+ .ToList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
-
-
-
-{`public class Products_ByProductType : AbstractIndexCreationTask
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `AllFields` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `AllFields` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
+
+```csharp
+public class Products_ByLocalizedDescription : AbstractIndexCreationTask
{
- public Products_ByProductType()
+ public Products_ByLocalizedDescription()
{
- Map = products => from p in products
+ Map = products => from product in products
select new
{
- // Call 'CreateField' to generate the dynamic-index-fields
- // The field name will be the value of document field 'ProductType'
- // The field terms will be derived from document field 'PricePerUnit'
- _ = CreateField(p.ProductType, p.PricePerUnit)
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
};
+
+ StoreAllFields(FieldStorage.No);
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ Analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`public class Products_ByProductType_JS : AbstractJavaScriptIndexCreationTask
+
+```csharp
+public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
{
- public Products_ByProductType_JS()
+ public Products_ByLocalizedDescription_JS()
{
Maps = new HashSet
{
- @"map('Products', function (p) {
+ @"map('Products', function (product) {
return {
- _: createField(p.ProductType, p.PricePerUnit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
};
+
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No
+ };
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ Fields["Description_English"] = new IndexFieldOptions
+ {
+ Analyzer = "StopAnalyzer"
+ };
}
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
- .WhereEquals("Electronics", 23)
- .ToList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
+```
-## Example - list
-
-
+#### Configure a fallback analyzer for all fields
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-
-
-
-* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
- public string Name \{ get; set; \}
-
- // For each element in this list, the VALUE of property 'PropName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- public List Attributes \{ get; set; \}
-\}
-
-public class Attribute
-\{
- public string PropName \{ get; set; \}
- public string PropValue \{ get; set; \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
-
-
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`public class Attributes_ByName : AbstractIndexCreationTask
+
+
+```csharp
+public class Products_ByLocalizedDescription : AbstractIndexCreationTask
{
- public Attributes_ByName()
+ public Products_ByLocalizedDescription()
{
- Map = products => from a in products
+ Map = products => from product in products
select new
{
- // Define the dynamic-index-fields by calling CreateField
- // A dynamic-index-field will be generated for each item in the Attributes list
-
- // For each item, the field name will be the value of field 'PropName'
- // The field terms will be derived from field 'PropValue'
- _ = a.Attributes.Select(item => CreateField(item.PropName, item.PropValue)),
-
- // A regular index field can be defined as well:
- Name = a.Name
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
};
+
+ StoreAllFields(FieldStorage.No);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ Analyze(Constants.Documents.Indexing.Fields.AllFields, "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`public class Attributes_ByName_JS : AbstractJavaScriptIndexCreationTask
+
+```csharp
+public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
{
- public Attributes_ByName_JS()
+ public Products_ByLocalizedDescription_JS()
{
Maps = new HashSet
{
- @"map('Products', function (p) {
+ @"map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
};
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No,
+ Analyzer = "StopAnalyzer"
+ };
}
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents matching a specific attribute property use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Width' is a dynamic-index-field that was indexed from the Attributes list
- .WhereEquals("Width", 10)
- .ToList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+
+The following applies when a `search()` query targets a **dynamic field**:
+
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `AllFields` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `AllFields` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `Analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `Analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+
-## CreateField syntax
+
+
+
#### Syntax for LINQ-index:
-
-
-{`object CreateField(string name, object value);
+
+```csharp
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
#### Syntax for JavaScript-index:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
| Parameters | Type | Description |
|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -540,11 +930,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
+
+
+
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

+
+
\ No newline at end of file
diff --git a/docs/indexes/content/_using-dynamic-fields-java.mdx b/docs/indexes/content/_using-dynamic-fields-java.mdx
index 17f3cbe360..d54ef6bea8 100644
--- a/docs/indexes/content/_using-dynamic-fields-java.mdx
+++ b/docs/indexes/content/_using-dynamic-fields-java.mdx
@@ -2,479 +2,918 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
+
-* Any value type can be indexed, string, number, date, etc.
+
+
+### Example - index every field under an object
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
+
-* In this page:
+* **The document**:
+
+
+ ```java
+ public class Product {
+ private String id;
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+ // The KEYS under the attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ private Map attributes;
-
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "color": "Red",
+ "size": 42
+ }
+ }
+ ```
+
-## Indexing documents fields KEYS
+* **The index**:
+
+ The following index will index any field under the `attributes` object from the document,
+ a dynamic-index-field will be created for each such field.
+ New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `color` & `size` will become the actual dynamic-index-fields.
+
+
+
+ ```java
+ public class Products_ByAttributeKey extends AbstractIndexCreationTask {
+ public Products_ByAttributeKey() {
+
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'.
+
+ // The actual field name will be 'item.Key'
+ // The actual field terms will be derived from 'item.Value'
+ map = "docs.Products.Select(p => new { " +
+ " _ = p.attributes.Select(item => " +
+ " this.CreateField(item.Key, item.Value)) " +
+ "})";
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByAttributeKey_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ " _: Object.keys(p.attributes) " +
+ " .map(key => createField(key, p.attributes[key])) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
-## Example - index any field under object
+* **The query**:
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _size_ use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByAttributeKey.class)
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ .whereEquals("size", 42)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey' where size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _DocumentQuery_ or _RQL_ because the field names (e.g. `size`, `color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `whereEquals("size", 42)` or RQL `where size = 42` instead.
+
-
+
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field
+
+The following example allows you to:
+ * Define an index on a collection **without** needing any common structure between the indexed documents.
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
+
+
+
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // The KEYS under the attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- private Dictionary attributes;
-
- // get + set implementation ...
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "attributes": \{
- "color": "Red",
- "size": 42
- \}
-\}
-`}
-
-
+
+
+ ```java
+ public class Product {
+ private String id;
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ private String firstName;
+ private String lastName;
+ private String title;
+ // ...
+
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer"
+ // ...
+ }
+ ```
+
* **The index**:
- The following index will index any field under the `attributes` object from the document,
- a dynamic-index-field will be created for each such field.
- New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The following index will index any field from the document,
+ a dynamic-index-field will be created for each field.
+ New fields added to the document after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+ The example uses an `AbstractJavaScriptIndexCreationTask` because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a map or collection.
+
+
+
+ ```java
+ public class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByAnyField_JS() {
+
+ // This will index EVERY FIELD under the top level of the document
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ " _: Object.keys(p).map(key => createField(key, p[key])) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- e.g. Keys `color` & `size` will become the actual dynamic-index-fields.
+* **The query**:
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByAnyField_JS.class)
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ .whereEquals("lastName", "Doe")
+ .toList();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
-
-
-
-{`public class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
- public Products_ByAttributeKey_JS() {
- // Call 'createField' to generate dynamic-index-fields from the attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
+
- // The actual field name will be the key
- // The actual field terms will be derived from p.attributes[key]
- setMaps(Sets.newHashSet(
- "map('Products', function (p) { " +
- " return { " +
- " _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], " +
- " { indexing: 'Search', storage: false, termVector: null })) " +
- " }; " +
- "}) "
- ));
- }
-}
-`}
-
-
-
+
+
+### Example - basic
-* **The query**:
- * You can now query the generated dynamic-index fields.
- Property `_` is Not queryable, it is only used in the index definition syntax.
- * To get all documents with some 'size' use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByAttributeKey_JS.class)
- .whereEquals("size", 42)
- .toList();
-`}
-
-
-
-
-{`// 'size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey/JS' where size = 42
-`}
-
-
-
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-## Example - index any field
+* **The document**:
+
+
+ ```java
+ public class Product {
+ private String id;
-
+ // The VALUE of productType will be dynamically indexed
+ private String productType;
+ private int pricePerUnit;
-* Define an index on a collection **without** needing any common structure between the indexed documents.
-* After index is deployed, any new field added to the document will be indexed as well.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
-
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```java
+ public class Products_ByProductType extends AbstractIndexCreationTask {
+ public Products_ByProductType() {
+
+ // Call 'CreateField' to generate the dynamic-index-field.
+ // The field name will be the value of document field 'productType'.
+ // The field terms will be derived from document field 'pricePerUnit'.
+ map = "docs.Products.Select(p => new { " +
+ " _ = this.CreateField(p.productType, p.pricePerUnit) " +
+ "})";
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByProductType_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ " _: createField(p.productType, p.pricePerUnit) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
-
-Consider if that is a true necessity, as indexing every single field can end up costing time and disk space.
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByProductType.class)
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ .whereEquals("Electronics", 23)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- private String firstName;
- private String lastName;
- private String title;
- // ...
-
- // get + set implementation ...
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "firstName": "John",
- "lastName": "Doe",
- "title": "Engineer",
- // ...
-\}
-`}
-
-
+
+
+ ```java
+ public class Product {
+ private String id;
+ private String name;
+
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ private List attributes;
+
+ // getters and setters ...
+ }
-* **The index**:
- The following index will index any field from the document,
- a dynamic-index-field will be created for each field.
- New fields added to the document after index creation time will be dynamically indexed as well.
+ public class Attribute {
+ private String propName;
+ private String propValue;
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ }
+ // ...
+ ]
+ }
+ ```
+
-
-
-
-{`public class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
- public Products_ByAnyField_JS() {
+* **The index**:
- // This will index EVERY FIELD under the top level of the document
- setMaps(Sets.newHashSet(
- "map('Products', function (p) { " +
- " return { " +
- " _: Object.keys(p).map(key => createField(key, p[key], " +
- " { indexing: 'Search', storage: true, termVector: null })) " +
- " }; " +
- "}) "
- ));
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```java
+ public class Attributes_ByName extends AbstractIndexCreationTask {
+ public Attributes_ByName() {
+
+ // Define the dynamic-index-fields by calling 'CreateField'.
+ // A dynamic-index-field will be generated for each item in 'attributes'.
+
+ // For each item, the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'.
+ // A regular index field (Name) is defined as well.
+ map = "docs.Products.Select(p => new { " +
+ " _ = p.attributes.Select(item => " +
+ " this.CreateField(item.propName, item.propValue)), " +
+ " Name = p.name " +
+ "})";
+ }
}
-}
-`}
-
-
-
+ ```
+
+
+ ```java
+ public class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
+ public Attributes_ByName_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // For each item,
+ // the field name will be the value of field 'propName'.
+ // The field terms will be derived from field 'propValue'.
+ " _: p.attributes.map(item => " +
+ " createField(item.propName, item.propValue)), " +
+ // A regular index field can be defined as well:
+ " Name: p.name " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
* **The query**:
- * To get all documents with some 'lastName' use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByAnyField_JS.class)
- .whereEquals("lastName", "Doe")
- .toList();
-`}
-
-
-
-
-{`// 'lastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where lastName = "Doe"
-`}
-
-
-
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Attributes_ByName.class)
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ .whereEquals("Width", 10)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `indexing: 'Search'` in the `createField` options object (`AbstractJavaScriptIndexCreationTask`)
+or `FieldIndexing.Search` in the `CreateFieldOptions` (`AbstractIndexCreationTask`).
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
-## Indexing documents fields VALUES
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Example - basic
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
-
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
-* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // The VALUE of productType will be dynamically indexed
- private String productType;
- private int pricePerUnit;
-
- // get + set implementation ...
-\}
-`}
-
-
+
+ ```java
+ public class Product {
+ private String id;
-
-
-{`// Sample document content
-\{
- "productType": "Electronics",
- "pricePerUnit": 23
-\}
-`}
-
-
+ private Map descriptions;
-* **The index**:
- The following index will index the **value** of document field 'productType'.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` map.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```java
+ public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+
+ private static final String USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ // Index each generated dynamic field for FTS
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
+ "})";
+
+ storeAllFields(FieldStorage.NO);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ getConfiguration().put(USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS, "true");
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+
+ private static final String USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ // Index each generated dynamic field for FTS
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
+
+ Map fields = new HashMap<>();
+
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
+ setFields(fields);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ getConfiguration().put(USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS, "true");
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```java
+ List results = session.advanced()
+ .documentQuery(Product.class, Products_ByLocalizedDescription.class)
+ .search("Description_English", "north wind")
+ .toList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
- This value will be the dynamic-index-field name on which you can query.
- e.g. Field value `Electronics` will be the dynamic-index-field.
+---
-
-
-
-{`public class Products_ByProductType extends AbstractIndexCreationTask {
- public Products_ByProductType() {
+
+
+### Configuring analyzers for dynamic fields
+
+The `CreateFieldOptions` (and the JavaScript `createField` options) do **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- map = "docs.Products.Select(p => new { " +
- " _ = this.CreateField(p.productType, p.pricePerUnit) " +
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
+
+```java
+public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
"})";
+
+ storeAllFields(FieldStorage.NO);
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByProductType.class)
- .whereEquals("Electronics", 23)
- .toList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-## Example - list
+
+```java
+public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
-
+ Map fields = new HashMap<>();
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
-
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ IndexFieldOptions englishOptions = new IndexFieldOptions();
+ englishOptions.setAnalyzer("StopAnalyzer");
+ fields.put("Description_English", englishOptions);
-* **The document**:
-
-
-{`public class Product \{
- private String id;
- private String name;
-
- // For each element in this list, the VALUE of property 'propName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- private List attributes;
-
- // get + set implementation ...
-\}
-
-public class Attribute \{
- private String propName;
- private String propValue;
-
- // get + set implementation ...
-\}
-`}
-
+ setFields(fields);
+ }
+}
+```
+
-
-
-{`// Sample document content
-\{
-name": "SomeName",
-attributes": [
- \{
- "propName": "Color",
- "propValue": "Blue"
- \},
- \{
- "propName": "Width",
- "propValue": "10"
- \},
- \{
- "propName": "Length",
- "propValue": "20"
- \},
- ...
-
-\}
-`}
-
-
+#### Configure a fallback analyzer for all fields
+
+
+
+```java
+public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
+ "})";
-* **The index**:
- The following index will create a dynamic-index-field per item in the document's `attributes` list.
- New items added to the attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's propName **value**.
- E.g., 'propName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`public class Attributes_ByName extends AbstractIndexCreationTask {
- public Attributes_ByName() {
-
- // For each attribute item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- // A regular-index-field (Name) is defined as well
- map =
- "docs.Products.Select(p => new { " +
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " +
- " Name = p.name " +
- "})";
+ storeAllFields(FieldStorage.NO);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ analyze(Constants.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer");
}
}
-`}
-
+```
-
+
+```java
+public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
-* **The query**:
- * To get all documents matching a specific attribute property use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Attributes_ByName.class)
- .whereEquals("Width", 10)
- .toList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+ Map fields = new HashMap<>();
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+ allFieldsOptions.setAnalyzer("StopAnalyzer");
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
+
+ setFields(fields);
+ }
+}
+```
+
+
+
+
+### Which analyzer is used for the query term?
+The following applies when a `search()` query targets a **dynamic field**:
-## CreateField syntax
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-#### Syntax for LINQ-index:
+
-
-
-{`object CreateField(string name, object value);
+
+
+
+
+#### Syntax for `AbstractIndexCreationTask`
+
+
+```csharp
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
-#### Syntax for JavaScript-index:
+#### Syntax for `AbstractJavaScriptIndexCreationTask`
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|----------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
+| Parameters | Type | Description |
+|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+* The `CreateField` syntax (and the `CreateFieldOptions` shape) above describes what is available inside the server-side `map` string of an `AbstractIndexCreationTask`,
+ since the Java client sends the `map` source to the server for compilation.
+ The JavaScript `createField` function is the equivalent for `AbstractJavaScriptIndexCreationTask` map sources.
+
* All above examples have used the character `_` in the dynamic-index-field definition.
However, using `_` is just a convention. Any other string can be used instead.
* This property is Not queryable, it is only used in the index definition syntax.
- The actual dynamic-index-fields that are generated are defined by the `CreateField` method.
+ The actual dynamic-index-fields that are generated are defined by the `CreateField` method (or the `createField` JS function).
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/docs/indexes/content/_using-dynamic-fields-nodejs.mdx b/docs/indexes/content/_using-dynamic-fields-nodejs.mdx
index b5df2df4a7..c14184c2b5 100644
--- a/docs/indexes/content/_using-dynamic-fields-nodejs.mdx
+++ b/docs/indexes/content/_using-dynamic-fields-nodejs.mdx
@@ -2,533 +2,710 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`createField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
+
-
-#### Example - index any field under object
-The following allows you to:
-
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
-**The document**:
-
-
-{`class Product \{
- constructor(id, attributes) \{
- this.id = id;
-
- // The KEYS under the attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- this.attributes = attributes;
- \}
-\}
-`}
-
-
+
+
+### Example - index every field under an object
-
-
-{`// Sample document content
-\{
- "attributes": \{
- "color": "Red",
- "size": 42
- \}
-\}
-`}
-
-
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
+
-**The index**:
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, attributes) {
+ this.id = id;
+
+ // The KEYS under the attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ this.attributes = attributes;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "color": "Red",
+ "size": 42
+ }
+ }
+ ```
+
-* The following index will index any field under the `attributes` object from the document,
+* **The index**:
+
+ The following index will index any field under the `attributes` object from the document,
a dynamic-index-field will be created for each such field.
- New fields added to the object after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- e.g. Keys `color` & `size` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
- constructor() {
- super();
-
- const { createField } = this.mapUtils();
-
- this.map("Products", p => {
- return {
- // Call 'createField' to generate dynamic-index-fields from the attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
-
- // The actual field name will be the key
- // The actual field terms will be derived from p.attributes[key]
- _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], {
- indexing: "Search",
- storage: false,
- termVector: null
- }))
- };
- });
+ New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `color` & `size` will become the actual dynamic-index-fields.
+
+
+ ```js
+ class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // Call 'createField' to generate dynamic-index-fields
+ // from the attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'
+
+ // The actual field name will be the key
+ // The actual field terms will be derived from p.attributes[key]
+ _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key]))
+ };
+ });
+ }
}
-}
-`}
-
-
-
-
-**The query**:
-
-* You can now query the generated dynamic-index fields.
- Property `_` is Not queryable, it is only used in the index definition syntax.
-
-* To get all documents with some 'size' use:
-
-
-
-
-{`const matchingDocuments = session.query({indexName: 'Products_ByAttributeKey'})
- // 'size' is a dynamic-index-field that was indexed from the attributes object
- .whereEquals('size', 42)
- .all();
-`}
-
-
-
-
-{`// 'size' is a dynamic-index-field that was indexed from the attributes object
-from index 'Products/ByAttributeKey' where size = 42
-`}
-
-
-
-
-
+ ```
+
+
+* **The query**:
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _size_ use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByAttributeKey/JS" })
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ .whereEquals("size", 42)
+ .all();
+ ```
+
+
+ ```sql
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey/JS' where size = 42
+ ```
+
+
+
+
+
+
+
+### Example - index every field
-#### Example - index any field
-The following allows you to:
-
-* Define an index on a collection **without** needing any common structure between the indexed documents.
-* After index is deployed, any new field added to the document will be indexed as well.
-
+The following example allows you to:
+ * Define an index on a collection **without** needing any common structure between the indexed documents.
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
+
+
-
-Consider if that is a true necessity, as indexing every single field can end up costing time and disk space.
-
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
-**The document**:
-
-
-{`class Product \{
- constructor(id, firstName, lastName, title) \{
- this.id = id;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- this.firstName = firstName;
- this.lastName = lastName;
- this.title = title;
- // ...
- \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "firstName": "John",
- "lastName": "Doe",
- "title": "Engineer",
- // ...
-\}
-`}
-
-
-**The index**:
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, firstName, lastName, title) {
+ this.id = id;
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.title = title;
+ // ...
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer",
+ // ...
+ }
+ ```
+
-* The following index will index any field from the document,
+* **The index**:
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
- New fields added to the document after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the field **key**.
- e.g. Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+ New fields added to the document after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+
+ ```js
+ class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ // This will index EVERY FIELD under the top level of the document
+ this.map("Products", p => {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByAnyField/JS" })
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ .whereEquals("lastName", "Doe")
+ .all();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-
-
-
-{`class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
- super();
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, productType, pricePerUnit) {
+ this.id = id;
+
+ // The VALUE of productType will be dynamically indexed
+ this.productType = productType;
+ this.pricePerUnit = pricePerUnit;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+ ```js
+ class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ _: createField(p.productType, p.pricePerUnit)
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByProductType/JS" })
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ .whereEquals("Electronics", 23)
+ .all();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType/JS' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
- const { createField } = this.mapUtils();
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
+
- this.map("Products", p => {
- return {
- // This will index EVERY FIELD under the top level of the document
- _: Object.keys(p).map(key => createField(key, p[key], {
- indexing: "Search",
- storage: true,
- termVector: null
- }))
- };
- });
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, name, attributes) {
+ this.id = id;
+ this.name = name;
+
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ this.attributes = attributes;
+ }
}
-}
-`}
-
-
-
-**The query**:
+ class Attribute {
+ constructor(propName, propValue) {
+ this.propName = propName;
+ this.propValue = propValue;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ },
+ ...
+ ]
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+ ```js
+ class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // Define the dynamic-index-fields by calling 'createField'
+ // A dynamic-index-field will be generated for each item in 'attributes'
+
+ // For each item, the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'
+ _: p.attributes.map(item =>
+ createField(item.propName, item.propValue)),
+
+ // A regular index field can be defined as well:
+ name: p.name
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Attributes/ByName/JS" })
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ .whereEquals("Width", 10)
+ .all();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName/JS' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `indexing: "Search"` in the `createField` options.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
-* To get all documents with some 'lastName' use:
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, descriptions) {
+ this.id = id;
+ this.descriptions = descriptions;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+ ```js
+ class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ const useSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ this.map("Products", product => {
+ return {
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: "Search",
+ storage: false
+ }))
+ };
+ });
+
+ this.storeAllFields("No");
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ this.configuration[useSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Products_ByAnyField_JS' })
- // 'lastName' is a dynamic-index-field that was indexed from the document
- .whereEquals('lastName', 'Doe')
- .all();
-`}
-
-
-
-
-{`// 'lastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where lastName = "Doe"
-`}
-
-
-
+* **Full-text search query**:
-
+ Query the generated dynamic field by its field name.
+ In this example, the query targets the generated field `Description_English`.
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Indexing documents fields VALUES
+
+
+ ```js
+ const results = await session
+ .query({ indexName: "Products/ByLocalizedDescription/JS" })
+ .search("Description_English", "north wind")
+ .all();
+ ```
+
-
-#### Example - basic
-This example shows:
-
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
-**The document**:
-
-
-{`class Product \{
- constructor(id, productType, pricePerUnit) \{
- this.id = id;
-
- // The VALUE of productType will be dynamically indexed
- this.productType = productType;
- this.pricePerUnit = pricePerUnit;
- \}
-\}
-`}
-
-
+
+ ```sql
+ from index "Products/ByLocalizedDescription/JS"
+ where search(Description_English, "north wind")
+ ```
+
+
-
-
-{`// Sample document content
-\{
- "productType": "Electronics",
- "pricePerUnit": 23
-\}
-`}
-
-
+---
-**The index**:
+
+
+### Configuring analyzers for dynamic fields
-* The following index will index the **value** of document field 'productType'.
+The `createField` options object does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
-* This value will be the dynamic-index-field name on which you can query.
- e.g. Field value `Electronics` will be the dynamic-index-field.
+---
-
-
-
-{`class Products_ByProductType extends AbstractCsharpIndexCreationTask {
- constructor () {
- super();
+#### Configure analyzer for a specific dynamic field
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- this.map = "docs.Products.Select(p => new { " +
- " _ = this.CreateField(p.productType, p.pricePerUnit) " +
- "})";
- }
-}
-`}
-
-
-
-
-{`class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
+
+```js
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
super();
const { createField } = this.mapUtils();
- this.map("Products", p => {
+ this.map("Products", product => {
return {
- _: [
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- createField(p.productType, p.pricePerUnit, {
- indexing: "Search",
- storage: false,
- termVector: null
- })
- ]
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ indexing: "Search",
+ storage: false
+ }))
};
});
- }
-}
-`}
-
-
-
-
-**The query**:
-
-* To get all documents of some product type having a specific price per unit use:
-
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Products_ByProductType' })
- // 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
- .whereEquals('Electronics', 23)
- .all();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-
-
-#### Example - list
-The following allows you to:
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-**The document**:
-
-
-{`class Product \{
- constructor(id, name, attributes) \{
- this.id = id;
- this.name = name;
-
- // For each element in this list, the VALUE of property 'propName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- this.attributes = attributes;
- \}
-\}
-
-class Attribute \{
- constructor(propName, propValue) \{
- this.propName = propName;
- this.propValue = propValue;
- \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "name": "SomeName",
- "attributes": [
- \{
- "propName": "Color",
- "propValue": "Blue"
- \},
- \{
- "propName": "Width",
- "propValue": "10"
- \},
- \{
- "propName": "Length",
- "propValue": "20"
- \},
- ...
- ]
-\}
-`}
-
-
-
-**The index**:
-
-* The following index will create a dynamic-index-field per item in the document's `attributes` list.
- New items added to the attributes list after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the item's propName **value**.
- e.g. 'propName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`class Attributes_ByName extends AbstractCsharpIndexCreationTask
-{
- constructor () {
- super();
+ this.storeAllFields("No");
- // For each attribute item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- // A regular-index-field (Name) is defined as well
- this.map =
- "docs.Products.Select(p => new { " +
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " +
- " Name = p.name " +
- "})";
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ this.analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
+
+#### Configure a fallback analyzer for all fields
+
+
+```js
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
super();
const { createField } = this.mapUtils();
- this.map("Products", p => {
+ this.map("Products", product => {
return {
- // For each item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- _: p.attributes.map(item => createField(item.propName, item.propValue, {
- indexing: "Search",
- storage: true,
- termVector: null
- })),
-
- // A regular-index-field can be defined as well:
- Name: p.name
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ indexing: "Search",
+ storage: false
+ }))
};
});
- }
-}
-`}
-
-
-
-
-**The query**:
-* To get all documents matching a specific attribute property use:
+ this.storeAllFields("No");
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Attributes/ByName' })
- // 'Width' is a dynamic-index-field that was indexed from the attributes list
- .whereEquals('Width', 10)
- .all();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ this.analyze(CONSTANTS.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer");
+ }
+}
+```
-
-
-
+
+
+
+
+### Which analyzer is used for the query term?
-## CreateField syntax
+The following applies when a `search()` query targets a **dynamic field**:
-#### Syntax for LINQ-index:
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `this.analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `this.analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-
-
-{`object CreateField(string name, object value);
+
-object CreateField(string name, object value, bool stored, bool analyzed);
+
-object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
-
+
-#### Syntax for JavaScript-index:
+#### Syntax:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|----------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+| Parameters | Type | Description |
+|----------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **options** | `object` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
-| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| options object | | |
+|-----------------|--------------------|-----------------------------------------------------------------------------------|
+| **storage** | `boolean` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
+| **indexing** | `FieldIndexing` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **termVector** | `FieldTermVector` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -536,21 +713,19 @@ object CreateField(string name, object value, CreateFieldOptions options);
However, using `_` is just a convention. Any other string can be used instead.
* This property is Not queryable, it is only used in the index definition syntax.
- The actual dynamic-index-fields that are generated are defined by the `CreateField` method.
+ The actual dynamic-index-fields that are generated are defined by the `createField` method.
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/docs/indexes/content/_using-dynamic-fields-php.mdx b/docs/indexes/content/_using-dynamic-fields-php.mdx
index 09c58cc9fc..6992310715 100644
--- a/docs/indexes/content/_using-dynamic-fields-php.mdx
+++ b/docs/indexes/content/_using-dynamic-fields-php.mdx
@@ -2,537 +2,969 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
+
-* In this page:
+
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
-## Indexing documents fields KEYS
-
-## Example - index any field under object
+* **The document**:
+
+
+ ```php
+ use Ds\Map as DSMap;
-
+ class Product
+ {
+ public ?string $id = null;
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+ // The KEYS under the attributes object will be dynamically indexed.
+ // Fields added to this object after index creation time will also get indexed.
+ public ?DSMap $attributes = null;
-
-
-* **The document**:
-
-
-{`use Ds\\Map as DSMap;
-
-class Product
-\{
- private ?string $id = null;
-
- // The KEYS under the Attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- public ?DSMap $attributes = null;
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-{`class Products_ByAttributeKey extends AbstractIndexCreationTask
-{
- public function __construct()
+
+
+ ```php
+ class Products_ByAttributeKey extends AbstractIndexCreationTask
{
- parent::__construct();
-
- $this->map = "from p in docs.Products select new {" .
- "_ = p.attributes.Select(item => CreateField(item.Key, item.Value))" .
- "}";
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the attributes object keys.
+ //
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'.
+ //
+ // The actual field name will be 'item.Key'.
+ // The actual field terms will be derived from 'item.Value'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = p.attributes.Select(item => CreateField(item.Key, item.Value)) " .
+ "}";
+ }
}
-}
-`}
-
-
-
-
-{`class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask
-{
- public function __construct()
+ ```
+
+
+ ```php
+ class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask
{
- parent::__construct();
-
- $this->setMaps([
- "map('Products', function (p) { " .
- " return { " .
- " _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], " .
- " { indexing: 'Search', storage: false, termVector: null })) " .
- " }; " .
- "}) "
- ]);
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.attributes)
+ .map(key => createField(key, p.attributes[key], null))
+ };
+ })"
+ ]);
+ }
}
-}
-`}
-
-
-
-
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- * To get all documents with some 'size' use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByAttributeKey::class)
- // 'Size' is a dynamic-index-field that was indexed from the Attributes object
- ->whereEquals("Size", 42)
- ->toList();
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
-
-## Example - index any field
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByAttributeKey::class)
+ // 'Size' is a dynamic-index-field that was indexed from the attributes object
+ ->whereEquals("Size", 42)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _documentQuery_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `whereEquals("Size", 42)` or RQL `where Size = 42` instead.
+
+
+
+
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`class Product
-\{
- private ?string $id = null;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- public ?string $firstName = null;
- public ?string $lastName = null;
- public ?string $title = null;
-
- // ... getters and setters
-\}
-`}
-
-
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
-
-
-{`// Sample document content
- \{
- "FirstName": "John",
- "LastName": "Doe",
- "Title": "Engineer",
+ // All KEYS in the document will be dynamically indexed.
+ // Fields added to the document after index creation time will also get indexed.
+ public ?string $firstName = null;
+ public ?string $lastName = null;
+ public ?string $title = null;
// ...
-\}
-`}
-
-
+
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer"
+ // ...
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask
-{
- public function __construct()
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
+
+
+
+ ```php
+ class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask
{
- parent::__construct();
-
- // This will index EVERY FIELD under the top level of the document
- $this->setMaps([
- "map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })"
- ]);
+ public function __construct()
+ {
+ parent::__construct();
+
+ // This will index EVERY FIELD under the top level of the document
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key], null))
+ };
+ })"
+ ]);
+ }
}
-}
-`}
-
-
-
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByAnyField_JS::class)
- // 'LastName' is a dynamic-index-field that was indexed from the document
- ->whereEquals("LastName", "Doe")
- ->toList();
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByAnyField_JS::class)
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ ->whereEquals("lastName", "Doe")
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
+* **The document**:
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
+ // The VALUE of productType will be dynamically indexed
+ public ?string $productType = null;
+ public ?int $pricePerUnit = null;
-## Indexing documents fields VALUES
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
-## Example - basic
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
-
+
+
+ ```php
+ class Products_ByProductType extends AbstractIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Call 'CreateField' to generate the dynamic-index-fields.
+ // The field name will be the value of document field 'productType'.
+ // The field terms will be derived from document field 'pricePerUnit'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = CreateField(p.productType, p.pricePerUnit) " .
+ "}";
+ }
+ }
+ ```
+
+
+ ```php
+ class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ _: createField(p.productType, p.pricePerUnit, null)
+ };
+ })"
+ ]);
+ }
+ }
+ ```
+
+
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByProductType::class)
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ ->whereEquals("Electronics", 23)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`class Product
-\{
- public ?string $id = null;
-
- // The VALUE of ProductType will be dynamically indexed
- public ?string $productType = null;
- public ?int $pricePerUnit = null;
-
- // ... getters and setters
-\}
-`}
-
-
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
+ public ?string $name = null;
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ public ?AttributeList $attributes = null;
+
+ // ... getters and setters
+ }
+
+ class Attribute
+ {
+ public ?string $propName = null;
+ public ?string $propValue = null;
+
+ // ... getters and setters
+ }
+
+ class AttributeList extends TypedList
+ {
+ protected function __construct()
+ {
+ parent::__construct(Attribute::class);
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ }
+ // ...
+ ]
+ }
+ ```
+
* **The index**:
- The below index will index the **value** of document field 'ProductType'.
+
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```php
+ class Attributes_ByName extends AbstractIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Define the dynamic-index-fields by calling 'CreateField'.
+ // A dynamic-index-field will be generated for each item in 'attributes'.
+ //
+ // For each item, the field name will be the value of field 'propName'.
+ // The field terms will be derived from field 'propValue'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = p.attributes.Select(item => CreateField(item.propName, item.propValue)), " .
+ " Name = p.name " .
+ "}";
+ }
+ }
+ ```
+
+
+ ```php
+ class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'
+ _: p.attributes.map(item => createField(
+ item.propName, item.propValue, null)),
+
+ // A regular index field can be defined as well:
+ Name: p.name
+ };
+ })"
+ ]);
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Attributes_ByName::class)
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ ->whereEquals("Width", 10)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing::search()` in `CreateFieldOptions`.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```php
+ use Ds\Map as DSMap;
+
+ class Product
+ {
+ public ?string $id = null;
+ public ?DSMap $descriptions = null;
+
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
-
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```php
+ class Products_ByLocalizedDescription extends AbstractIndexCreationTask
+ {
+ private const USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ // Index each generated dynamic field for FTS
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
+
+ $this->storeAllFields(FieldStorage::no());
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ $this->getConfiguration()[self::USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS] = "true";
+ }
+ }
+ ```
+
+
+ ```php
+ class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ private const USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (product) {
+ return {
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })"
+ ]);
+
+ // Apply a storage default to every generated field
+ $fields = new IndexFieldOptionsArray();
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
+ $this->setFields($fields);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ $this->getConfiguration()[self::USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS] = "true";
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```php
+ /** @var array $results */
+ $results = $session->advanced()
+ ->documentQuery(Product::class, Products_ByLocalizedDescription::class)
+ ->search("Description_English", "north wind")
+ ->toList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
+
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
-
-{`class Products_ByProductType extends AbstractIndexCreationTask
+```php
+class Products_ByLocalizedDescription extends AbstractIndexCreationTask
{
public function __construct()
{
parent::__construct();
- // Call 'CreateField' to generate the dynamic-index-fields
- // The field name will be the value of document field 'ProductType'
- // The field terms will be derived from document field 'PricePerUnit'
- $this->map = "docs.Products.Select(p => new { " .
- " _ = this.CreateField(p.productType, p.pricePerUnit) " .
- "})";
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
+
+ $this->storeAllFields(FieldStorage::no());
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ $this->analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask
+
+```php
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
{
public function __construct()
{
parent::__construct();
$this->setMaps([
- "map('Products', function (p) {
+ "map('Products', function (product) {
return {
- _: createField(p.ProductType, p.PricePerUnit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
]);
- }
-}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByProductType::class)
-// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-->whereEquals("Electronics", 23)
-->toList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-## Example - list
-
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
+ // Apply a storage default to every generated field +
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ $fields = new IndexFieldOptionsArray();
-
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
-* **The document**:
-
-
-{`class Product
-\{
- public ?string $id = null;
- public ?string $name = null;
-
- // For each element in this list, the VALUE of property 'PropName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- public ?AttributeList $attributes = null;
-
- // ... getters and setters
-\}
-
-class Attribute
-\{
- public ?string $propName = null;
- public ?string $propValue = null;
-
- // ... getters and setters
-\}
-
-class AttributeList extends TypedList
-\{
- protected function __construct()
- \{
- parent::__construct(Attribute::class);
- \}
-\}
-`}
-
-
+ $englishFieldOptions = new IndexFieldOptions();
+ $englishFieldOptions->setAnalyzer("StopAnalyzer");
+ $fields->offsetSet("Description_English", $englishFieldOptions);
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
+ $this->setFields($fields);
+ }
+}
+```
+
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `width` will be a dynamic-index-field.
+#### Configure a fallback analyzer for all fields
-
+
-
-{`class Attributes_ByName extends AbstractIndexCreationTask
+```php
+class Products_ByLocalizedDescription extends AbstractIndexCreationTask
{
public function __construct()
{
parent::__construct();
- // Define the dynamic-index-fields by calling CreateField
- // A dynamic-index-field will be generated for each item in the Attributes list
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
- // For each item, the field name will be the value of field 'PropName'
- // The field terms will be derived from field 'PropValue'
+ $this->storeAllFields(FieldStorage::no());
- $this->map =
- "docs.Products.Select(p => new { " .
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " .
- " Name = p.name " .
- "})";
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ $this->analyze(DocumentsIndexingFields::ALL_FIELDS, "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask
+
+```php
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
{
public function __construct()
{
parent::__construct();
$this->setMaps([
- "map('Products', function (p) {
+ "map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
]);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ $fields = new IndexFieldOptionsArray();
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $allFieldsOptions->setAnalyzer("StopAnalyzer");
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
+ $this->setFields($fields);
}
}
-`}
-
-
-
-
-* **The query**:
- To get all documents matching a specific attribute property use:
-
-
-
-{`/** @var array $matchingDocuments */
-$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Attributes_ByName::class)
- // 'Width' is a dynamic-index-field that was indexed from the Attributes list
- ->whereEquals("Width", 10)
- ->toList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+The following applies when a `search()` query targets a **dynamic field**:
-## CreateField syntax
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `$this->analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `$this->analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-
-
-{`object CreateField(string name, object value);
+
+
+
+
+
+
+#### Syntax for LINQ-index:
+
+
+```php
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
-| Parameters | Type | Description |
-|------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **name** | `string` | Name of the dynamic-index-field |
-| **value** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`False` - will set `FieldStorage.NO` (default value)
`True` - will set `FieldStorate.YES` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`None` - `FieldIndexing.Default` (default value)
`False` - `FieldIndexing.Exact`
`True` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+#### Syntax for JavaScript-index:
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
-| **Storage** | `FieldStorage` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing` | |
-| **TermVector** | `FieldTermVector` | |
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
+
+
+| Parameters | Type | Description |
+|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage::no()` (default value)
`true` - will set `FieldStorage::yes()` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing::default()` (default value)
`false` - `FieldIndexing::exact()`
`true` - `FieldIndexing::search()` |
+| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
+| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -544,17 +976,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/docs/indexes/content/_using-dynamic-fields-python.mdx b/docs/indexes/content/_using-dynamic-fields-python.mdx
index 69514a29e2..6862d18067 100644
--- a/docs/indexes/content/_using-dynamic-fields-python.mdx
+++ b/docs/indexes/content/_using-dynamic-fields-python.mdx
@@ -1,490 +1,886 @@
import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
-import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
-
-## Example - index any field under object
+
-
-
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, attributes: Dict[str, object] = None):
- self.Id = Id
-
- # The KEYS under the Attributes object will be dynamically indexed
- # Fields added to this object after index creation time will also get indexed
- self.attributes = attributes
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, Attributes: Dict[str, object] = None):
+ self.Id = Id
+
+ # The KEYS under the Attributes object will be dynamically indexed
+ # Fields added to this object after index creation time will also get indexed
+ self.Attributes = Attributes
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `Attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAttributeKey(AbstractIndexCreationTask):
- def __init__(self):
- super().__init__()
- self.map = (
- "from p in docs.Products select new {"
- "_ = p.attributes.Select(item => CreateField(item.Key, item.Value))"
- "}"
- )
-`}
-
-
-
-
-{`class Products_ByAttributeKey_JS(AbstractJavaScriptIndexCreationTask):
- def __init__(self):
- super().__init__()
- self.maps = {
- """
- map('Products', function (p) {
- return {
- _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key],
- { indexing: 'Search', storage: true, termVector: null }))
- };
- })
- """
- }
-`}
-
-
-
-
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+
+
+
+ ```python
+ class Products_ByAttributeKey(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from p in docs.Products select new { "
+ # Call 'CreateField' to generate dynamic-index-fields
+ # from the Attributes object keys.
+
+ # Using '_' is just a convention.
+ # Any other string can be used instead of '_'
+
+ # The actual field name will be 'item.Key'
+ # The actual field terms will be derived from 'item.Value'
+ "_ = p.Attributes.Select(item => CreateField(item.Key, item.Value)) "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Products_ByAttributeKey_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.Attributes)
+ .map(key => createField(key, p.Attributes[key]))
+ };
+ })
+ """
+ ]
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- * To get all documents with some 'size' use:
-
-
-
-{`matching_documents = list(
- session.query_index_type(Products_ByAttributeKey, Product)
- # 'size' is a dynamic-index-field that was indexed from the attributes object
- .where_equals("size", 42)
-)
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
-
-## Example - index any field
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByAttributeKey, Product)
+ # 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ .where_equals("Size", 42)
+ )
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _document_query_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `where_equals("Size", 42)` or RQL `where Size = 42`.
+
+
+
+
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, first_name: str = None, last_name: str = None, title: str = None):
- self.Id = Id
-
- # All KEYS in the document will be dynamically indexes
- # Fields added to the document after index creation time wil also get indexed
- self.first_name = first_name
- self.last_name = last_name
- self.title = title
- # ...
-`}
-
-
-
-
-
-{`// Sample document content
- \{
+
+
+ ```python
+ class Product:
+ def __init__(
+ self,
+ Id: str = None,
+ FirstName: str = None,
+ LastName: str = None,
+ Title: str = None,
+ ):
+ self.Id = Id
+
+ # All KEYS in the document will be dynamically indexed
+ # Fields added to the document after index creation time will also get indexed
+ self.FirstName = FirstName
+ self.LastName = LastName
+ self.Title = Title
+ # ...
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
"FirstName": "John",
"LastName": "Doe",
"Title": "Engineer",
// ...
-\}
-`}
-
-
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAnyField_JS(AbstractJavaScriptIndexCreationTask):
- def __init__(self):
- super().__init__()
- # This will index EVERY FIELD under the top level of the document
- self.maps = {
- """
- map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })
- """
- }
-`}
-
-
-
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
+
+
+
+ ```python
+ class Products_ByAnyField_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ # This will index EVERY FIELD under the top level of the document
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ })
+ """
+ ]
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`# 'last_name' is a dynamic-index-field that was indexed from the document
-matching_documents = list(
- session.query_index_type(Products_ByAnyField_JS, Product).where_equals("last_name", "Doe")
-)
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _LastName_ use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByAnyField_JS, Product)
+ # 'LastName' is a dynamic-index-field that was indexed from the document
+ .where_equals("LastName", "Doe")
+ )
+ ```
+
+
+ ```sql
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where LastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
+
+* **The document**:
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, ProductType: str = None, PricePerUnit: int = None):
+ self.Id = Id
+
+ # The VALUE of ProductType will be dynamically indexed
+ self.ProductType = ProductType
+ self.PricePerUnit = PricePerUnit
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "ProductType": "Electronics",
+ "PricePerUnit": 23
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will index the **value** of document field 'ProductType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```python
+ class Products_ByProductType(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from p in docs.Products select new { "
+ # Call 'CreateField' to generate the dynamic-index-fields
+ # The field name will be the value of document field 'ProductType'
+ # The field terms will be derived from document field 'PricePerUnit'
+ "_ = CreateField(p.ProductType, p.PricePerUnit) "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Products_ByProductType_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _: createField(p.ProductType, p.PricePerUnit)
+ };
+ })
+ """
+ ]
+ ```
+
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByProductType, Product)
+ # 'Electronics' is the dynamic-index-field that was indexed
+ # from document field 'ProductType'
+ .where_equals("Electronics", 23)
+ )
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
+
+
+* **The document**:
+
+
+ ```python
+ class Attribute:
+ def __init__(self, PropName: str = None, PropValue: str = None):
+ self.PropName = PropName
+ self.PropValue = PropValue
+
+
+ class Product:
+ def __init__(self, Id: str = None, Name: str = None, Attributes: List[Attribute] = None):
+ self.Id = Id
+ self.Name = Name
+
+ # For each element in this list,
+ # the VALUE of property 'PropName' will be dynamically indexed.
+ # e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ self.Attributes = Attributes
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Name": "SomeName",
+ "Attributes": [
+ {
+ "PropName": "Color",
+ "PropValue": "Blue"
+ },
+ {
+ "PropName": "Width",
+ "PropValue": "10"
+ },
+ {
+ "PropName": "Length",
+ "PropValue": "20"
+ },
+ // ...
+ ]
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will create a dynamic-index-field per item in the document's `Attributes` list.
+ New items added to the Attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
+ E.g., 'PropName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```python
+ class Attributes_ByName(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from a in docs.Products select new { "
+ # Define the dynamic-index-fields by calling 'CreateField'
+ # A dynamic-index-field will be generated for each item in 'Attributes'
+
+ # For each item, the field name will be the value of field 'PropName'
+ # The field terms will be derived from field 'PropValue'
+ "_ = a.Attributes.Select(item => CreateField(item.PropName, item.PropValue)), "
+
+ # A regular index field can be defined as well:
+ "Name = a.Name "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Attributes_ByName_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _: p.Attributes.map(item => createField(item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name: p.Name
+ };
+ })
+ """
+ ]
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Attributes_ByName, Product)
+ # 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ .where_equals("Width", 10)
+ )
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing.Search` in `CreateFieldOptions`.
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Indexing documents fields VALUES
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
-## Example - basic
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
-
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, Descriptions: Dict[str, str] = None):
+ self.Id = Id
+ self.Descriptions = Descriptions
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
-* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, product_type: str = None, price_per_unit: float = None):
- self.Id = Id
-
- # The VALUE of ProductType will be dynamically indexed
- self.product_type = product_type
- self.price_per_unit = price_per_unit
-`}
-
-
+* **The index**:
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+ The following index creates one dynamic field for each entry in the `Descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
-* **The index**:
- The below index will index the **value** of document field 'ProductType'.
-
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```python
+ class Products_ByLocalizedDescription(AbstractIndexCreationTask):
+ USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS = (
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery"
+ )
+
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ # Index each generated dynamic field for FTS
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
+ "}"
+ )
+
+ self._store_all_fields(FieldStorage.NO)
+
+ # Set this configuration key to true so that search() queries on dynamic fields
+ # will use the 'Default Search Analyzer' when the generated field name
+ # has no explicit analyzer configuration.
+ self.configuration = {
+ Products_ByLocalizedDescription.USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS: "true"
+ }
+ ```
+
+
+ ```python
+ class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
+ USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS = (
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery"
+ )
+
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (product) {
+ return {
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })
+ """
+ ]
+
+ # Apply a storage default to every generated field
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO)
+ }
+
+ # Set this configuration key to true so that search() queries on dynamic fields
+ # will use the 'Default Search Analyzer' when the generated field name
+ # has no explicit analyzer configuration.
+ self.configuration = {
+ Products_ByLocalizedDescription_JS.USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS: "true"
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```python
+ results = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByLocalizedDescription, Product)
+ .search("Description_English", "north wind")
+ )
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
+
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
-
-{`class Products_ByProductType(AbstractIndexCreationTask):
+```python
+class Products_ByLocalizedDescription(AbstractIndexCreationTask):
def __init__(self):
super().__init__()
+ self.map = (
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
+ "}"
+ )
- # Call 'CreateField' to generate the dynamic-index-fields
- # The field name will be the value of document field 'product_type'
- # The field terms will be derived from document field 'price_per_unit'
- self.map = "from p in docs.Products select new { _ = CreateField(p.product_type, p.price_per_unit)}"
-`}
-
+ self._store_all_fields(FieldStorage.NO)
+
+ # Configure an analyzer for a known generated dynamic field name
+ # ==============================================================
+ self._analyze("Description_English", "StopAnalyzer")
+```
-
-
-{`class Products_ByProductType_JS(AbstractJavaScriptIndexCreationTask):
+
+```python
+class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
def __init__(self):
super().__init__()
- self.maps = {
+ self.maps = [
"""
- map('Products', function (p) {
+ map('Products', function (product) {
return {
- _: createField(p.product_type, p.price_per_unit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})
"""
+ ]
+
+ # Configure an analyzer for a known generated dynamic field name
+ # ==============================================================
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO),
+ "Description_English":
+ IndexFieldOptions(analyzer="StopAnalyzer")
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`# 'electronics' is the dynamic-index-field that was indexed from the document 'product_type'
-matching_documents = list(
- session.advanced.document_query_from_index_type(Products_ByProductType, Product).where_equals(
- "electronics", 23
- )
-)
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
+```
-## Example - list
-
-
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-
-
-
-* **The document**:
-
-
-{`class Attribute:
- def __init__(self, prop_name: str = None, prop_value: str = None):
- self.prop_name = prop_name
- self.prop_value = prop_value
-
-
-class Product:
- def __init__(self, Id: str = None, name: str = None, attributes: List[Attribute] = None):
- self.Id = Id
- self.name = name
- # For each element in this list, the VALUE of property 'prop_name' will be dynamically indexed
- # e.g. color, width, length (in ex. below) will become dynamic-index-field
- self.attributes = attributes
-`}
-
-
-
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
-
-
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `width` will be a dynamic-index-field.
+#### Configure a fallback analyzer for all fields
-
-{`class Attributes_ByName(AbstractIndexCreationTask):
+```python
+class Products_ByLocalizedDescription(AbstractIndexCreationTask):
def __init__(self):
super().__init__()
self.map = (
- "from a in docs.Products select new "
- "{ _ = a.attributes.Select( item => CreateField(item.prop_name, item.prop_value)), name = a.name "
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
"}"
)
-`}
-
+
+ self._store_all_fields(FieldStorage.NO)
+
+ # Use this as a fallback for fields that do not have
+ # their own explicit analyzer configuration
+ # ==================================================
+ self._analyze(constants.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer")
+```
-
-
-{`class Attributes_ByName_JS(AbstractJavaScriptIndexCreationTask):
+
+```python
+class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
def __init__(self):
super().__init__()
- self.maps = {
+ self.maps = [
"""
- map('Products', function (p) {
+ map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})
"""
+ ]
+
+ # Use this as a fallback for fields that do not have
+ # their own explicit analyzer configuration
+ # ==================================================
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO, analyzer="StopAnalyzer")
}
-`}
-
-
-
-
-* **The query**:
- To get all documents matching a specific attribute property use:
-
-
-
-{`matching_documents = list(
- session.advanced.document_query_from_index_type(Attributes_ByName, Product).where_equals(
- "width", 10
- )
-)
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+
+The following applies when a `search()` query targets a **dynamic field**:
+
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `self._analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `self._analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+
+
+
-## CreateField syntax
+
#### Syntax for Index:
-
-
-{`object CreateField(string name, object value);
+
+```python
+CreateField(name, value)
-object CreateField(string name, object value, bool stored, bool analyzed);
+CreateField(name, value, stored, analyzed)
-object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+CreateField(name, value, CreateFieldOptions)
+```
#### Syntax for JavaScript-index:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **name** | `string` | Name of the dynamic-index-field |
-| **value** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`False` - will set `FieldStorage.NO` (default value)
`True` - will set `FieldStorate.YES` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`None` - `FieldIndexing.Default` (default value)
`False` - `FieldIndexing.Exact`
`True` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+| Parameters | Type | Description |
+|----------------|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
+| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -496,17 +892,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).


-
-
-
-
+
+
diff --git a/docs/indexes/querying/content/_searching-csharp.mdx b/docs/indexes/querying/content/_searching-csharp.mdx
index d20ef5a65e..f0be0e6ffd 100644
--- a/docs/indexes/querying/content/_searching-csharp.mdx
+++ b/docs/indexes/querying/content/_searching-csharp.mdx
@@ -16,11 +16,13 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
* [Searching with wildcards](../../../indexes/querying/searching.mdx#searching-with-wildcards)
* [When using RavenStandardAnalyzer or StandardAnalyzer or NGramAnalyzer](../../../indexes/querying/searching.mdx#when-usingoror)
@@ -28,6 +30,7 @@ import CodeBlock from '@theme/CodeBlock';
* [When using the Exact analyzer](../../../indexes/querying/searching.mdx#when-using-the-exact-analyzer)
+
## Indexing single field for FTS
#### The index:
@@ -262,7 +265,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly,
+* To search across ALL fields in a document without defining each one explicitly,
use the `AsJson` method in the _Map_ function to extract all property values and index them in a single searchable field.
* This approach makes the index robust to changes in the document schema.
@@ -377,7 +380,14 @@ where search(AllValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/docs/indexes/querying/content/_searching-java.mdx b/docs/indexes/querying/content/_searching-java.mdx
index 7d85246ced..4accf3f512 100644
--- a/docs/indexes/querying/content/_searching-java.mdx
+++ b/docs/indexes/querying/content/_searching-java.mdx
@@ -388,4 +388,11 @@ where search(allValues, "tofu")
+## Indexing dynamic fields for FTS
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
\ No newline at end of file
diff --git a/docs/indexes/querying/content/_searching-nodejs.mdx b/docs/indexes/querying/content/_searching-nodejs.mdx
index 4ca66b5877..cb73bfd7c0 100644
--- a/docs/indexes/querying/content/_searching-nodejs.mdx
+++ b/docs/indexes/querying/content/_searching-nodejs.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,11 +17,13 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
* [Searching with wildcards](../../../indexes/querying/searching.mdx#searching-with-wildcards)
* [When using RavenStandardAnalyzer or StandardAnalyzer or NGramAnalyzer](../../../indexes/querying/searching.mdx#when-usingoror)
@@ -29,6 +31,7 @@ import CodeBlock from '@theme/CodeBlock';
* [When using the Exact analyzer](../../../indexes/querying/searching.mdx#when-using-the-exact-analyzer)
+
## Indexing single field for FTS
#### The index:
@@ -163,7 +166,7 @@ where (search(employeeData, "Manager") or search(employeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available when using **a C# LINQ string** that is assigned to the `map` property in the Node.js index class,
as shown in the example below.
@@ -229,6 +232,14 @@ where search(AllValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/docs/indexes/querying/content/_searching-php.mdx b/docs/indexes/querying/content/_searching-php.mdx
index 55261ce19f..510a6f8752 100644
--- a/docs/indexes/querying/content/_searching-php.mdx
+++ b/docs/indexes/querying/content/_searching-php.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,14 +17,17 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
+
## Indexing single field for FTS
#### The index:
@@ -253,7 +256,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available in the **C# LINQ string** that is assigned to the `map` property in the PHP index class,
as shown in the example below.
@@ -332,6 +335,15 @@ where search(allValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
+
## Boosting search results
diff --git a/docs/indexes/querying/content/_searching-python.mdx b/docs/indexes/querying/content/_searching-python.mdx
index f06c29d94f..88c6aa452f 100644
--- a/docs/indexes/querying/content/_searching-python.mdx
+++ b/docs/indexes/querying/content/_searching-python.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,14 +17,17 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
+
## Indexing single field for FTS
#### The index:
@@ -167,7 +170,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available in the **C# LINQ string** that is assigned to the `map` property in the Python index class,
as shown in the example below.
@@ -238,6 +241,14 @@ where search(all_values, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/docs/indexes/using-dynamic-fields.mdx b/docs/indexes/using-dynamic-fields.mdx
index 19b5239557..e465ba5431 100644
--- a/docs/indexes/using-dynamic-fields.mdx
+++ b/docs/indexes/using-dynamic-fields.mdx
@@ -1,6 +1,6 @@
---
-title: "Indexes: Dynamic Index Fields"
-sidebar_label: Dynamic Fields
+title: "Dynamic Index Fields"
+sidebar_label: "Dynamic Index Fields"
description: "Index document fields dynamically in RavenDB when field names are unknown at index definition time, using the CreateField method."
sidebar_position: 27
supported_languages: ["csharp", "java", "python", "php", "nodejs"]
@@ -32,7 +32,6 @@ import UsingDynamicFieldsPython from './content/_using-dynamic-fields-python.mdx
import UsingDynamicFieldsPhp from './content/_using-dynamic-fields-php.mdx';
import UsingDynamicFieldsNodejs from './content/_using-dynamic-fields-nodejs.mdx';
-
diff --git a/docs/server/configuration/indexing-configuration.mdx b/docs/server/configuration/indexing-configuration.mdx
index 132bf987f5..0abdfc4f72 100644
--- a/docs/server/configuration/indexing-configuration.mdx
+++ b/docs/server/configuration/indexing-configuration.mdx
@@ -104,6 +104,7 @@ import LanguageContent from "@site/src/components/LanguageContent";
[Indexing.OrderByTicksAutomaticallyWhenDatesAreInvolved](../../server/configuration/indexing-configuration.mdx#indexingorderbyticksautomaticallywhendatesareinvolved)
[Indexing.QueryClauseCache.Disabled](../../server/configuration/indexing-configuration.mdx#indexingqueryclausecachedisabled)
[Indexing.QueryClauseCache.RepeatedQueriesTimeFrameInSec](../../server/configuration/indexing-configuration.mdx#indexingqueryclausecacherepeatedqueriestimeframeinsec)
+ [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
[Indexing.ScratchSpaceLimitInMb](../../server/configuration/indexing-configuration.mdx#indexingscratchspacelimitinmb)
[Indexing.Static.SearchEngineType](../../server/configuration/indexing-configuration.mdx#indexingstaticsearchenginetype)
[Indexing.Throttling.TimeIntervalInMs](../../server/configuration/indexing-configuration.mdx#indexingthrottlingtimeintervalinms)
@@ -1009,6 +1010,33 @@ Queries that repeat within this time frame will be considered worth caching.
+## Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery
+
+* This setting controls which analyzer is used for the **query term** when a **`search()` query** targets a [Dynamic index field](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ that was indexed for full-text search, and no analyzer is explicitly configured for that field in the index definition.
+
+ * `false` (default):
+ The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) is used to analyze the **query term**.
+ This analyzer can be configured via the [Indexing.Analyzers.Default](../../server/configuration/indexing-configuration.mdx#indexinganalyzersdefault) configuration key.
+
+ * `true`:
+ The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) is used to analyze the **query term**.
+ This analyzer can be configured via the [Indexing.Analyzers.Search.Default](../../server/configuration/indexing-configuration.mdx#indexinganalyzerssearchdefault) configuration key.
+
+* See the table in [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ for the complete analyzer-selection rules based on this configuration key and the analyzer configured for the dynamic index field.
+
+* This configuration applies to both the Lucene and Corax search engines.
+ The default is `false` to preserve backward compatibility.
+
+---
+
+- **Type**: `bool`
+- **Default**: `false`
+- **Scope**: Server-wide, or per database, or per index
+
+
+
## Indexing.ScratchSpaceLimitInMb
* Amount of scratch space in megabytes that we allow to use for the index storage.
diff --git a/versioned_docs/version-6.2/indexes/assets/dynamic-index-fields-1.png b/versioned_docs/version-6.2/indexes/assets/dynamic-index-fields-1.png
index b13d9076f8..a20adda0ec 100644
Binary files a/versioned_docs/version-6.2/indexes/assets/dynamic-index-fields-1.png and b/versioned_docs/version-6.2/indexes/assets/dynamic-index-fields-1.png differ
diff --git a/versioned_docs/version-6.2/indexes/assets/dynamic-index-fields-2.png b/versioned_docs/version-6.2/indexes/assets/dynamic-index-fields-2.png
index dd2b4082ea..c5b1bc14bc 100644
Binary files a/versioned_docs/version-6.2/indexes/assets/dynamic-index-fields-2.png and b/versioned_docs/version-6.2/indexes/assets/dynamic-index-fields-2.png differ
diff --git a/versioned_docs/version-6.2/indexes/content/_using-analyzers-csharp.mdx b/versioned_docs/version-6.2/indexes/content/_using-analyzers-csharp.mdx
index 6022cfd145..2e824fea4b 100644
--- a/versioned_docs/version-6.2/indexes/content/_using-analyzers-csharp.mdx
+++ b/versioned_docs/version-6.2/indexes/content/_using-analyzers-csharp.mdx
@@ -24,7 +24,7 @@ import CodeBlock from '@theme/CodeBlock';
* [Understanding the role of analyzers](../../indexes/using-analyzers.mdx#understanding-the-role-of-analyzers)
* [Analyzers available in RavenDB](../../indexes/using-analyzers.mdx#analyzers-available-in-ravendb)
* [Setting analyzer for index-field](../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field)
- * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendb)
+ * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendbs-default-analyzers)
* [Disabling indexing for index-field](../../indexes/using-analyzers.mdx#disabling-indexing-for-index-field)
* [Creating custom analyzers](../../indexes/using-analyzers.mdx#creating-custom-analyzers)
* [Viewing the indexed terms](../../indexes/using-analyzers.mdx#viewing-the-indexed-terms)
diff --git a/versioned_docs/version-6.2/indexes/content/_using-analyzers-nodejs.mdx b/versioned_docs/version-6.2/indexes/content/_using-analyzers-nodejs.mdx
index 6afd3b6202..fae2cdd2b9 100644
--- a/versioned_docs/version-6.2/indexes/content/_using-analyzers-nodejs.mdx
+++ b/versioned_docs/version-6.2/indexes/content/_using-analyzers-nodejs.mdx
@@ -24,7 +24,7 @@ import CodeBlock from '@theme/CodeBlock';
* [Understanding the role of analyzers](../../indexes/using-analyzers.mdx#understanding-the-role-of-analyzers)
* [Analyzers available in RavenDB](../../indexes/using-analyzers.mdx#analyzers-available-in-ravendb)
* [Setting analyzer for index-field](../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field)
- * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendb)
+ * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendbs-default-analyzers)
* [Disabling indexing for index-field](../../indexes/using-analyzers.mdx#disabling-indexing-for-index-field)
* [Creating custom analyzers](../../indexes/using-analyzers.mdx#creating-custom-analyzers)
* [Viewing the indexed terms](../../indexes/using-analyzers.mdx#viewing-the-indexed-terms)
diff --git a/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-csharp.mdx b/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-csharp.mdx
index b4c4f518df..5bf052d482 100644
--- a/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-csharp.mdx
+++ b/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-csharp.mdx
@@ -2,533 +2,923 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
-
-## Example - index any field under object
-
-
+
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // The KEYS under the Attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- public Dictionary Attributes \{ get; set; \}
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // The KEYS under the Attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ public Dictionary Attributes { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `Attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-{`public class Products_ByAttributeKey : AbstractIndexCreationTask
-{
- public Products_ByAttributeKey()
+
+
+ ```csharp
+ public class Products_ByAttributeKey : AbstractIndexCreationTask
{
- Map = products => from p in products
- select new
- {
- // Call 'CreateField' to generate dynamic-index-fields from the Attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
-
- // The actual field name will be item.Key
- // The actual field terms will be derived from item.Value
- _ = p.Attributes.Select(item => CreateField(item.Key, item.Value))
- };
+ public Products_ByAttributeKey()
+ {
+ Map = products => from p in products
+ select new
+ {
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the Attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'
+
+ // The actual field name will be 'item.Key'
+ // The actual field terms will be derived from 'item.Value'
+ _ = p.Attributes.Select(item => CreateField(item.Key, item.Value))
+ };
+ }
}
-}
-`}
-
-
-
-
-{`public class Products_ByAttributeKey_JS : AbstractJavaScriptIndexCreationTask
-{
- public Products_ByAttributeKey_JS()
+ ```
+
+
+ ```csharp
+ public class Products_ByAttributeKey_JS : AbstractJavaScriptIndexCreationTask
{
- Maps = new HashSet
+ public Products_ByAttributeKey_JS()
{
- @"map('Products', function (p) {
- return {
- _: Object.keys(p.Attributes).map(key => createField(key, p.Attributes[key],
- { indexing: 'Search', storage: true, termVector: null }))
- };
- })"
- };
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.Attributes)
+ .map(key => createField(key, p.Attributes[key]))
+ };
+ })"
+ };
+ }
}
-}
-`}
-
-
-
-
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- The `_` property is Not queryable but used only in the index definition syntax.
- * To get all documents with some 'Size' use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Size' is a dynamic-index-field that was indexed from the Attributes object
- .WhereEquals("Size", 42)
- .ToList();
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ .WhereEquals("Size", 42)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _DocumentQuery_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ A strongly typed LINQ query such as `Query().Where(p => p.Size == 42)` would not compile.
+ Use the string-based `WhereEquals("Size", 42)` or RQL `where Size = 42` instead.
+
-## Example - index any field
+
-
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- public string FirstName \{ get; set; \}
- public string LastName \{ get; set; \}
- public string Title \{ get; set; \}
- // ...
-\}
-`}
-
-
-
-
-
-{`// Sample document content
- \{
- "FirstName": "John",
- "LastName": "Doe",
- "Title": "Engineer",
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ public string FirstName { get; set; }
+ public string LastName { get; set; }
+ public string Title { get; set; }
// ...
-\}
-`}
-
-
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "FirstName": "John",
+ "LastName": "Doe",
+ "Title": "Engineer",
+ // ...
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
-
-
-
-{`public class Products_ByAnyField_JS : AbstractJavaScriptIndexCreationTask
-{
- public Products_ByAnyField_JS()
+
+
+ ```csharp
+ public class Products_ByAnyField_JS : AbstractJavaScriptIndexCreationTask
{
- // This will index EVERY FIELD under the top level of the document
- Maps = new HashSet
+ public Products_ByAnyField_JS()
{
- @"map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })"
- };
+ // This will index EVERY FIELD under the top level of the document
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ })"
+ };
+ }
}
-}
-`}
-
-
-
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'LastName' is a dynamic-index-field that was indexed from the document
- .WhereEquals("LastName", "Doe")
- .ToList();
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _LastName_ use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ .WhereEquals("LastName", "Doe")
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where LastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+### Example - basic
-## Indexing documents fields VALUES
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-## Example - basic
+* **The document**:
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // The VALUE of ProductType will be dynamically indexed
+ public string ProductType { get; set; }
+ public int PricePerUnit { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "ProductType": "Electronics",
+ "PricePerUnit": 23
+ }
+ ```
+
-
+* **The index**:
+
+ The following index will index the **value** of document field 'ProductType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```csharp
+ public class Products_ByProductType : AbstractIndexCreationTask
+ {
+ public Products_ByProductType()
+ {
+ Map = products => from p in products
+ select new
+ {
+ // Call 'CreateField' to generate the dynamic-index-fields
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _ = CreateField(p.ProductType, p.PricePerUnit)
+ };
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Products_ByProductType_JS : AbstractJavaScriptIndexCreationTask
+ {
+ public Products_ByProductType_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _: createField(p.ProductType, p.PricePerUnit)
+ };
+ })"
+ };
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ .WhereEquals("Electronics", 23)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
+### Example - list
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // The VALUE of ProductType will be dynamically indexed
- public string ProductType \{ get; set; \}
- public int PricePerUnit \{ get; set; \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+ public string Name { get; set; }
+
+ // For each element in this list,
+ // the VALUE of property 'PropName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ public List Attributes { get; set; }
+ }
+
+ public class Attribute
+ {
+ public string PropName { get; set; }
+ public string PropValue { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Name": "SomeName",
+ "Attributes": [
+ {
+ "PropName": "Color",
+ "PropValue": "Blue"
+ },
+ {
+ "PropName": "Width",
+ "PropValue": "10"
+ },
+ {
+ "PropName": "Length",
+ "PropValue": "20"
+ },
+ ...
+ ]
+ }
+ ```
+
* **The index**:
- The below index will index the **value** of document field 'ProductType'.
+
+ The following index will create a dynamic-index-field per item in the document's `Attributes` list.
+ New items added to the Attributes list after index creation time will be dynamically indexed as well.
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
+ E.g., 'PropName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```csharp
+ public class Attributes_ByName : AbstractIndexCreationTask
+ {
+ public Attributes_ByName()
+ {
+ Map = products => from a in products
+ select new
+ {
+ // Define the dynamic-index-fields by calling 'CreateField'
+ // A dynamic-index-field will be generated for each item in 'Attributes'
+
+ // For each item, the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _ = a.Attributes.Select(item =>
+ CreateField(item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name = a.Name
+ };
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Attributes_ByName_JS : AbstractJavaScriptIndexCreationTask
+ {
+ public Attributes_ByName_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _: p.Attributes.map(item => createField(
+ item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name: p.Name
+ };
+ })"
+ };
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ .WhereEquals("Width", 10)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing.Search` in `CreateFieldOptions`.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `AllFields` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `AllFields` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ public Dictionary Descriptions { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `Descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```csharp
+ public class Products_ByLocalizedDescription : AbstractIndexCreationTask
+ {
+ private const string UseSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription()
+ {
+ Map = products => from product in products
+ select new
+ {
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ // Index each generated dynamic field for FTS
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
+ };
+
+ StoreAllFields(FieldStorage.No);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ Configuration[UseSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
+ {
+ private const string UseSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (product) {
+ return {
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })"
+ };
+
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No
+ };
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ Configuration[UseSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```csharp
+ List results = session.Advanced
+ .DocumentQuery()
+ .Search("Description_English", "north wind")
+ .ToList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
-
-
-
-{`public class Products_ByProductType : AbstractIndexCreationTask
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `AllFields` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `AllFields` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
+
+```csharp
+public class Products_ByLocalizedDescription : AbstractIndexCreationTask
{
- public Products_ByProductType()
+ public Products_ByLocalizedDescription()
{
- Map = products => from p in products
+ Map = products => from product in products
select new
{
- // Call 'CreateField' to generate the dynamic-index-fields
- // The field name will be the value of document field 'ProductType'
- // The field terms will be derived from document field 'PricePerUnit'
- _ = CreateField(p.ProductType, p.PricePerUnit)
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
};
+
+ StoreAllFields(FieldStorage.No);
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ Analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`public class Products_ByProductType_JS : AbstractJavaScriptIndexCreationTask
+
+```csharp
+public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
{
- public Products_ByProductType_JS()
+ public Products_ByLocalizedDescription_JS()
{
Maps = new HashSet
{
- @"map('Products', function (p) {
+ @"map('Products', function (product) {
return {
- _: createField(p.ProductType, p.PricePerUnit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
};
+
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No
+ };
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ Fields["Description_English"] = new IndexFieldOptions
+ {
+ Analyzer = "StopAnalyzer"
+ };
}
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
- .WhereEquals("Electronics", 23)
- .ToList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
+```
-## Example - list
-
-
+#### Configure a fallback analyzer for all fields
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-
-
-
-* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
- public string Name \{ get; set; \}
-
- // For each element in this list, the VALUE of property 'PropName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- public List Attributes \{ get; set; \}
-\}
-
-public class Attribute
-\{
- public string PropName \{ get; set; \}
- public string PropValue \{ get; set; \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
-
-
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`public class Attributes_ByName : AbstractIndexCreationTask
+
+
+```csharp
+public class Products_ByLocalizedDescription : AbstractIndexCreationTask
{
- public Attributes_ByName()
+ public Products_ByLocalizedDescription()
{
- Map = products => from a in products
+ Map = products => from product in products
select new
{
- // Define the dynamic-index-fields by calling CreateField
- // A dynamic-index-field will be generated for each item in the Attributes list
-
- // For each item, the field name will be the value of field 'PropName'
- // The field terms will be derived from field 'PropValue'
- _ = a.Attributes.Select(item => CreateField(item.PropName, item.PropValue)),
-
- // A regular index field can be defined as well:
- Name = a.Name
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
};
+
+ StoreAllFields(FieldStorage.No);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ Analyze(Constants.Documents.Indexing.Fields.AllFields, "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`public class Attributes_ByName_JS : AbstractJavaScriptIndexCreationTask
+
+```csharp
+public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
{
- public Attributes_ByName_JS()
+ public Products_ByLocalizedDescription_JS()
{
Maps = new HashSet
{
- @"map('Products', function (p) {
+ @"map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
};
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No,
+ Analyzer = "StopAnalyzer"
+ };
}
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents matching a specific attribute property use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Width' is a dynamic-index-field that was indexed from the Attributes list
- .WhereEquals("Width", 10)
- .ToList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+
+The following applies when a `search()` query targets a **dynamic field**:
+
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `AllFields` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `AllFields` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `Analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `Analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+
-## CreateField syntax
+
+
+
#### Syntax for LINQ-index:
-
-
-{`object CreateField(string name, object value);
+
+```csharp
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
#### Syntax for JavaScript-index:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
| Parameters | Type | Description |
|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -540,11 +930,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
+
+
+
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

+
+
\ No newline at end of file
diff --git a/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-java.mdx b/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-java.mdx
index 17f3cbe360..d54ef6bea8 100644
--- a/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-java.mdx
+++ b/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-java.mdx
@@ -2,479 +2,918 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
+
-* Any value type can be indexed, string, number, date, etc.
+
+
+### Example - index every field under an object
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
+
-* In this page:
+* **The document**:
+
+
+ ```java
+ public class Product {
+ private String id;
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+ // The KEYS under the attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ private Map attributes;
-
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "color": "Red",
+ "size": 42
+ }
+ }
+ ```
+
-## Indexing documents fields KEYS
+* **The index**:
+
+ The following index will index any field under the `attributes` object from the document,
+ a dynamic-index-field will be created for each such field.
+ New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `color` & `size` will become the actual dynamic-index-fields.
+
+
+
+ ```java
+ public class Products_ByAttributeKey extends AbstractIndexCreationTask {
+ public Products_ByAttributeKey() {
+
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'.
+
+ // The actual field name will be 'item.Key'
+ // The actual field terms will be derived from 'item.Value'
+ map = "docs.Products.Select(p => new { " +
+ " _ = p.attributes.Select(item => " +
+ " this.CreateField(item.Key, item.Value)) " +
+ "})";
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByAttributeKey_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ " _: Object.keys(p.attributes) " +
+ " .map(key => createField(key, p.attributes[key])) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
-## Example - index any field under object
+* **The query**:
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _size_ use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByAttributeKey.class)
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ .whereEquals("size", 42)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey' where size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _DocumentQuery_ or _RQL_ because the field names (e.g. `size`, `color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `whereEquals("size", 42)` or RQL `where size = 42` instead.
+
-
+
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field
+
+The following example allows you to:
+ * Define an index on a collection **without** needing any common structure between the indexed documents.
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
+
+
+
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // The KEYS under the attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- private Dictionary attributes;
-
- // get + set implementation ...
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "attributes": \{
- "color": "Red",
- "size": 42
- \}
-\}
-`}
-
-
+
+
+ ```java
+ public class Product {
+ private String id;
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ private String firstName;
+ private String lastName;
+ private String title;
+ // ...
+
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer"
+ // ...
+ }
+ ```
+
* **The index**:
- The following index will index any field under the `attributes` object from the document,
- a dynamic-index-field will be created for each such field.
- New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The following index will index any field from the document,
+ a dynamic-index-field will be created for each field.
+ New fields added to the document after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+ The example uses an `AbstractJavaScriptIndexCreationTask` because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a map or collection.
+
+
+
+ ```java
+ public class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByAnyField_JS() {
+
+ // This will index EVERY FIELD under the top level of the document
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ " _: Object.keys(p).map(key => createField(key, p[key])) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- e.g. Keys `color` & `size` will become the actual dynamic-index-fields.
+* **The query**:
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByAnyField_JS.class)
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ .whereEquals("lastName", "Doe")
+ .toList();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
-
-
-
-{`public class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
- public Products_ByAttributeKey_JS() {
- // Call 'createField' to generate dynamic-index-fields from the attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
+
- // The actual field name will be the key
- // The actual field terms will be derived from p.attributes[key]
- setMaps(Sets.newHashSet(
- "map('Products', function (p) { " +
- " return { " +
- " _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], " +
- " { indexing: 'Search', storage: false, termVector: null })) " +
- " }; " +
- "}) "
- ));
- }
-}
-`}
-
-
-
+
+
+### Example - basic
-* **The query**:
- * You can now query the generated dynamic-index fields.
- Property `_` is Not queryable, it is only used in the index definition syntax.
- * To get all documents with some 'size' use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByAttributeKey_JS.class)
- .whereEquals("size", 42)
- .toList();
-`}
-
-
-
-
-{`// 'size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey/JS' where size = 42
-`}
-
-
-
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-## Example - index any field
+* **The document**:
+
+
+ ```java
+ public class Product {
+ private String id;
-
+ // The VALUE of productType will be dynamically indexed
+ private String productType;
+ private int pricePerUnit;
-* Define an index on a collection **without** needing any common structure between the indexed documents.
-* After index is deployed, any new field added to the document will be indexed as well.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
-
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```java
+ public class Products_ByProductType extends AbstractIndexCreationTask {
+ public Products_ByProductType() {
+
+ // Call 'CreateField' to generate the dynamic-index-field.
+ // The field name will be the value of document field 'productType'.
+ // The field terms will be derived from document field 'pricePerUnit'.
+ map = "docs.Products.Select(p => new { " +
+ " _ = this.CreateField(p.productType, p.pricePerUnit) " +
+ "})";
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByProductType_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ " _: createField(p.productType, p.pricePerUnit) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
-
-Consider if that is a true necessity, as indexing every single field can end up costing time and disk space.
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByProductType.class)
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ .whereEquals("Electronics", 23)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- private String firstName;
- private String lastName;
- private String title;
- // ...
-
- // get + set implementation ...
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "firstName": "John",
- "lastName": "Doe",
- "title": "Engineer",
- // ...
-\}
-`}
-
-
+
+
+ ```java
+ public class Product {
+ private String id;
+ private String name;
+
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ private List attributes;
+
+ // getters and setters ...
+ }
-* **The index**:
- The following index will index any field from the document,
- a dynamic-index-field will be created for each field.
- New fields added to the document after index creation time will be dynamically indexed as well.
+ public class Attribute {
+ private String propName;
+ private String propValue;
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ }
+ // ...
+ ]
+ }
+ ```
+
-
-
-
-{`public class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
- public Products_ByAnyField_JS() {
+* **The index**:
- // This will index EVERY FIELD under the top level of the document
- setMaps(Sets.newHashSet(
- "map('Products', function (p) { " +
- " return { " +
- " _: Object.keys(p).map(key => createField(key, p[key], " +
- " { indexing: 'Search', storage: true, termVector: null })) " +
- " }; " +
- "}) "
- ));
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```java
+ public class Attributes_ByName extends AbstractIndexCreationTask {
+ public Attributes_ByName() {
+
+ // Define the dynamic-index-fields by calling 'CreateField'.
+ // A dynamic-index-field will be generated for each item in 'attributes'.
+
+ // For each item, the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'.
+ // A regular index field (Name) is defined as well.
+ map = "docs.Products.Select(p => new { " +
+ " _ = p.attributes.Select(item => " +
+ " this.CreateField(item.propName, item.propValue)), " +
+ " Name = p.name " +
+ "})";
+ }
}
-}
-`}
-
-
-
+ ```
+
+
+ ```java
+ public class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
+ public Attributes_ByName_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // For each item,
+ // the field name will be the value of field 'propName'.
+ // The field terms will be derived from field 'propValue'.
+ " _: p.attributes.map(item => " +
+ " createField(item.propName, item.propValue)), " +
+ // A regular index field can be defined as well:
+ " Name: p.name " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
* **The query**:
- * To get all documents with some 'lastName' use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByAnyField_JS.class)
- .whereEquals("lastName", "Doe")
- .toList();
-`}
-
-
-
-
-{`// 'lastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where lastName = "Doe"
-`}
-
-
-
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Attributes_ByName.class)
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ .whereEquals("Width", 10)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `indexing: 'Search'` in the `createField` options object (`AbstractJavaScriptIndexCreationTask`)
+or `FieldIndexing.Search` in the `CreateFieldOptions` (`AbstractIndexCreationTask`).
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
-## Indexing documents fields VALUES
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Example - basic
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
-
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
-* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // The VALUE of productType will be dynamically indexed
- private String productType;
- private int pricePerUnit;
-
- // get + set implementation ...
-\}
-`}
-
-
+
+ ```java
+ public class Product {
+ private String id;
-
-
-{`// Sample document content
-\{
- "productType": "Electronics",
- "pricePerUnit": 23
-\}
-`}
-
-
+ private Map descriptions;
-* **The index**:
- The following index will index the **value** of document field 'productType'.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` map.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```java
+ public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+
+ private static final String USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ // Index each generated dynamic field for FTS
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
+ "})";
+
+ storeAllFields(FieldStorage.NO);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ getConfiguration().put(USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS, "true");
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+
+ private static final String USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ // Index each generated dynamic field for FTS
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
+
+ Map fields = new HashMap<>();
+
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
+ setFields(fields);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ getConfiguration().put(USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS, "true");
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```java
+ List results = session.advanced()
+ .documentQuery(Product.class, Products_ByLocalizedDescription.class)
+ .search("Description_English", "north wind")
+ .toList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
- This value will be the dynamic-index-field name on which you can query.
- e.g. Field value `Electronics` will be the dynamic-index-field.
+---
-
-
-
-{`public class Products_ByProductType extends AbstractIndexCreationTask {
- public Products_ByProductType() {
+
+
+### Configuring analyzers for dynamic fields
+
+The `CreateFieldOptions` (and the JavaScript `createField` options) do **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- map = "docs.Products.Select(p => new { " +
- " _ = this.CreateField(p.productType, p.pricePerUnit) " +
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
+
+```java
+public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
"})";
+
+ storeAllFields(FieldStorage.NO);
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByProductType.class)
- .whereEquals("Electronics", 23)
- .toList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-## Example - list
+
+```java
+public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
-
+ Map fields = new HashMap<>();
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
-
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ IndexFieldOptions englishOptions = new IndexFieldOptions();
+ englishOptions.setAnalyzer("StopAnalyzer");
+ fields.put("Description_English", englishOptions);
-* **The document**:
-
-
-{`public class Product \{
- private String id;
- private String name;
-
- // For each element in this list, the VALUE of property 'propName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- private List attributes;
-
- // get + set implementation ...
-\}
-
-public class Attribute \{
- private String propName;
- private String propValue;
-
- // get + set implementation ...
-\}
-`}
-
+ setFields(fields);
+ }
+}
+```
+
-
-
-{`// Sample document content
-\{
-name": "SomeName",
-attributes": [
- \{
- "propName": "Color",
- "propValue": "Blue"
- \},
- \{
- "propName": "Width",
- "propValue": "10"
- \},
- \{
- "propName": "Length",
- "propValue": "20"
- \},
- ...
-
-\}
-`}
-
-
+#### Configure a fallback analyzer for all fields
+
+
+
+```java
+public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
+ "})";
-* **The index**:
- The following index will create a dynamic-index-field per item in the document's `attributes` list.
- New items added to the attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's propName **value**.
- E.g., 'propName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`public class Attributes_ByName extends AbstractIndexCreationTask {
- public Attributes_ByName() {
-
- // For each attribute item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- // A regular-index-field (Name) is defined as well
- map =
- "docs.Products.Select(p => new { " +
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " +
- " Name = p.name " +
- "})";
+ storeAllFields(FieldStorage.NO);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ analyze(Constants.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer");
}
}
-`}
-
+```
-
+
+```java
+public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
-* **The query**:
- * To get all documents matching a specific attribute property use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Attributes_ByName.class)
- .whereEquals("Width", 10)
- .toList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+ Map fields = new HashMap<>();
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+ allFieldsOptions.setAnalyzer("StopAnalyzer");
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
+
+ setFields(fields);
+ }
+}
+```
+
+
+
+
+### Which analyzer is used for the query term?
+The following applies when a `search()` query targets a **dynamic field**:
-## CreateField syntax
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-#### Syntax for LINQ-index:
+
-
-
-{`object CreateField(string name, object value);
+
+
+
+
+#### Syntax for `AbstractIndexCreationTask`
+
+
+```csharp
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
-#### Syntax for JavaScript-index:
+#### Syntax for `AbstractJavaScriptIndexCreationTask`
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|----------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
+| Parameters | Type | Description |
+|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+* The `CreateField` syntax (and the `CreateFieldOptions` shape) above describes what is available inside the server-side `map` string of an `AbstractIndexCreationTask`,
+ since the Java client sends the `map` source to the server for compilation.
+ The JavaScript `createField` function is the equivalent for `AbstractJavaScriptIndexCreationTask` map sources.
+
* All above examples have used the character `_` in the dynamic-index-field definition.
However, using `_` is just a convention. Any other string can be used instead.
* This property is Not queryable, it is only used in the index definition syntax.
- The actual dynamic-index-fields that are generated are defined by the `CreateField` method.
+ The actual dynamic-index-fields that are generated are defined by the `CreateField` method (or the `createField` JS function).
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-nodejs.mdx b/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-nodejs.mdx
index b5df2df4a7..c14184c2b5 100644
--- a/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-nodejs.mdx
+++ b/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-nodejs.mdx
@@ -2,533 +2,710 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`createField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
+
-
-#### Example - index any field under object
-The following allows you to:
-
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
-**The document**:
-
-
-{`class Product \{
- constructor(id, attributes) \{
- this.id = id;
-
- // The KEYS under the attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- this.attributes = attributes;
- \}
-\}
-`}
-
-
+
+
+### Example - index every field under an object
-
-
-{`// Sample document content
-\{
- "attributes": \{
- "color": "Red",
- "size": 42
- \}
-\}
-`}
-
-
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
+
-**The index**:
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, attributes) {
+ this.id = id;
+
+ // The KEYS under the attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ this.attributes = attributes;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "color": "Red",
+ "size": 42
+ }
+ }
+ ```
+
-* The following index will index any field under the `attributes` object from the document,
+* **The index**:
+
+ The following index will index any field under the `attributes` object from the document,
a dynamic-index-field will be created for each such field.
- New fields added to the object after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- e.g. Keys `color` & `size` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
- constructor() {
- super();
-
- const { createField } = this.mapUtils();
-
- this.map("Products", p => {
- return {
- // Call 'createField' to generate dynamic-index-fields from the attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
-
- // The actual field name will be the key
- // The actual field terms will be derived from p.attributes[key]
- _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], {
- indexing: "Search",
- storage: false,
- termVector: null
- }))
- };
- });
+ New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `color` & `size` will become the actual dynamic-index-fields.
+
+
+ ```js
+ class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // Call 'createField' to generate dynamic-index-fields
+ // from the attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'
+
+ // The actual field name will be the key
+ // The actual field terms will be derived from p.attributes[key]
+ _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key]))
+ };
+ });
+ }
}
-}
-`}
-
-
-
-
-**The query**:
-
-* You can now query the generated dynamic-index fields.
- Property `_` is Not queryable, it is only used in the index definition syntax.
-
-* To get all documents with some 'size' use:
-
-
-
-
-{`const matchingDocuments = session.query({indexName: 'Products_ByAttributeKey'})
- // 'size' is a dynamic-index-field that was indexed from the attributes object
- .whereEquals('size', 42)
- .all();
-`}
-
-
-
-
-{`// 'size' is a dynamic-index-field that was indexed from the attributes object
-from index 'Products/ByAttributeKey' where size = 42
-`}
-
-
-
-
-
+ ```
+
+
+* **The query**:
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _size_ use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByAttributeKey/JS" })
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ .whereEquals("size", 42)
+ .all();
+ ```
+
+
+ ```sql
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey/JS' where size = 42
+ ```
+
+
+
+
+
+
+
+### Example - index every field
-#### Example - index any field
-The following allows you to:
-
-* Define an index on a collection **without** needing any common structure between the indexed documents.
-* After index is deployed, any new field added to the document will be indexed as well.
-
+The following example allows you to:
+ * Define an index on a collection **without** needing any common structure between the indexed documents.
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
+
+
-
-Consider if that is a true necessity, as indexing every single field can end up costing time and disk space.
-
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
-**The document**:
-
-
-{`class Product \{
- constructor(id, firstName, lastName, title) \{
- this.id = id;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- this.firstName = firstName;
- this.lastName = lastName;
- this.title = title;
- // ...
- \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "firstName": "John",
- "lastName": "Doe",
- "title": "Engineer",
- // ...
-\}
-`}
-
-
-**The index**:
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, firstName, lastName, title) {
+ this.id = id;
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.title = title;
+ // ...
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer",
+ // ...
+ }
+ ```
+
-* The following index will index any field from the document,
+* **The index**:
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
- New fields added to the document after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the field **key**.
- e.g. Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+ New fields added to the document after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+
+ ```js
+ class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ // This will index EVERY FIELD under the top level of the document
+ this.map("Products", p => {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByAnyField/JS" })
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ .whereEquals("lastName", "Doe")
+ .all();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-
-
-
-{`class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
- super();
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, productType, pricePerUnit) {
+ this.id = id;
+
+ // The VALUE of productType will be dynamically indexed
+ this.productType = productType;
+ this.pricePerUnit = pricePerUnit;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+ ```js
+ class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ _: createField(p.productType, p.pricePerUnit)
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByProductType/JS" })
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ .whereEquals("Electronics", 23)
+ .all();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType/JS' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
- const { createField } = this.mapUtils();
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
+
- this.map("Products", p => {
- return {
- // This will index EVERY FIELD under the top level of the document
- _: Object.keys(p).map(key => createField(key, p[key], {
- indexing: "Search",
- storage: true,
- termVector: null
- }))
- };
- });
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, name, attributes) {
+ this.id = id;
+ this.name = name;
+
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ this.attributes = attributes;
+ }
}
-}
-`}
-
-
-
-**The query**:
+ class Attribute {
+ constructor(propName, propValue) {
+ this.propName = propName;
+ this.propValue = propValue;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ },
+ ...
+ ]
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+ ```js
+ class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // Define the dynamic-index-fields by calling 'createField'
+ // A dynamic-index-field will be generated for each item in 'attributes'
+
+ // For each item, the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'
+ _: p.attributes.map(item =>
+ createField(item.propName, item.propValue)),
+
+ // A regular index field can be defined as well:
+ name: p.name
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Attributes/ByName/JS" })
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ .whereEquals("Width", 10)
+ .all();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName/JS' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `indexing: "Search"` in the `createField` options.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
-* To get all documents with some 'lastName' use:
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, descriptions) {
+ this.id = id;
+ this.descriptions = descriptions;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+ ```js
+ class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ const useSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ this.map("Products", product => {
+ return {
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: "Search",
+ storage: false
+ }))
+ };
+ });
+
+ this.storeAllFields("No");
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ this.configuration[useSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Products_ByAnyField_JS' })
- // 'lastName' is a dynamic-index-field that was indexed from the document
- .whereEquals('lastName', 'Doe')
- .all();
-`}
-
-
-
-
-{`// 'lastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where lastName = "Doe"
-`}
-
-
-
+* **Full-text search query**:
-
+ Query the generated dynamic field by its field name.
+ In this example, the query targets the generated field `Description_English`.
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Indexing documents fields VALUES
+
+
+ ```js
+ const results = await session
+ .query({ indexName: "Products/ByLocalizedDescription/JS" })
+ .search("Description_English", "north wind")
+ .all();
+ ```
+
-
-#### Example - basic
-This example shows:
-
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
-**The document**:
-
-
-{`class Product \{
- constructor(id, productType, pricePerUnit) \{
- this.id = id;
-
- // The VALUE of productType will be dynamically indexed
- this.productType = productType;
- this.pricePerUnit = pricePerUnit;
- \}
-\}
-`}
-
-
+
+ ```sql
+ from index "Products/ByLocalizedDescription/JS"
+ where search(Description_English, "north wind")
+ ```
+
+
-
-
-{`// Sample document content
-\{
- "productType": "Electronics",
- "pricePerUnit": 23
-\}
-`}
-
-
+---
-**The index**:
+
+
+### Configuring analyzers for dynamic fields
-* The following index will index the **value** of document field 'productType'.
+The `createField` options object does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
-* This value will be the dynamic-index-field name on which you can query.
- e.g. Field value `Electronics` will be the dynamic-index-field.
+---
-
-
-
-{`class Products_ByProductType extends AbstractCsharpIndexCreationTask {
- constructor () {
- super();
+#### Configure analyzer for a specific dynamic field
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- this.map = "docs.Products.Select(p => new { " +
- " _ = this.CreateField(p.productType, p.pricePerUnit) " +
- "})";
- }
-}
-`}
-
-
-
-
-{`class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
+
+```js
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
super();
const { createField } = this.mapUtils();
- this.map("Products", p => {
+ this.map("Products", product => {
return {
- _: [
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- createField(p.productType, p.pricePerUnit, {
- indexing: "Search",
- storage: false,
- termVector: null
- })
- ]
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ indexing: "Search",
+ storage: false
+ }))
};
});
- }
-}
-`}
-
-
-
-
-**The query**:
-
-* To get all documents of some product type having a specific price per unit use:
-
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Products_ByProductType' })
- // 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
- .whereEquals('Electronics', 23)
- .all();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-
-
-#### Example - list
-The following allows you to:
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-**The document**:
-
-
-{`class Product \{
- constructor(id, name, attributes) \{
- this.id = id;
- this.name = name;
-
- // For each element in this list, the VALUE of property 'propName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- this.attributes = attributes;
- \}
-\}
-
-class Attribute \{
- constructor(propName, propValue) \{
- this.propName = propName;
- this.propValue = propValue;
- \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "name": "SomeName",
- "attributes": [
- \{
- "propName": "Color",
- "propValue": "Blue"
- \},
- \{
- "propName": "Width",
- "propValue": "10"
- \},
- \{
- "propName": "Length",
- "propValue": "20"
- \},
- ...
- ]
-\}
-`}
-
-
-
-**The index**:
-
-* The following index will create a dynamic-index-field per item in the document's `attributes` list.
- New items added to the attributes list after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the item's propName **value**.
- e.g. 'propName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`class Attributes_ByName extends AbstractCsharpIndexCreationTask
-{
- constructor () {
- super();
+ this.storeAllFields("No");
- // For each attribute item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- // A regular-index-field (Name) is defined as well
- this.map =
- "docs.Products.Select(p => new { " +
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " +
- " Name = p.name " +
- "})";
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ this.analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
+
+#### Configure a fallback analyzer for all fields
+
+
+```js
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
super();
const { createField } = this.mapUtils();
- this.map("Products", p => {
+ this.map("Products", product => {
return {
- // For each item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- _: p.attributes.map(item => createField(item.propName, item.propValue, {
- indexing: "Search",
- storage: true,
- termVector: null
- })),
-
- // A regular-index-field can be defined as well:
- Name: p.name
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ indexing: "Search",
+ storage: false
+ }))
};
});
- }
-}
-`}
-
-
-
-
-**The query**:
-* To get all documents matching a specific attribute property use:
+ this.storeAllFields("No");
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Attributes/ByName' })
- // 'Width' is a dynamic-index-field that was indexed from the attributes list
- .whereEquals('Width', 10)
- .all();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ this.analyze(CONSTANTS.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer");
+ }
+}
+```
-
-
-
+
+
+
+
+### Which analyzer is used for the query term?
-## CreateField syntax
+The following applies when a `search()` query targets a **dynamic field**:
-#### Syntax for LINQ-index:
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `this.analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `this.analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-
-
-{`object CreateField(string name, object value);
+
-object CreateField(string name, object value, bool stored, bool analyzed);
+
-object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
-
+
-#### Syntax for JavaScript-index:
+#### Syntax:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|----------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+| Parameters | Type | Description |
+|----------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **options** | `object` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
-| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| options object | | |
+|-----------------|--------------------|-----------------------------------------------------------------------------------|
+| **storage** | `boolean` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
+| **indexing** | `FieldIndexing` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **termVector** | `FieldTermVector` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -536,21 +713,19 @@ object CreateField(string name, object value, CreateFieldOptions options);
However, using `_` is just a convention. Any other string can be used instead.
* This property is Not queryable, it is only used in the index definition syntax.
- The actual dynamic-index-fields that are generated are defined by the `CreateField` method.
+ The actual dynamic-index-fields that are generated are defined by the `createField` method.
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-php.mdx b/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-php.mdx
index 09c58cc9fc..6992310715 100644
--- a/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-php.mdx
+++ b/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-php.mdx
@@ -2,537 +2,969 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
+
-* In this page:
+
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
-## Indexing documents fields KEYS
-
-## Example - index any field under object
+* **The document**:
+
+
+ ```php
+ use Ds\Map as DSMap;
-
+ class Product
+ {
+ public ?string $id = null;
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+ // The KEYS under the attributes object will be dynamically indexed.
+ // Fields added to this object after index creation time will also get indexed.
+ public ?DSMap $attributes = null;
-
-
-* **The document**:
-
-
-{`use Ds\\Map as DSMap;
-
-class Product
-\{
- private ?string $id = null;
-
- // The KEYS under the Attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- public ?DSMap $attributes = null;
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-{`class Products_ByAttributeKey extends AbstractIndexCreationTask
-{
- public function __construct()
+
+
+ ```php
+ class Products_ByAttributeKey extends AbstractIndexCreationTask
{
- parent::__construct();
-
- $this->map = "from p in docs.Products select new {" .
- "_ = p.attributes.Select(item => CreateField(item.Key, item.Value))" .
- "}";
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the attributes object keys.
+ //
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'.
+ //
+ // The actual field name will be 'item.Key'.
+ // The actual field terms will be derived from 'item.Value'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = p.attributes.Select(item => CreateField(item.Key, item.Value)) " .
+ "}";
+ }
}
-}
-`}
-
-
-
-
-{`class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask
-{
- public function __construct()
+ ```
+
+
+ ```php
+ class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask
{
- parent::__construct();
-
- $this->setMaps([
- "map('Products', function (p) { " .
- " return { " .
- " _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], " .
- " { indexing: 'Search', storage: false, termVector: null })) " .
- " }; " .
- "}) "
- ]);
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.attributes)
+ .map(key => createField(key, p.attributes[key], null))
+ };
+ })"
+ ]);
+ }
}
-}
-`}
-
-
-
-
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- * To get all documents with some 'size' use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByAttributeKey::class)
- // 'Size' is a dynamic-index-field that was indexed from the Attributes object
- ->whereEquals("Size", 42)
- ->toList();
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
-
-## Example - index any field
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByAttributeKey::class)
+ // 'Size' is a dynamic-index-field that was indexed from the attributes object
+ ->whereEquals("Size", 42)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _documentQuery_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `whereEquals("Size", 42)` or RQL `where Size = 42` instead.
+
+
+
+
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`class Product
-\{
- private ?string $id = null;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- public ?string $firstName = null;
- public ?string $lastName = null;
- public ?string $title = null;
-
- // ... getters and setters
-\}
-`}
-
-
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
-
-
-{`// Sample document content
- \{
- "FirstName": "John",
- "LastName": "Doe",
- "Title": "Engineer",
+ // All KEYS in the document will be dynamically indexed.
+ // Fields added to the document after index creation time will also get indexed.
+ public ?string $firstName = null;
+ public ?string $lastName = null;
+ public ?string $title = null;
// ...
-\}
-`}
-
-
+
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer"
+ // ...
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask
-{
- public function __construct()
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
+
+
+
+ ```php
+ class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask
{
- parent::__construct();
-
- // This will index EVERY FIELD under the top level of the document
- $this->setMaps([
- "map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })"
- ]);
+ public function __construct()
+ {
+ parent::__construct();
+
+ // This will index EVERY FIELD under the top level of the document
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key], null))
+ };
+ })"
+ ]);
+ }
}
-}
-`}
-
-
-
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByAnyField_JS::class)
- // 'LastName' is a dynamic-index-field that was indexed from the document
- ->whereEquals("LastName", "Doe")
- ->toList();
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByAnyField_JS::class)
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ ->whereEquals("lastName", "Doe")
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
+* **The document**:
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
+ // The VALUE of productType will be dynamically indexed
+ public ?string $productType = null;
+ public ?int $pricePerUnit = null;
-## Indexing documents fields VALUES
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
-## Example - basic
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
-
+
+
+ ```php
+ class Products_ByProductType extends AbstractIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Call 'CreateField' to generate the dynamic-index-fields.
+ // The field name will be the value of document field 'productType'.
+ // The field terms will be derived from document field 'pricePerUnit'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = CreateField(p.productType, p.pricePerUnit) " .
+ "}";
+ }
+ }
+ ```
+
+
+ ```php
+ class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ _: createField(p.productType, p.pricePerUnit, null)
+ };
+ })"
+ ]);
+ }
+ }
+ ```
+
+
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByProductType::class)
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ ->whereEquals("Electronics", 23)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`class Product
-\{
- public ?string $id = null;
-
- // The VALUE of ProductType will be dynamically indexed
- public ?string $productType = null;
- public ?int $pricePerUnit = null;
-
- // ... getters and setters
-\}
-`}
-
-
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
+ public ?string $name = null;
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ public ?AttributeList $attributes = null;
+
+ // ... getters and setters
+ }
+
+ class Attribute
+ {
+ public ?string $propName = null;
+ public ?string $propValue = null;
+
+ // ... getters and setters
+ }
+
+ class AttributeList extends TypedList
+ {
+ protected function __construct()
+ {
+ parent::__construct(Attribute::class);
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ }
+ // ...
+ ]
+ }
+ ```
+
* **The index**:
- The below index will index the **value** of document field 'ProductType'.
+
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```php
+ class Attributes_ByName extends AbstractIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Define the dynamic-index-fields by calling 'CreateField'.
+ // A dynamic-index-field will be generated for each item in 'attributes'.
+ //
+ // For each item, the field name will be the value of field 'propName'.
+ // The field terms will be derived from field 'propValue'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = p.attributes.Select(item => CreateField(item.propName, item.propValue)), " .
+ " Name = p.name " .
+ "}";
+ }
+ }
+ ```
+
+
+ ```php
+ class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'
+ _: p.attributes.map(item => createField(
+ item.propName, item.propValue, null)),
+
+ // A regular index field can be defined as well:
+ Name: p.name
+ };
+ })"
+ ]);
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Attributes_ByName::class)
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ ->whereEquals("Width", 10)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing::search()` in `CreateFieldOptions`.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```php
+ use Ds\Map as DSMap;
+
+ class Product
+ {
+ public ?string $id = null;
+ public ?DSMap $descriptions = null;
+
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
-
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```php
+ class Products_ByLocalizedDescription extends AbstractIndexCreationTask
+ {
+ private const USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ // Index each generated dynamic field for FTS
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
+
+ $this->storeAllFields(FieldStorage::no());
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ $this->getConfiguration()[self::USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS] = "true";
+ }
+ }
+ ```
+
+
+ ```php
+ class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ private const USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (product) {
+ return {
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })"
+ ]);
+
+ // Apply a storage default to every generated field
+ $fields = new IndexFieldOptionsArray();
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
+ $this->setFields($fields);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ $this->getConfiguration()[self::USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS] = "true";
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```php
+ /** @var array $results */
+ $results = $session->advanced()
+ ->documentQuery(Product::class, Products_ByLocalizedDescription::class)
+ ->search("Description_English", "north wind")
+ ->toList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
+
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
-
-{`class Products_ByProductType extends AbstractIndexCreationTask
+```php
+class Products_ByLocalizedDescription extends AbstractIndexCreationTask
{
public function __construct()
{
parent::__construct();
- // Call 'CreateField' to generate the dynamic-index-fields
- // The field name will be the value of document field 'ProductType'
- // The field terms will be derived from document field 'PricePerUnit'
- $this->map = "docs.Products.Select(p => new { " .
- " _ = this.CreateField(p.productType, p.pricePerUnit) " .
- "})";
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
+
+ $this->storeAllFields(FieldStorage::no());
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ $this->analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask
+
+```php
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
{
public function __construct()
{
parent::__construct();
$this->setMaps([
- "map('Products', function (p) {
+ "map('Products', function (product) {
return {
- _: createField(p.ProductType, p.PricePerUnit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
]);
- }
-}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByProductType::class)
-// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-->whereEquals("Electronics", 23)
-->toList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-## Example - list
-
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
+ // Apply a storage default to every generated field +
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ $fields = new IndexFieldOptionsArray();
-
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
-* **The document**:
-
-
-{`class Product
-\{
- public ?string $id = null;
- public ?string $name = null;
-
- // For each element in this list, the VALUE of property 'PropName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- public ?AttributeList $attributes = null;
-
- // ... getters and setters
-\}
-
-class Attribute
-\{
- public ?string $propName = null;
- public ?string $propValue = null;
-
- // ... getters and setters
-\}
-
-class AttributeList extends TypedList
-\{
- protected function __construct()
- \{
- parent::__construct(Attribute::class);
- \}
-\}
-`}
-
-
+ $englishFieldOptions = new IndexFieldOptions();
+ $englishFieldOptions->setAnalyzer("StopAnalyzer");
+ $fields->offsetSet("Description_English", $englishFieldOptions);
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
+ $this->setFields($fields);
+ }
+}
+```
+
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `width` will be a dynamic-index-field.
+#### Configure a fallback analyzer for all fields
-
+
-
-{`class Attributes_ByName extends AbstractIndexCreationTask
+```php
+class Products_ByLocalizedDescription extends AbstractIndexCreationTask
{
public function __construct()
{
parent::__construct();
- // Define the dynamic-index-fields by calling CreateField
- // A dynamic-index-field will be generated for each item in the Attributes list
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
- // For each item, the field name will be the value of field 'PropName'
- // The field terms will be derived from field 'PropValue'
+ $this->storeAllFields(FieldStorage::no());
- $this->map =
- "docs.Products.Select(p => new { " .
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " .
- " Name = p.name " .
- "})";
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ $this->analyze(DocumentsIndexingFields::ALL_FIELDS, "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask
+
+```php
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
{
public function __construct()
{
parent::__construct();
$this->setMaps([
- "map('Products', function (p) {
+ "map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
]);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ $fields = new IndexFieldOptionsArray();
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $allFieldsOptions->setAnalyzer("StopAnalyzer");
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
+ $this->setFields($fields);
}
}
-`}
-
-
-
-
-* **The query**:
- To get all documents matching a specific attribute property use:
-
-
-
-{`/** @var array $matchingDocuments */
-$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Attributes_ByName::class)
- // 'Width' is a dynamic-index-field that was indexed from the Attributes list
- ->whereEquals("Width", 10)
- ->toList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+The following applies when a `search()` query targets a **dynamic field**:
-## CreateField syntax
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `$this->analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `$this->analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-
-
-{`object CreateField(string name, object value);
+
+
+
+
+
+
+#### Syntax for LINQ-index:
+
+
+```php
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
-| Parameters | Type | Description |
-|------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **name** | `string` | Name of the dynamic-index-field |
-| **value** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`False` - will set `FieldStorage.NO` (default value)
`True` - will set `FieldStorate.YES` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`None` - `FieldIndexing.Default` (default value)
`False` - `FieldIndexing.Exact`
`True` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+#### Syntax for JavaScript-index:
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
-| **Storage** | `FieldStorage` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing` | |
-| **TermVector** | `FieldTermVector` | |
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
+
+
+| Parameters | Type | Description |
+|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage::no()` (default value)
`true` - will set `FieldStorage::yes()` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing::default()` (default value)
`false` - `FieldIndexing::exact()`
`true` - `FieldIndexing::search()` |
+| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
+| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -544,17 +976,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-python.mdx b/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-python.mdx
index 69514a29e2..6862d18067 100644
--- a/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-python.mdx
+++ b/versioned_docs/version-6.2/indexes/content/_using-dynamic-fields-python.mdx
@@ -1,490 +1,886 @@
import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
-import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
-
-## Example - index any field under object
+
-
-
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, attributes: Dict[str, object] = None):
- self.Id = Id
-
- # The KEYS under the Attributes object will be dynamically indexed
- # Fields added to this object after index creation time will also get indexed
- self.attributes = attributes
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, Attributes: Dict[str, object] = None):
+ self.Id = Id
+
+ # The KEYS under the Attributes object will be dynamically indexed
+ # Fields added to this object after index creation time will also get indexed
+ self.Attributes = Attributes
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `Attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAttributeKey(AbstractIndexCreationTask):
- def __init__(self):
- super().__init__()
- self.map = (
- "from p in docs.Products select new {"
- "_ = p.attributes.Select(item => CreateField(item.Key, item.Value))"
- "}"
- )
-`}
-
-
-
-
-{`class Products_ByAttributeKey_JS(AbstractJavaScriptIndexCreationTask):
- def __init__(self):
- super().__init__()
- self.maps = {
- """
- map('Products', function (p) {
- return {
- _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key],
- { indexing: 'Search', storage: true, termVector: null }))
- };
- })
- """
- }
-`}
-
-
-
-
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+
+
+
+ ```python
+ class Products_ByAttributeKey(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from p in docs.Products select new { "
+ # Call 'CreateField' to generate dynamic-index-fields
+ # from the Attributes object keys.
+
+ # Using '_' is just a convention.
+ # Any other string can be used instead of '_'
+
+ # The actual field name will be 'item.Key'
+ # The actual field terms will be derived from 'item.Value'
+ "_ = p.Attributes.Select(item => CreateField(item.Key, item.Value)) "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Products_ByAttributeKey_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.Attributes)
+ .map(key => createField(key, p.Attributes[key]))
+ };
+ })
+ """
+ ]
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- * To get all documents with some 'size' use:
-
-
-
-{`matching_documents = list(
- session.query_index_type(Products_ByAttributeKey, Product)
- # 'size' is a dynamic-index-field that was indexed from the attributes object
- .where_equals("size", 42)
-)
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
-
-## Example - index any field
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByAttributeKey, Product)
+ # 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ .where_equals("Size", 42)
+ )
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _document_query_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `where_equals("Size", 42)` or RQL `where Size = 42`.
+
+
+
+
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, first_name: str = None, last_name: str = None, title: str = None):
- self.Id = Id
-
- # All KEYS in the document will be dynamically indexes
- # Fields added to the document after index creation time wil also get indexed
- self.first_name = first_name
- self.last_name = last_name
- self.title = title
- # ...
-`}
-
-
-
-
-
-{`// Sample document content
- \{
+
+
+ ```python
+ class Product:
+ def __init__(
+ self,
+ Id: str = None,
+ FirstName: str = None,
+ LastName: str = None,
+ Title: str = None,
+ ):
+ self.Id = Id
+
+ # All KEYS in the document will be dynamically indexed
+ # Fields added to the document after index creation time will also get indexed
+ self.FirstName = FirstName
+ self.LastName = LastName
+ self.Title = Title
+ # ...
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
"FirstName": "John",
"LastName": "Doe",
"Title": "Engineer",
// ...
-\}
-`}
-
-
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAnyField_JS(AbstractJavaScriptIndexCreationTask):
- def __init__(self):
- super().__init__()
- # This will index EVERY FIELD under the top level of the document
- self.maps = {
- """
- map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })
- """
- }
-`}
-
-
-
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
+
+
+
+ ```python
+ class Products_ByAnyField_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ # This will index EVERY FIELD under the top level of the document
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ })
+ """
+ ]
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`# 'last_name' is a dynamic-index-field that was indexed from the document
-matching_documents = list(
- session.query_index_type(Products_ByAnyField_JS, Product).where_equals("last_name", "Doe")
-)
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _LastName_ use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByAnyField_JS, Product)
+ # 'LastName' is a dynamic-index-field that was indexed from the document
+ .where_equals("LastName", "Doe")
+ )
+ ```
+
+
+ ```sql
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where LastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
+
+* **The document**:
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, ProductType: str = None, PricePerUnit: int = None):
+ self.Id = Id
+
+ # The VALUE of ProductType will be dynamically indexed
+ self.ProductType = ProductType
+ self.PricePerUnit = PricePerUnit
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "ProductType": "Electronics",
+ "PricePerUnit": 23
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will index the **value** of document field 'ProductType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```python
+ class Products_ByProductType(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from p in docs.Products select new { "
+ # Call 'CreateField' to generate the dynamic-index-fields
+ # The field name will be the value of document field 'ProductType'
+ # The field terms will be derived from document field 'PricePerUnit'
+ "_ = CreateField(p.ProductType, p.PricePerUnit) "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Products_ByProductType_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _: createField(p.ProductType, p.PricePerUnit)
+ };
+ })
+ """
+ ]
+ ```
+
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByProductType, Product)
+ # 'Electronics' is the dynamic-index-field that was indexed
+ # from document field 'ProductType'
+ .where_equals("Electronics", 23)
+ )
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
+
+
+* **The document**:
+
+
+ ```python
+ class Attribute:
+ def __init__(self, PropName: str = None, PropValue: str = None):
+ self.PropName = PropName
+ self.PropValue = PropValue
+
+
+ class Product:
+ def __init__(self, Id: str = None, Name: str = None, Attributes: List[Attribute] = None):
+ self.Id = Id
+ self.Name = Name
+
+ # For each element in this list,
+ # the VALUE of property 'PropName' will be dynamically indexed.
+ # e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ self.Attributes = Attributes
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Name": "SomeName",
+ "Attributes": [
+ {
+ "PropName": "Color",
+ "PropValue": "Blue"
+ },
+ {
+ "PropName": "Width",
+ "PropValue": "10"
+ },
+ {
+ "PropName": "Length",
+ "PropValue": "20"
+ },
+ // ...
+ ]
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will create a dynamic-index-field per item in the document's `Attributes` list.
+ New items added to the Attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
+ E.g., 'PropName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```python
+ class Attributes_ByName(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from a in docs.Products select new { "
+ # Define the dynamic-index-fields by calling 'CreateField'
+ # A dynamic-index-field will be generated for each item in 'Attributes'
+
+ # For each item, the field name will be the value of field 'PropName'
+ # The field terms will be derived from field 'PropValue'
+ "_ = a.Attributes.Select(item => CreateField(item.PropName, item.PropValue)), "
+
+ # A regular index field can be defined as well:
+ "Name = a.Name "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Attributes_ByName_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _: p.Attributes.map(item => createField(item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name: p.Name
+ };
+ })
+ """
+ ]
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Attributes_ByName, Product)
+ # 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ .where_equals("Width", 10)
+ )
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing.Search` in `CreateFieldOptions`.
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Indexing documents fields VALUES
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
-## Example - basic
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
-
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, Descriptions: Dict[str, str] = None):
+ self.Id = Id
+ self.Descriptions = Descriptions
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
-* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, product_type: str = None, price_per_unit: float = None):
- self.Id = Id
-
- # The VALUE of ProductType will be dynamically indexed
- self.product_type = product_type
- self.price_per_unit = price_per_unit
-`}
-
-
+* **The index**:
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+ The following index creates one dynamic field for each entry in the `Descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
-* **The index**:
- The below index will index the **value** of document field 'ProductType'.
-
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```python
+ class Products_ByLocalizedDescription(AbstractIndexCreationTask):
+ USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS = (
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery"
+ )
+
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ # Index each generated dynamic field for FTS
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
+ "}"
+ )
+
+ self._store_all_fields(FieldStorage.NO)
+
+ # Set this configuration key to true so that search() queries on dynamic fields
+ # will use the 'Default Search Analyzer' when the generated field name
+ # has no explicit analyzer configuration.
+ self.configuration = {
+ Products_ByLocalizedDescription.USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS: "true"
+ }
+ ```
+
+
+ ```python
+ class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
+ USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS = (
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery"
+ )
+
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (product) {
+ return {
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })
+ """
+ ]
+
+ # Apply a storage default to every generated field
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO)
+ }
+
+ # Set this configuration key to true so that search() queries on dynamic fields
+ # will use the 'Default Search Analyzer' when the generated field name
+ # has no explicit analyzer configuration.
+ self.configuration = {
+ Products_ByLocalizedDescription_JS.USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS: "true"
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```python
+ results = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByLocalizedDescription, Product)
+ .search("Description_English", "north wind")
+ )
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
+
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
-
-{`class Products_ByProductType(AbstractIndexCreationTask):
+```python
+class Products_ByLocalizedDescription(AbstractIndexCreationTask):
def __init__(self):
super().__init__()
+ self.map = (
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
+ "}"
+ )
- # Call 'CreateField' to generate the dynamic-index-fields
- # The field name will be the value of document field 'product_type'
- # The field terms will be derived from document field 'price_per_unit'
- self.map = "from p in docs.Products select new { _ = CreateField(p.product_type, p.price_per_unit)}"
-`}
-
+ self._store_all_fields(FieldStorage.NO)
+
+ # Configure an analyzer for a known generated dynamic field name
+ # ==============================================================
+ self._analyze("Description_English", "StopAnalyzer")
+```
-
-
-{`class Products_ByProductType_JS(AbstractJavaScriptIndexCreationTask):
+
+```python
+class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
def __init__(self):
super().__init__()
- self.maps = {
+ self.maps = [
"""
- map('Products', function (p) {
+ map('Products', function (product) {
return {
- _: createField(p.product_type, p.price_per_unit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})
"""
+ ]
+
+ # Configure an analyzer for a known generated dynamic field name
+ # ==============================================================
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO),
+ "Description_English":
+ IndexFieldOptions(analyzer="StopAnalyzer")
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`# 'electronics' is the dynamic-index-field that was indexed from the document 'product_type'
-matching_documents = list(
- session.advanced.document_query_from_index_type(Products_ByProductType, Product).where_equals(
- "electronics", 23
- )
-)
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
+```
-## Example - list
-
-
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-
-
-
-* **The document**:
-
-
-{`class Attribute:
- def __init__(self, prop_name: str = None, prop_value: str = None):
- self.prop_name = prop_name
- self.prop_value = prop_value
-
-
-class Product:
- def __init__(self, Id: str = None, name: str = None, attributes: List[Attribute] = None):
- self.Id = Id
- self.name = name
- # For each element in this list, the VALUE of property 'prop_name' will be dynamically indexed
- # e.g. color, width, length (in ex. below) will become dynamic-index-field
- self.attributes = attributes
-`}
-
-
-
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
-
-
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `width` will be a dynamic-index-field.
+#### Configure a fallback analyzer for all fields
-
-{`class Attributes_ByName(AbstractIndexCreationTask):
+```python
+class Products_ByLocalizedDescription(AbstractIndexCreationTask):
def __init__(self):
super().__init__()
self.map = (
- "from a in docs.Products select new "
- "{ _ = a.attributes.Select( item => CreateField(item.prop_name, item.prop_value)), name = a.name "
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
"}"
)
-`}
-
+
+ self._store_all_fields(FieldStorage.NO)
+
+ # Use this as a fallback for fields that do not have
+ # their own explicit analyzer configuration
+ # ==================================================
+ self._analyze(constants.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer")
+```
-
-
-{`class Attributes_ByName_JS(AbstractJavaScriptIndexCreationTask):
+
+```python
+class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
def __init__(self):
super().__init__()
- self.maps = {
+ self.maps = [
"""
- map('Products', function (p) {
+ map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})
"""
+ ]
+
+ # Use this as a fallback for fields that do not have
+ # their own explicit analyzer configuration
+ # ==================================================
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO, analyzer="StopAnalyzer")
}
-`}
-
-
-
-
-* **The query**:
- To get all documents matching a specific attribute property use:
-
-
-
-{`matching_documents = list(
- session.advanced.document_query_from_index_type(Attributes_ByName, Product).where_equals(
- "width", 10
- )
-)
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+
+The following applies when a `search()` query targets a **dynamic field**:
+
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `self._analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `self._analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+
+
+
-## CreateField syntax
+
#### Syntax for Index:
-
-
-{`object CreateField(string name, object value);
+
+```python
+CreateField(name, value)
-object CreateField(string name, object value, bool stored, bool analyzed);
+CreateField(name, value, stored, analyzed)
-object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+CreateField(name, value, CreateFieldOptions)
+```
#### Syntax for JavaScript-index:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **name** | `string` | Name of the dynamic-index-field |
-| **value** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`False` - will set `FieldStorage.NO` (default value)
`True` - will set `FieldStorate.YES` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`None` - `FieldIndexing.Default` (default value)
`False` - `FieldIndexing.Exact`
`True` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+| Parameters | Type | Description |
+|----------------|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
+| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -496,17 +892,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).


-
-
-
-
+
+
diff --git a/versioned_docs/version-6.2/indexes/querying/content/_searching-csharp.mdx b/versioned_docs/version-6.2/indexes/querying/content/_searching-csharp.mdx
index d20ef5a65e..f0be0e6ffd 100644
--- a/versioned_docs/version-6.2/indexes/querying/content/_searching-csharp.mdx
+++ b/versioned_docs/version-6.2/indexes/querying/content/_searching-csharp.mdx
@@ -16,11 +16,13 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
* [Searching with wildcards](../../../indexes/querying/searching.mdx#searching-with-wildcards)
* [When using RavenStandardAnalyzer or StandardAnalyzer or NGramAnalyzer](../../../indexes/querying/searching.mdx#when-usingoror)
@@ -28,6 +30,7 @@ import CodeBlock from '@theme/CodeBlock';
* [When using the Exact analyzer](../../../indexes/querying/searching.mdx#when-using-the-exact-analyzer)
+
## Indexing single field for FTS
#### The index:
@@ -262,7 +265,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly,
+* To search across ALL fields in a document without defining each one explicitly,
use the `AsJson` method in the _Map_ function to extract all property values and index them in a single searchable field.
* This approach makes the index robust to changes in the document schema.
@@ -377,7 +380,14 @@ where search(AllValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/versioned_docs/version-6.2/indexes/querying/content/_searching-java.mdx b/versioned_docs/version-6.2/indexes/querying/content/_searching-java.mdx
index 7d85246ced..4accf3f512 100644
--- a/versioned_docs/version-6.2/indexes/querying/content/_searching-java.mdx
+++ b/versioned_docs/version-6.2/indexes/querying/content/_searching-java.mdx
@@ -388,4 +388,11 @@ where search(allValues, "tofu")
+## Indexing dynamic fields for FTS
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
\ No newline at end of file
diff --git a/versioned_docs/version-6.2/indexes/querying/content/_searching-nodejs.mdx b/versioned_docs/version-6.2/indexes/querying/content/_searching-nodejs.mdx
index 4ca66b5877..cb73bfd7c0 100644
--- a/versioned_docs/version-6.2/indexes/querying/content/_searching-nodejs.mdx
+++ b/versioned_docs/version-6.2/indexes/querying/content/_searching-nodejs.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,11 +17,13 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
* [Searching with wildcards](../../../indexes/querying/searching.mdx#searching-with-wildcards)
* [When using RavenStandardAnalyzer or StandardAnalyzer or NGramAnalyzer](../../../indexes/querying/searching.mdx#when-usingoror)
@@ -29,6 +31,7 @@ import CodeBlock from '@theme/CodeBlock';
* [When using the Exact analyzer](../../../indexes/querying/searching.mdx#when-using-the-exact-analyzer)
+
## Indexing single field for FTS
#### The index:
@@ -163,7 +166,7 @@ where (search(employeeData, "Manager") or search(employeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available when using **a C# LINQ string** that is assigned to the `map` property in the Node.js index class,
as shown in the example below.
@@ -229,6 +232,14 @@ where search(AllValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/versioned_docs/version-6.2/indexes/querying/content/_searching-php.mdx b/versioned_docs/version-6.2/indexes/querying/content/_searching-php.mdx
index 55261ce19f..510a6f8752 100644
--- a/versioned_docs/version-6.2/indexes/querying/content/_searching-php.mdx
+++ b/versioned_docs/version-6.2/indexes/querying/content/_searching-php.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,14 +17,17 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
+
## Indexing single field for FTS
#### The index:
@@ -253,7 +256,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available in the **C# LINQ string** that is assigned to the `map` property in the PHP index class,
as shown in the example below.
@@ -332,6 +335,15 @@ where search(allValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
+
## Boosting search results
diff --git a/versioned_docs/version-6.2/indexes/querying/content/_searching-python.mdx b/versioned_docs/version-6.2/indexes/querying/content/_searching-python.mdx
index f06c29d94f..88c6aa452f 100644
--- a/versioned_docs/version-6.2/indexes/querying/content/_searching-python.mdx
+++ b/versioned_docs/version-6.2/indexes/querying/content/_searching-python.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,14 +17,17 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
+
## Indexing single field for FTS
#### The index:
@@ -167,7 +170,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available in the **C# LINQ string** that is assigned to the `map` property in the Python index class,
as shown in the example below.
@@ -238,6 +241,14 @@ where search(all_values, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/versioned_docs/version-6.2/indexes/using-dynamic-fields.mdx b/versioned_docs/version-6.2/indexes/using-dynamic-fields.mdx
index e9ffb33a07..e465ba5431 100644
--- a/versioned_docs/version-6.2/indexes/using-dynamic-fields.mdx
+++ b/versioned_docs/version-6.2/indexes/using-dynamic-fields.mdx
@@ -1,7 +1,8 @@
---
-title: "Indexes: Dynamic Index Fields"
-sidebar_label: Dynamic Fields
-sidebar_position: 28
+title: "Dynamic Index Fields"
+sidebar_label: "Dynamic Index Fields"
+description: "Index document fields dynamically in RavenDB when field names are unknown at index definition time, using the CreateField method."
+sidebar_position: 27
supported_languages: ["csharp", "java", "python", "php", "nodejs"]
see_also:
- title: "Boosting"
@@ -31,7 +32,6 @@ import UsingDynamicFieldsPython from './content/_using-dynamic-fields-python.mdx
import UsingDynamicFieldsPhp from './content/_using-dynamic-fields-php.mdx';
import UsingDynamicFieldsNodejs from './content/_using-dynamic-fields-nodejs.mdx';
-
diff --git a/versioned_docs/version-6.2/server/configuration/indexing-configuration.mdx b/versioned_docs/version-6.2/server/configuration/indexing-configuration.mdx
index fe64090eb5..e845bf3326 100644
--- a/versioned_docs/version-6.2/server/configuration/indexing-configuration.mdx
+++ b/versioned_docs/version-6.2/server/configuration/indexing-configuration.mdx
@@ -95,6 +95,7 @@ import LanguageContent from "@site/src/components/LanguageContent";
[Indexing.OrderByTicksAutomaticallyWhenDatesAreInvolved](../../server/configuration/indexing-configuration.mdx#indexingorderbyticksautomaticallywhendatesareinvolved)
[Indexing.QueryClauseCache.Disabled](../../server/configuration/indexing-configuration.mdx#indexingqueryclausecachedisabled)
[Indexing.QueryClauseCache.RepeatedQueriesTimeFrameInSec](../../server/configuration/indexing-configuration.mdx#indexingqueryclausecacherepeatedqueriestimeframeinsec)
+ [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
[Indexing.ScratchSpaceLimitInMb](../../server/configuration/indexing-configuration.mdx#indexingscratchspacelimitinmb)
[Indexing.Static.SearchEngineType](../../server/configuration/indexing-configuration.mdx#indexingstaticsearchenginetype)
[Indexing.Throttling.TimeIntervalInMs](../../server/configuration/indexing-configuration.mdx#indexingthrottlingtimeintervalinms)
@@ -893,6 +894,33 @@ Queries that repeat within this time frame will be considered worth caching.
+## Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery
+
+* This setting controls which analyzer is used for the **query term** when a **`search()` query** targets a [Dynamic index field](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ that was indexed for full-text search, and no analyzer is explicitly configured for that field in the index definition.
+
+ * `false` (default):
+ The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) is used to analyze the **query term**.
+ This analyzer can be configured via the [Indexing.Analyzers.Default](../../server/configuration/indexing-configuration.mdx#indexinganalyzersdefault) configuration key.
+
+ * `true`:
+ The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) is used to analyze the **query term**.
+ This analyzer can be configured via the [Indexing.Analyzers.Search.Default](../../server/configuration/indexing-configuration.mdx#indexinganalyzerssearchdefault) configuration key.
+
+* See the table in [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ for the complete analyzer-selection rules based on this configuration key and the analyzer configured for the dynamic index field.
+
+* This configuration applies to both the Lucene and Corax search engines.
+ The default is `false` to preserve backward compatibility.
+
+---
+
+- **Type**: `bool`
+- **Default**: `false`
+- **Scope**: Server-wide, or per database, or per index
+
+
+
## Indexing.ScratchSpaceLimitInMb
* Amount of scratch space in megabytes that we allow to use for the index storage.
diff --git a/versioned_docs/version-7.0/indexes/assets/dynamic-index-fields-1.png b/versioned_docs/version-7.0/indexes/assets/dynamic-index-fields-1.png
index b13d9076f8..a20adda0ec 100644
Binary files a/versioned_docs/version-7.0/indexes/assets/dynamic-index-fields-1.png and b/versioned_docs/version-7.0/indexes/assets/dynamic-index-fields-1.png differ
diff --git a/versioned_docs/version-7.0/indexes/assets/dynamic-index-fields-2.png b/versioned_docs/version-7.0/indexes/assets/dynamic-index-fields-2.png
index dd2b4082ea..c5b1bc14bc 100644
Binary files a/versioned_docs/version-7.0/indexes/assets/dynamic-index-fields-2.png and b/versioned_docs/version-7.0/indexes/assets/dynamic-index-fields-2.png differ
diff --git a/versioned_docs/version-7.0/indexes/content/_using-analyzers-csharp.mdx b/versioned_docs/version-7.0/indexes/content/_using-analyzers-csharp.mdx
index 6022cfd145..2e824fea4b 100644
--- a/versioned_docs/version-7.0/indexes/content/_using-analyzers-csharp.mdx
+++ b/versioned_docs/version-7.0/indexes/content/_using-analyzers-csharp.mdx
@@ -24,7 +24,7 @@ import CodeBlock from '@theme/CodeBlock';
* [Understanding the role of analyzers](../../indexes/using-analyzers.mdx#understanding-the-role-of-analyzers)
* [Analyzers available in RavenDB](../../indexes/using-analyzers.mdx#analyzers-available-in-ravendb)
* [Setting analyzer for index-field](../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field)
- * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendb)
+ * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendbs-default-analyzers)
* [Disabling indexing for index-field](../../indexes/using-analyzers.mdx#disabling-indexing-for-index-field)
* [Creating custom analyzers](../../indexes/using-analyzers.mdx#creating-custom-analyzers)
* [Viewing the indexed terms](../../indexes/using-analyzers.mdx#viewing-the-indexed-terms)
diff --git a/versioned_docs/version-7.0/indexes/content/_using-analyzers-nodejs.mdx b/versioned_docs/version-7.0/indexes/content/_using-analyzers-nodejs.mdx
index 6afd3b6202..fae2cdd2b9 100644
--- a/versioned_docs/version-7.0/indexes/content/_using-analyzers-nodejs.mdx
+++ b/versioned_docs/version-7.0/indexes/content/_using-analyzers-nodejs.mdx
@@ -24,7 +24,7 @@ import CodeBlock from '@theme/CodeBlock';
* [Understanding the role of analyzers](../../indexes/using-analyzers.mdx#understanding-the-role-of-analyzers)
* [Analyzers available in RavenDB](../../indexes/using-analyzers.mdx#analyzers-available-in-ravendb)
* [Setting analyzer for index-field](../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field)
- * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendb)
+ * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendbs-default-analyzers)
* [Disabling indexing for index-field](../../indexes/using-analyzers.mdx#disabling-indexing-for-index-field)
* [Creating custom analyzers](../../indexes/using-analyzers.mdx#creating-custom-analyzers)
* [Viewing the indexed terms](../../indexes/using-analyzers.mdx#viewing-the-indexed-terms)
diff --git a/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-csharp.mdx b/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-csharp.mdx
index b4c4f518df..5bf052d482 100644
--- a/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-csharp.mdx
+++ b/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-csharp.mdx
@@ -2,533 +2,923 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
-
-## Example - index any field under object
-
-
+
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // The KEYS under the Attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- public Dictionary Attributes \{ get; set; \}
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // The KEYS under the Attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ public Dictionary Attributes { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `Attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-{`public class Products_ByAttributeKey : AbstractIndexCreationTask
-{
- public Products_ByAttributeKey()
+
+
+ ```csharp
+ public class Products_ByAttributeKey : AbstractIndexCreationTask
{
- Map = products => from p in products
- select new
- {
- // Call 'CreateField' to generate dynamic-index-fields from the Attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
-
- // The actual field name will be item.Key
- // The actual field terms will be derived from item.Value
- _ = p.Attributes.Select(item => CreateField(item.Key, item.Value))
- };
+ public Products_ByAttributeKey()
+ {
+ Map = products => from p in products
+ select new
+ {
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the Attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'
+
+ // The actual field name will be 'item.Key'
+ // The actual field terms will be derived from 'item.Value'
+ _ = p.Attributes.Select(item => CreateField(item.Key, item.Value))
+ };
+ }
}
-}
-`}
-
-
-
-
-{`public class Products_ByAttributeKey_JS : AbstractJavaScriptIndexCreationTask
-{
- public Products_ByAttributeKey_JS()
+ ```
+
+
+ ```csharp
+ public class Products_ByAttributeKey_JS : AbstractJavaScriptIndexCreationTask
{
- Maps = new HashSet
+ public Products_ByAttributeKey_JS()
{
- @"map('Products', function (p) {
- return {
- _: Object.keys(p.Attributes).map(key => createField(key, p.Attributes[key],
- { indexing: 'Search', storage: true, termVector: null }))
- };
- })"
- };
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.Attributes)
+ .map(key => createField(key, p.Attributes[key]))
+ };
+ })"
+ };
+ }
}
-}
-`}
-
-
-
-
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- The `_` property is Not queryable but used only in the index definition syntax.
- * To get all documents with some 'Size' use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Size' is a dynamic-index-field that was indexed from the Attributes object
- .WhereEquals("Size", 42)
- .ToList();
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ .WhereEquals("Size", 42)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _DocumentQuery_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ A strongly typed LINQ query such as `Query().Where(p => p.Size == 42)` would not compile.
+ Use the string-based `WhereEquals("Size", 42)` or RQL `where Size = 42` instead.
+
-## Example - index any field
+
-
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- public string FirstName \{ get; set; \}
- public string LastName \{ get; set; \}
- public string Title \{ get; set; \}
- // ...
-\}
-`}
-
-
-
-
-
-{`// Sample document content
- \{
- "FirstName": "John",
- "LastName": "Doe",
- "Title": "Engineer",
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ public string FirstName { get; set; }
+ public string LastName { get; set; }
+ public string Title { get; set; }
// ...
-\}
-`}
-
-
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "FirstName": "John",
+ "LastName": "Doe",
+ "Title": "Engineer",
+ // ...
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
-
-
-
-{`public class Products_ByAnyField_JS : AbstractJavaScriptIndexCreationTask
-{
- public Products_ByAnyField_JS()
+
+
+ ```csharp
+ public class Products_ByAnyField_JS : AbstractJavaScriptIndexCreationTask
{
- // This will index EVERY FIELD under the top level of the document
- Maps = new HashSet
+ public Products_ByAnyField_JS()
{
- @"map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })"
- };
+ // This will index EVERY FIELD under the top level of the document
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ })"
+ };
+ }
}
-}
-`}
-
-
-
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'LastName' is a dynamic-index-field that was indexed from the document
- .WhereEquals("LastName", "Doe")
- .ToList();
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _LastName_ use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ .WhereEquals("LastName", "Doe")
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where LastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+### Example - basic
-## Indexing documents fields VALUES
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-## Example - basic
+* **The document**:
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // The VALUE of ProductType will be dynamically indexed
+ public string ProductType { get; set; }
+ public int PricePerUnit { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "ProductType": "Electronics",
+ "PricePerUnit": 23
+ }
+ ```
+
-
+* **The index**:
+
+ The following index will index the **value** of document field 'ProductType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```csharp
+ public class Products_ByProductType : AbstractIndexCreationTask
+ {
+ public Products_ByProductType()
+ {
+ Map = products => from p in products
+ select new
+ {
+ // Call 'CreateField' to generate the dynamic-index-fields
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _ = CreateField(p.ProductType, p.PricePerUnit)
+ };
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Products_ByProductType_JS : AbstractJavaScriptIndexCreationTask
+ {
+ public Products_ByProductType_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _: createField(p.ProductType, p.PricePerUnit)
+ };
+ })"
+ };
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ .WhereEquals("Electronics", 23)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
+### Example - list
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // The VALUE of ProductType will be dynamically indexed
- public string ProductType \{ get; set; \}
- public int PricePerUnit \{ get; set; \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+ public string Name { get; set; }
+
+ // For each element in this list,
+ // the VALUE of property 'PropName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ public List Attributes { get; set; }
+ }
+
+ public class Attribute
+ {
+ public string PropName { get; set; }
+ public string PropValue { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Name": "SomeName",
+ "Attributes": [
+ {
+ "PropName": "Color",
+ "PropValue": "Blue"
+ },
+ {
+ "PropName": "Width",
+ "PropValue": "10"
+ },
+ {
+ "PropName": "Length",
+ "PropValue": "20"
+ },
+ ...
+ ]
+ }
+ ```
+
* **The index**:
- The below index will index the **value** of document field 'ProductType'.
+
+ The following index will create a dynamic-index-field per item in the document's `Attributes` list.
+ New items added to the Attributes list after index creation time will be dynamically indexed as well.
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
+ E.g., 'PropName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```csharp
+ public class Attributes_ByName : AbstractIndexCreationTask
+ {
+ public Attributes_ByName()
+ {
+ Map = products => from a in products
+ select new
+ {
+ // Define the dynamic-index-fields by calling 'CreateField'
+ // A dynamic-index-field will be generated for each item in 'Attributes'
+
+ // For each item, the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _ = a.Attributes.Select(item =>
+ CreateField(item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name = a.Name
+ };
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Attributes_ByName_JS : AbstractJavaScriptIndexCreationTask
+ {
+ public Attributes_ByName_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _: p.Attributes.map(item => createField(
+ item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name: p.Name
+ };
+ })"
+ };
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ .WhereEquals("Width", 10)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing.Search` in `CreateFieldOptions`.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `AllFields` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `AllFields` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ public Dictionary Descriptions { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `Descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```csharp
+ public class Products_ByLocalizedDescription : AbstractIndexCreationTask
+ {
+ private const string UseSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription()
+ {
+ Map = products => from product in products
+ select new
+ {
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ // Index each generated dynamic field for FTS
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
+ };
+
+ StoreAllFields(FieldStorage.No);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ Configuration[UseSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
+ {
+ private const string UseSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (product) {
+ return {
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })"
+ };
+
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No
+ };
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ Configuration[UseSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```csharp
+ List results = session.Advanced
+ .DocumentQuery()
+ .Search("Description_English", "north wind")
+ .ToList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
-
-
-
-{`public class Products_ByProductType : AbstractIndexCreationTask
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `AllFields` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `AllFields` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
+
+```csharp
+public class Products_ByLocalizedDescription : AbstractIndexCreationTask
{
- public Products_ByProductType()
+ public Products_ByLocalizedDescription()
{
- Map = products => from p in products
+ Map = products => from product in products
select new
{
- // Call 'CreateField' to generate the dynamic-index-fields
- // The field name will be the value of document field 'ProductType'
- // The field terms will be derived from document field 'PricePerUnit'
- _ = CreateField(p.ProductType, p.PricePerUnit)
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
};
+
+ StoreAllFields(FieldStorage.No);
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ Analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`public class Products_ByProductType_JS : AbstractJavaScriptIndexCreationTask
+
+```csharp
+public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
{
- public Products_ByProductType_JS()
+ public Products_ByLocalizedDescription_JS()
{
Maps = new HashSet
{
- @"map('Products', function (p) {
+ @"map('Products', function (product) {
return {
- _: createField(p.ProductType, p.PricePerUnit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
};
+
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No
+ };
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ Fields["Description_English"] = new IndexFieldOptions
+ {
+ Analyzer = "StopAnalyzer"
+ };
}
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
- .WhereEquals("Electronics", 23)
- .ToList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
+```
-## Example - list
-
-
+#### Configure a fallback analyzer for all fields
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-
-
-
-* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
- public string Name \{ get; set; \}
-
- // For each element in this list, the VALUE of property 'PropName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- public List Attributes \{ get; set; \}
-\}
-
-public class Attribute
-\{
- public string PropName \{ get; set; \}
- public string PropValue \{ get; set; \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
-
-
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`public class Attributes_ByName : AbstractIndexCreationTask
+
+
+```csharp
+public class Products_ByLocalizedDescription : AbstractIndexCreationTask
{
- public Attributes_ByName()
+ public Products_ByLocalizedDescription()
{
- Map = products => from a in products
+ Map = products => from product in products
select new
{
- // Define the dynamic-index-fields by calling CreateField
- // A dynamic-index-field will be generated for each item in the Attributes list
-
- // For each item, the field name will be the value of field 'PropName'
- // The field terms will be derived from field 'PropValue'
- _ = a.Attributes.Select(item => CreateField(item.PropName, item.PropValue)),
-
- // A regular index field can be defined as well:
- Name = a.Name
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
};
+
+ StoreAllFields(FieldStorage.No);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ Analyze(Constants.Documents.Indexing.Fields.AllFields, "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`public class Attributes_ByName_JS : AbstractJavaScriptIndexCreationTask
+
+```csharp
+public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
{
- public Attributes_ByName_JS()
+ public Products_ByLocalizedDescription_JS()
{
Maps = new HashSet
{
- @"map('Products', function (p) {
+ @"map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
};
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No,
+ Analyzer = "StopAnalyzer"
+ };
}
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents matching a specific attribute property use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Width' is a dynamic-index-field that was indexed from the Attributes list
- .WhereEquals("Width", 10)
- .ToList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+
+The following applies when a `search()` query targets a **dynamic field**:
+
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `AllFields` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `AllFields` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `Analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `Analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+
-## CreateField syntax
+
+
+
#### Syntax for LINQ-index:
-
-
-{`object CreateField(string name, object value);
+
+```csharp
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
#### Syntax for JavaScript-index:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
| Parameters | Type | Description |
|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -540,11 +930,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
+
+
+
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

+
+
\ No newline at end of file
diff --git a/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-java.mdx b/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-java.mdx
index 17f3cbe360..d54ef6bea8 100644
--- a/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-java.mdx
+++ b/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-java.mdx
@@ -2,479 +2,918 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
+
-* Any value type can be indexed, string, number, date, etc.
+
+
+### Example - index every field under an object
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
+
-* In this page:
+* **The document**:
+
+
+ ```java
+ public class Product {
+ private String id;
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+ // The KEYS under the attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ private Map attributes;
-
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "color": "Red",
+ "size": 42
+ }
+ }
+ ```
+
-## Indexing documents fields KEYS
+* **The index**:
+
+ The following index will index any field under the `attributes` object from the document,
+ a dynamic-index-field will be created for each such field.
+ New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `color` & `size` will become the actual dynamic-index-fields.
+
+
+
+ ```java
+ public class Products_ByAttributeKey extends AbstractIndexCreationTask {
+ public Products_ByAttributeKey() {
+
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'.
+
+ // The actual field name will be 'item.Key'
+ // The actual field terms will be derived from 'item.Value'
+ map = "docs.Products.Select(p => new { " +
+ " _ = p.attributes.Select(item => " +
+ " this.CreateField(item.Key, item.Value)) " +
+ "})";
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByAttributeKey_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ " _: Object.keys(p.attributes) " +
+ " .map(key => createField(key, p.attributes[key])) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
-## Example - index any field under object
+* **The query**:
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _size_ use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByAttributeKey.class)
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ .whereEquals("size", 42)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey' where size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _DocumentQuery_ or _RQL_ because the field names (e.g. `size`, `color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `whereEquals("size", 42)` or RQL `where size = 42` instead.
+
-
+
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field
+
+The following example allows you to:
+ * Define an index on a collection **without** needing any common structure between the indexed documents.
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
+
+
+
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // The KEYS under the attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- private Dictionary attributes;
-
- // get + set implementation ...
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "attributes": \{
- "color": "Red",
- "size": 42
- \}
-\}
-`}
-
-
+
+
+ ```java
+ public class Product {
+ private String id;
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ private String firstName;
+ private String lastName;
+ private String title;
+ // ...
+
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer"
+ // ...
+ }
+ ```
+
* **The index**:
- The following index will index any field under the `attributes` object from the document,
- a dynamic-index-field will be created for each such field.
- New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The following index will index any field from the document,
+ a dynamic-index-field will be created for each field.
+ New fields added to the document after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+ The example uses an `AbstractJavaScriptIndexCreationTask` because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a map or collection.
+
+
+
+ ```java
+ public class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByAnyField_JS() {
+
+ // This will index EVERY FIELD under the top level of the document
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ " _: Object.keys(p).map(key => createField(key, p[key])) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- e.g. Keys `color` & `size` will become the actual dynamic-index-fields.
+* **The query**:
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByAnyField_JS.class)
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ .whereEquals("lastName", "Doe")
+ .toList();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
-
-
-
-{`public class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
- public Products_ByAttributeKey_JS() {
- // Call 'createField' to generate dynamic-index-fields from the attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
+
- // The actual field name will be the key
- // The actual field terms will be derived from p.attributes[key]
- setMaps(Sets.newHashSet(
- "map('Products', function (p) { " +
- " return { " +
- " _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], " +
- " { indexing: 'Search', storage: false, termVector: null })) " +
- " }; " +
- "}) "
- ));
- }
-}
-`}
-
-
-
+
+
+### Example - basic
-* **The query**:
- * You can now query the generated dynamic-index fields.
- Property `_` is Not queryable, it is only used in the index definition syntax.
- * To get all documents with some 'size' use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByAttributeKey_JS.class)
- .whereEquals("size", 42)
- .toList();
-`}
-
-
-
-
-{`// 'size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey/JS' where size = 42
-`}
-
-
-
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-## Example - index any field
+* **The document**:
+
+
+ ```java
+ public class Product {
+ private String id;
-
+ // The VALUE of productType will be dynamically indexed
+ private String productType;
+ private int pricePerUnit;
-* Define an index on a collection **without** needing any common structure between the indexed documents.
-* After index is deployed, any new field added to the document will be indexed as well.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
-
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```java
+ public class Products_ByProductType extends AbstractIndexCreationTask {
+ public Products_ByProductType() {
+
+ // Call 'CreateField' to generate the dynamic-index-field.
+ // The field name will be the value of document field 'productType'.
+ // The field terms will be derived from document field 'pricePerUnit'.
+ map = "docs.Products.Select(p => new { " +
+ " _ = this.CreateField(p.productType, p.pricePerUnit) " +
+ "})";
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByProductType_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ " _: createField(p.productType, p.pricePerUnit) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
-
-Consider if that is a true necessity, as indexing every single field can end up costing time and disk space.
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByProductType.class)
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ .whereEquals("Electronics", 23)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- private String firstName;
- private String lastName;
- private String title;
- // ...
-
- // get + set implementation ...
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "firstName": "John",
- "lastName": "Doe",
- "title": "Engineer",
- // ...
-\}
-`}
-
-
+
+
+ ```java
+ public class Product {
+ private String id;
+ private String name;
+
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ private List attributes;
+
+ // getters and setters ...
+ }
-* **The index**:
- The following index will index any field from the document,
- a dynamic-index-field will be created for each field.
- New fields added to the document after index creation time will be dynamically indexed as well.
+ public class Attribute {
+ private String propName;
+ private String propValue;
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ }
+ // ...
+ ]
+ }
+ ```
+
-
-
-
-{`public class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
- public Products_ByAnyField_JS() {
+* **The index**:
- // This will index EVERY FIELD under the top level of the document
- setMaps(Sets.newHashSet(
- "map('Products', function (p) { " +
- " return { " +
- " _: Object.keys(p).map(key => createField(key, p[key], " +
- " { indexing: 'Search', storage: true, termVector: null })) " +
- " }; " +
- "}) "
- ));
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```java
+ public class Attributes_ByName extends AbstractIndexCreationTask {
+ public Attributes_ByName() {
+
+ // Define the dynamic-index-fields by calling 'CreateField'.
+ // A dynamic-index-field will be generated for each item in 'attributes'.
+
+ // For each item, the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'.
+ // A regular index field (Name) is defined as well.
+ map = "docs.Products.Select(p => new { " +
+ " _ = p.attributes.Select(item => " +
+ " this.CreateField(item.propName, item.propValue)), " +
+ " Name = p.name " +
+ "})";
+ }
}
-}
-`}
-
-
-
+ ```
+
+
+ ```java
+ public class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
+ public Attributes_ByName_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // For each item,
+ // the field name will be the value of field 'propName'.
+ // The field terms will be derived from field 'propValue'.
+ " _: p.attributes.map(item => " +
+ " createField(item.propName, item.propValue)), " +
+ // A regular index field can be defined as well:
+ " Name: p.name " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
* **The query**:
- * To get all documents with some 'lastName' use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByAnyField_JS.class)
- .whereEquals("lastName", "Doe")
- .toList();
-`}
-
-
-
-
-{`// 'lastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where lastName = "Doe"
-`}
-
-
-
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Attributes_ByName.class)
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ .whereEquals("Width", 10)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `indexing: 'Search'` in the `createField` options object (`AbstractJavaScriptIndexCreationTask`)
+or `FieldIndexing.Search` in the `CreateFieldOptions` (`AbstractIndexCreationTask`).
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
-## Indexing documents fields VALUES
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Example - basic
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
-
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
-* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // The VALUE of productType will be dynamically indexed
- private String productType;
- private int pricePerUnit;
-
- // get + set implementation ...
-\}
-`}
-
-
+
+ ```java
+ public class Product {
+ private String id;
-
-
-{`// Sample document content
-\{
- "productType": "Electronics",
- "pricePerUnit": 23
-\}
-`}
-
-
+ private Map descriptions;
-* **The index**:
- The following index will index the **value** of document field 'productType'.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` map.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```java
+ public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+
+ private static final String USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ // Index each generated dynamic field for FTS
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
+ "})";
+
+ storeAllFields(FieldStorage.NO);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ getConfiguration().put(USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS, "true");
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+
+ private static final String USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ // Index each generated dynamic field for FTS
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
+
+ Map fields = new HashMap<>();
+
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
+ setFields(fields);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ getConfiguration().put(USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS, "true");
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```java
+ List results = session.advanced()
+ .documentQuery(Product.class, Products_ByLocalizedDescription.class)
+ .search("Description_English", "north wind")
+ .toList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
- This value will be the dynamic-index-field name on which you can query.
- e.g. Field value `Electronics` will be the dynamic-index-field.
+---
-
-
-
-{`public class Products_ByProductType extends AbstractIndexCreationTask {
- public Products_ByProductType() {
+
+
+### Configuring analyzers for dynamic fields
+
+The `CreateFieldOptions` (and the JavaScript `createField` options) do **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- map = "docs.Products.Select(p => new { " +
- " _ = this.CreateField(p.productType, p.pricePerUnit) " +
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
+
+```java
+public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
"})";
+
+ storeAllFields(FieldStorage.NO);
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByProductType.class)
- .whereEquals("Electronics", 23)
- .toList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-## Example - list
+
+```java
+public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
-
+ Map fields = new HashMap<>();
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
-
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ IndexFieldOptions englishOptions = new IndexFieldOptions();
+ englishOptions.setAnalyzer("StopAnalyzer");
+ fields.put("Description_English", englishOptions);
-* **The document**:
-
-
-{`public class Product \{
- private String id;
- private String name;
-
- // For each element in this list, the VALUE of property 'propName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- private List attributes;
-
- // get + set implementation ...
-\}
-
-public class Attribute \{
- private String propName;
- private String propValue;
-
- // get + set implementation ...
-\}
-`}
-
+ setFields(fields);
+ }
+}
+```
+
-
-
-{`// Sample document content
-\{
-name": "SomeName",
-attributes": [
- \{
- "propName": "Color",
- "propValue": "Blue"
- \},
- \{
- "propName": "Width",
- "propValue": "10"
- \},
- \{
- "propName": "Length",
- "propValue": "20"
- \},
- ...
-
-\}
-`}
-
-
+#### Configure a fallback analyzer for all fields
+
+
+
+```java
+public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
+ "})";
-* **The index**:
- The following index will create a dynamic-index-field per item in the document's `attributes` list.
- New items added to the attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's propName **value**.
- E.g., 'propName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`public class Attributes_ByName extends AbstractIndexCreationTask {
- public Attributes_ByName() {
-
- // For each attribute item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- // A regular-index-field (Name) is defined as well
- map =
- "docs.Products.Select(p => new { " +
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " +
- " Name = p.name " +
- "})";
+ storeAllFields(FieldStorage.NO);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ analyze(Constants.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer");
}
}
-`}
-
+```
-
+
+```java
+public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
-* **The query**:
- * To get all documents matching a specific attribute property use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Attributes_ByName.class)
- .whereEquals("Width", 10)
- .toList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+ Map fields = new HashMap<>();
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+ allFieldsOptions.setAnalyzer("StopAnalyzer");
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
+
+ setFields(fields);
+ }
+}
+```
+
+
+
+
+### Which analyzer is used for the query term?
+The following applies when a `search()` query targets a **dynamic field**:
-## CreateField syntax
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-#### Syntax for LINQ-index:
+
-
-
-{`object CreateField(string name, object value);
+
+
+
+
+#### Syntax for `AbstractIndexCreationTask`
+
+
+```csharp
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
-#### Syntax for JavaScript-index:
+#### Syntax for `AbstractJavaScriptIndexCreationTask`
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|----------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
+| Parameters | Type | Description |
+|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+* The `CreateField` syntax (and the `CreateFieldOptions` shape) above describes what is available inside the server-side `map` string of an `AbstractIndexCreationTask`,
+ since the Java client sends the `map` source to the server for compilation.
+ The JavaScript `createField` function is the equivalent for `AbstractJavaScriptIndexCreationTask` map sources.
+
* All above examples have used the character `_` in the dynamic-index-field definition.
However, using `_` is just a convention. Any other string can be used instead.
* This property is Not queryable, it is only used in the index definition syntax.
- The actual dynamic-index-fields that are generated are defined by the `CreateField` method.
+ The actual dynamic-index-fields that are generated are defined by the `CreateField` method (or the `createField` JS function).
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-nodejs.mdx b/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-nodejs.mdx
index b5df2df4a7..c14184c2b5 100644
--- a/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-nodejs.mdx
+++ b/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-nodejs.mdx
@@ -2,533 +2,710 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`createField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
+
-
-#### Example - index any field under object
-The following allows you to:
-
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
-**The document**:
-
-
-{`class Product \{
- constructor(id, attributes) \{
- this.id = id;
-
- // The KEYS under the attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- this.attributes = attributes;
- \}
-\}
-`}
-
-
+
+
+### Example - index every field under an object
-
-
-{`// Sample document content
-\{
- "attributes": \{
- "color": "Red",
- "size": 42
- \}
-\}
-`}
-
-
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
+
-**The index**:
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, attributes) {
+ this.id = id;
+
+ // The KEYS under the attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ this.attributes = attributes;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "color": "Red",
+ "size": 42
+ }
+ }
+ ```
+
-* The following index will index any field under the `attributes` object from the document,
+* **The index**:
+
+ The following index will index any field under the `attributes` object from the document,
a dynamic-index-field will be created for each such field.
- New fields added to the object after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- e.g. Keys `color` & `size` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
- constructor() {
- super();
-
- const { createField } = this.mapUtils();
-
- this.map("Products", p => {
- return {
- // Call 'createField' to generate dynamic-index-fields from the attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
-
- // The actual field name will be the key
- // The actual field terms will be derived from p.attributes[key]
- _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], {
- indexing: "Search",
- storage: false,
- termVector: null
- }))
- };
- });
+ New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `color` & `size` will become the actual dynamic-index-fields.
+
+
+ ```js
+ class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // Call 'createField' to generate dynamic-index-fields
+ // from the attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'
+
+ // The actual field name will be the key
+ // The actual field terms will be derived from p.attributes[key]
+ _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key]))
+ };
+ });
+ }
}
-}
-`}
-
-
-
-
-**The query**:
-
-* You can now query the generated dynamic-index fields.
- Property `_` is Not queryable, it is only used in the index definition syntax.
-
-* To get all documents with some 'size' use:
-
-
-
-
-{`const matchingDocuments = session.query({indexName: 'Products_ByAttributeKey'})
- // 'size' is a dynamic-index-field that was indexed from the attributes object
- .whereEquals('size', 42)
- .all();
-`}
-
-
-
-
-{`// 'size' is a dynamic-index-field that was indexed from the attributes object
-from index 'Products/ByAttributeKey' where size = 42
-`}
-
-
-
-
-
+ ```
+
+
+* **The query**:
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _size_ use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByAttributeKey/JS" })
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ .whereEquals("size", 42)
+ .all();
+ ```
+
+
+ ```sql
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey/JS' where size = 42
+ ```
+
+
+
+
+
+
+
+### Example - index every field
-#### Example - index any field
-The following allows you to:
-
-* Define an index on a collection **without** needing any common structure between the indexed documents.
-* After index is deployed, any new field added to the document will be indexed as well.
-
+The following example allows you to:
+ * Define an index on a collection **without** needing any common structure between the indexed documents.
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
+
+
-
-Consider if that is a true necessity, as indexing every single field can end up costing time and disk space.
-
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
-**The document**:
-
-
-{`class Product \{
- constructor(id, firstName, lastName, title) \{
- this.id = id;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- this.firstName = firstName;
- this.lastName = lastName;
- this.title = title;
- // ...
- \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "firstName": "John",
- "lastName": "Doe",
- "title": "Engineer",
- // ...
-\}
-`}
-
-
-**The index**:
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, firstName, lastName, title) {
+ this.id = id;
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.title = title;
+ // ...
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer",
+ // ...
+ }
+ ```
+
-* The following index will index any field from the document,
+* **The index**:
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
- New fields added to the document after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the field **key**.
- e.g. Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+ New fields added to the document after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+
+ ```js
+ class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ // This will index EVERY FIELD under the top level of the document
+ this.map("Products", p => {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByAnyField/JS" })
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ .whereEquals("lastName", "Doe")
+ .all();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-
-
-
-{`class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
- super();
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, productType, pricePerUnit) {
+ this.id = id;
+
+ // The VALUE of productType will be dynamically indexed
+ this.productType = productType;
+ this.pricePerUnit = pricePerUnit;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+ ```js
+ class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ _: createField(p.productType, p.pricePerUnit)
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByProductType/JS" })
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ .whereEquals("Electronics", 23)
+ .all();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType/JS' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
- const { createField } = this.mapUtils();
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
+
- this.map("Products", p => {
- return {
- // This will index EVERY FIELD under the top level of the document
- _: Object.keys(p).map(key => createField(key, p[key], {
- indexing: "Search",
- storage: true,
- termVector: null
- }))
- };
- });
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, name, attributes) {
+ this.id = id;
+ this.name = name;
+
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ this.attributes = attributes;
+ }
}
-}
-`}
-
-
-
-**The query**:
+ class Attribute {
+ constructor(propName, propValue) {
+ this.propName = propName;
+ this.propValue = propValue;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ },
+ ...
+ ]
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+ ```js
+ class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // Define the dynamic-index-fields by calling 'createField'
+ // A dynamic-index-field will be generated for each item in 'attributes'
+
+ // For each item, the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'
+ _: p.attributes.map(item =>
+ createField(item.propName, item.propValue)),
+
+ // A regular index field can be defined as well:
+ name: p.name
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Attributes/ByName/JS" })
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ .whereEquals("Width", 10)
+ .all();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName/JS' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `indexing: "Search"` in the `createField` options.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
-* To get all documents with some 'lastName' use:
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, descriptions) {
+ this.id = id;
+ this.descriptions = descriptions;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+ ```js
+ class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ const useSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ this.map("Products", product => {
+ return {
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: "Search",
+ storage: false
+ }))
+ };
+ });
+
+ this.storeAllFields("No");
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ this.configuration[useSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Products_ByAnyField_JS' })
- // 'lastName' is a dynamic-index-field that was indexed from the document
- .whereEquals('lastName', 'Doe')
- .all();
-`}
-
-
-
-
-{`// 'lastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where lastName = "Doe"
-`}
-
-
-
+* **Full-text search query**:
-
+ Query the generated dynamic field by its field name.
+ In this example, the query targets the generated field `Description_English`.
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Indexing documents fields VALUES
+
+
+ ```js
+ const results = await session
+ .query({ indexName: "Products/ByLocalizedDescription/JS" })
+ .search("Description_English", "north wind")
+ .all();
+ ```
+
-
-#### Example - basic
-This example shows:
-
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
-**The document**:
-
-
-{`class Product \{
- constructor(id, productType, pricePerUnit) \{
- this.id = id;
-
- // The VALUE of productType will be dynamically indexed
- this.productType = productType;
- this.pricePerUnit = pricePerUnit;
- \}
-\}
-`}
-
-
+
+ ```sql
+ from index "Products/ByLocalizedDescription/JS"
+ where search(Description_English, "north wind")
+ ```
+
+
-
-
-{`// Sample document content
-\{
- "productType": "Electronics",
- "pricePerUnit": 23
-\}
-`}
-
-
+---
-**The index**:
+
+
+### Configuring analyzers for dynamic fields
-* The following index will index the **value** of document field 'productType'.
+The `createField` options object does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
-* This value will be the dynamic-index-field name on which you can query.
- e.g. Field value `Electronics` will be the dynamic-index-field.
+---
-
-
-
-{`class Products_ByProductType extends AbstractCsharpIndexCreationTask {
- constructor () {
- super();
+#### Configure analyzer for a specific dynamic field
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- this.map = "docs.Products.Select(p => new { " +
- " _ = this.CreateField(p.productType, p.pricePerUnit) " +
- "})";
- }
-}
-`}
-
-
-
-
-{`class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
+
+```js
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
super();
const { createField } = this.mapUtils();
- this.map("Products", p => {
+ this.map("Products", product => {
return {
- _: [
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- createField(p.productType, p.pricePerUnit, {
- indexing: "Search",
- storage: false,
- termVector: null
- })
- ]
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ indexing: "Search",
+ storage: false
+ }))
};
});
- }
-}
-`}
-
-
-
-
-**The query**:
-
-* To get all documents of some product type having a specific price per unit use:
-
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Products_ByProductType' })
- // 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
- .whereEquals('Electronics', 23)
- .all();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-
-
-#### Example - list
-The following allows you to:
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-**The document**:
-
-
-{`class Product \{
- constructor(id, name, attributes) \{
- this.id = id;
- this.name = name;
-
- // For each element in this list, the VALUE of property 'propName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- this.attributes = attributes;
- \}
-\}
-
-class Attribute \{
- constructor(propName, propValue) \{
- this.propName = propName;
- this.propValue = propValue;
- \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "name": "SomeName",
- "attributes": [
- \{
- "propName": "Color",
- "propValue": "Blue"
- \},
- \{
- "propName": "Width",
- "propValue": "10"
- \},
- \{
- "propName": "Length",
- "propValue": "20"
- \},
- ...
- ]
-\}
-`}
-
-
-
-**The index**:
-
-* The following index will create a dynamic-index-field per item in the document's `attributes` list.
- New items added to the attributes list after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the item's propName **value**.
- e.g. 'propName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`class Attributes_ByName extends AbstractCsharpIndexCreationTask
-{
- constructor () {
- super();
+ this.storeAllFields("No");
- // For each attribute item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- // A regular-index-field (Name) is defined as well
- this.map =
- "docs.Products.Select(p => new { " +
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " +
- " Name = p.name " +
- "})";
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ this.analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
+
+#### Configure a fallback analyzer for all fields
+
+
+```js
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
super();
const { createField } = this.mapUtils();
- this.map("Products", p => {
+ this.map("Products", product => {
return {
- // For each item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- _: p.attributes.map(item => createField(item.propName, item.propValue, {
- indexing: "Search",
- storage: true,
- termVector: null
- })),
-
- // A regular-index-field can be defined as well:
- Name: p.name
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ indexing: "Search",
+ storage: false
+ }))
};
});
- }
-}
-`}
-
-
-
-
-**The query**:
-* To get all documents matching a specific attribute property use:
+ this.storeAllFields("No");
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Attributes/ByName' })
- // 'Width' is a dynamic-index-field that was indexed from the attributes list
- .whereEquals('Width', 10)
- .all();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ this.analyze(CONSTANTS.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer");
+ }
+}
+```
-
-
-
+
+
+
+
+### Which analyzer is used for the query term?
-## CreateField syntax
+The following applies when a `search()` query targets a **dynamic field**:
-#### Syntax for LINQ-index:
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `this.analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `this.analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-
-
-{`object CreateField(string name, object value);
+
-object CreateField(string name, object value, bool stored, bool analyzed);
+
-object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
-
+
-#### Syntax for JavaScript-index:
+#### Syntax:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|----------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+| Parameters | Type | Description |
+|----------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **options** | `object` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
-| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| options object | | |
+|-----------------|--------------------|-----------------------------------------------------------------------------------|
+| **storage** | `boolean` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
+| **indexing** | `FieldIndexing` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **termVector** | `FieldTermVector` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -536,21 +713,19 @@ object CreateField(string name, object value, CreateFieldOptions options);
However, using `_` is just a convention. Any other string can be used instead.
* This property is Not queryable, it is only used in the index definition syntax.
- The actual dynamic-index-fields that are generated are defined by the `CreateField` method.
+ The actual dynamic-index-fields that are generated are defined by the `createField` method.
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-php.mdx b/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-php.mdx
index 09c58cc9fc..6992310715 100644
--- a/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-php.mdx
+++ b/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-php.mdx
@@ -2,537 +2,969 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
+
-* In this page:
+
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
-## Indexing documents fields KEYS
-
-## Example - index any field under object
+* **The document**:
+
+
+ ```php
+ use Ds\Map as DSMap;
-
+ class Product
+ {
+ public ?string $id = null;
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+ // The KEYS under the attributes object will be dynamically indexed.
+ // Fields added to this object after index creation time will also get indexed.
+ public ?DSMap $attributes = null;
-
-
-* **The document**:
-
-
-{`use Ds\\Map as DSMap;
-
-class Product
-\{
- private ?string $id = null;
-
- // The KEYS under the Attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- public ?DSMap $attributes = null;
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-{`class Products_ByAttributeKey extends AbstractIndexCreationTask
-{
- public function __construct()
+
+
+ ```php
+ class Products_ByAttributeKey extends AbstractIndexCreationTask
{
- parent::__construct();
-
- $this->map = "from p in docs.Products select new {" .
- "_ = p.attributes.Select(item => CreateField(item.Key, item.Value))" .
- "}";
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the attributes object keys.
+ //
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'.
+ //
+ // The actual field name will be 'item.Key'.
+ // The actual field terms will be derived from 'item.Value'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = p.attributes.Select(item => CreateField(item.Key, item.Value)) " .
+ "}";
+ }
}
-}
-`}
-
-
-
-
-{`class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask
-{
- public function __construct()
+ ```
+
+
+ ```php
+ class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask
{
- parent::__construct();
-
- $this->setMaps([
- "map('Products', function (p) { " .
- " return { " .
- " _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], " .
- " { indexing: 'Search', storage: false, termVector: null })) " .
- " }; " .
- "}) "
- ]);
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.attributes)
+ .map(key => createField(key, p.attributes[key], null))
+ };
+ })"
+ ]);
+ }
}
-}
-`}
-
-
-
-
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- * To get all documents with some 'size' use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByAttributeKey::class)
- // 'Size' is a dynamic-index-field that was indexed from the Attributes object
- ->whereEquals("Size", 42)
- ->toList();
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
-
-## Example - index any field
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByAttributeKey::class)
+ // 'Size' is a dynamic-index-field that was indexed from the attributes object
+ ->whereEquals("Size", 42)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _documentQuery_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `whereEquals("Size", 42)` or RQL `where Size = 42` instead.
+
+
+
+
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`class Product
-\{
- private ?string $id = null;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- public ?string $firstName = null;
- public ?string $lastName = null;
- public ?string $title = null;
-
- // ... getters and setters
-\}
-`}
-
-
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
-
-
-{`// Sample document content
- \{
- "FirstName": "John",
- "LastName": "Doe",
- "Title": "Engineer",
+ // All KEYS in the document will be dynamically indexed.
+ // Fields added to the document after index creation time will also get indexed.
+ public ?string $firstName = null;
+ public ?string $lastName = null;
+ public ?string $title = null;
// ...
-\}
-`}
-
-
+
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer"
+ // ...
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask
-{
- public function __construct()
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
+
+
+
+ ```php
+ class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask
{
- parent::__construct();
-
- // This will index EVERY FIELD under the top level of the document
- $this->setMaps([
- "map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })"
- ]);
+ public function __construct()
+ {
+ parent::__construct();
+
+ // This will index EVERY FIELD under the top level of the document
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key], null))
+ };
+ })"
+ ]);
+ }
}
-}
-`}
-
-
-
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByAnyField_JS::class)
- // 'LastName' is a dynamic-index-field that was indexed from the document
- ->whereEquals("LastName", "Doe")
- ->toList();
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByAnyField_JS::class)
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ ->whereEquals("lastName", "Doe")
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
+* **The document**:
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
+ // The VALUE of productType will be dynamically indexed
+ public ?string $productType = null;
+ public ?int $pricePerUnit = null;
-## Indexing documents fields VALUES
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
-## Example - basic
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
-
+
+
+ ```php
+ class Products_ByProductType extends AbstractIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Call 'CreateField' to generate the dynamic-index-fields.
+ // The field name will be the value of document field 'productType'.
+ // The field terms will be derived from document field 'pricePerUnit'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = CreateField(p.productType, p.pricePerUnit) " .
+ "}";
+ }
+ }
+ ```
+
+
+ ```php
+ class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ _: createField(p.productType, p.pricePerUnit, null)
+ };
+ })"
+ ]);
+ }
+ }
+ ```
+
+
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByProductType::class)
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ ->whereEquals("Electronics", 23)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`class Product
-\{
- public ?string $id = null;
-
- // The VALUE of ProductType will be dynamically indexed
- public ?string $productType = null;
- public ?int $pricePerUnit = null;
-
- // ... getters and setters
-\}
-`}
-
-
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
+ public ?string $name = null;
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ public ?AttributeList $attributes = null;
+
+ // ... getters and setters
+ }
+
+ class Attribute
+ {
+ public ?string $propName = null;
+ public ?string $propValue = null;
+
+ // ... getters and setters
+ }
+
+ class AttributeList extends TypedList
+ {
+ protected function __construct()
+ {
+ parent::__construct(Attribute::class);
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ }
+ // ...
+ ]
+ }
+ ```
+
* **The index**:
- The below index will index the **value** of document field 'ProductType'.
+
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```php
+ class Attributes_ByName extends AbstractIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Define the dynamic-index-fields by calling 'CreateField'.
+ // A dynamic-index-field will be generated for each item in 'attributes'.
+ //
+ // For each item, the field name will be the value of field 'propName'.
+ // The field terms will be derived from field 'propValue'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = p.attributes.Select(item => CreateField(item.propName, item.propValue)), " .
+ " Name = p.name " .
+ "}";
+ }
+ }
+ ```
+
+
+ ```php
+ class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'
+ _: p.attributes.map(item => createField(
+ item.propName, item.propValue, null)),
+
+ // A regular index field can be defined as well:
+ Name: p.name
+ };
+ })"
+ ]);
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Attributes_ByName::class)
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ ->whereEquals("Width", 10)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing::search()` in `CreateFieldOptions`.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```php
+ use Ds\Map as DSMap;
+
+ class Product
+ {
+ public ?string $id = null;
+ public ?DSMap $descriptions = null;
+
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
-
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```php
+ class Products_ByLocalizedDescription extends AbstractIndexCreationTask
+ {
+ private const USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ // Index each generated dynamic field for FTS
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
+
+ $this->storeAllFields(FieldStorage::no());
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ $this->getConfiguration()[self::USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS] = "true";
+ }
+ }
+ ```
+
+
+ ```php
+ class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ private const USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (product) {
+ return {
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })"
+ ]);
+
+ // Apply a storage default to every generated field
+ $fields = new IndexFieldOptionsArray();
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
+ $this->setFields($fields);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ $this->getConfiguration()[self::USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS] = "true";
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```php
+ /** @var array $results */
+ $results = $session->advanced()
+ ->documentQuery(Product::class, Products_ByLocalizedDescription::class)
+ ->search("Description_English", "north wind")
+ ->toList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
+
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
-
-{`class Products_ByProductType extends AbstractIndexCreationTask
+```php
+class Products_ByLocalizedDescription extends AbstractIndexCreationTask
{
public function __construct()
{
parent::__construct();
- // Call 'CreateField' to generate the dynamic-index-fields
- // The field name will be the value of document field 'ProductType'
- // The field terms will be derived from document field 'PricePerUnit'
- $this->map = "docs.Products.Select(p => new { " .
- " _ = this.CreateField(p.productType, p.pricePerUnit) " .
- "})";
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
+
+ $this->storeAllFields(FieldStorage::no());
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ $this->analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask
+
+```php
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
{
public function __construct()
{
parent::__construct();
$this->setMaps([
- "map('Products', function (p) {
+ "map('Products', function (product) {
return {
- _: createField(p.ProductType, p.PricePerUnit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
]);
- }
-}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByProductType::class)
-// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-->whereEquals("Electronics", 23)
-->toList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-## Example - list
-
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
+ // Apply a storage default to every generated field +
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ $fields = new IndexFieldOptionsArray();
-
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
-* **The document**:
-
-
-{`class Product
-\{
- public ?string $id = null;
- public ?string $name = null;
-
- // For each element in this list, the VALUE of property 'PropName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- public ?AttributeList $attributes = null;
-
- // ... getters and setters
-\}
-
-class Attribute
-\{
- public ?string $propName = null;
- public ?string $propValue = null;
-
- // ... getters and setters
-\}
-
-class AttributeList extends TypedList
-\{
- protected function __construct()
- \{
- parent::__construct(Attribute::class);
- \}
-\}
-`}
-
-
+ $englishFieldOptions = new IndexFieldOptions();
+ $englishFieldOptions->setAnalyzer("StopAnalyzer");
+ $fields->offsetSet("Description_English", $englishFieldOptions);
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
+ $this->setFields($fields);
+ }
+}
+```
+
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `width` will be a dynamic-index-field.
+#### Configure a fallback analyzer for all fields
-
+
-
-{`class Attributes_ByName extends AbstractIndexCreationTask
+```php
+class Products_ByLocalizedDescription extends AbstractIndexCreationTask
{
public function __construct()
{
parent::__construct();
- // Define the dynamic-index-fields by calling CreateField
- // A dynamic-index-field will be generated for each item in the Attributes list
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
- // For each item, the field name will be the value of field 'PropName'
- // The field terms will be derived from field 'PropValue'
+ $this->storeAllFields(FieldStorage::no());
- $this->map =
- "docs.Products.Select(p => new { " .
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " .
- " Name = p.name " .
- "})";
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ $this->analyze(DocumentsIndexingFields::ALL_FIELDS, "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask
+
+```php
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
{
public function __construct()
{
parent::__construct();
$this->setMaps([
- "map('Products', function (p) {
+ "map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
]);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ $fields = new IndexFieldOptionsArray();
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $allFieldsOptions->setAnalyzer("StopAnalyzer");
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
+ $this->setFields($fields);
}
}
-`}
-
-
-
-
-* **The query**:
- To get all documents matching a specific attribute property use:
-
-
-
-{`/** @var array $matchingDocuments */
-$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Attributes_ByName::class)
- // 'Width' is a dynamic-index-field that was indexed from the Attributes list
- ->whereEquals("Width", 10)
- ->toList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+The following applies when a `search()` query targets a **dynamic field**:
-## CreateField syntax
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `$this->analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `$this->analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-
-
-{`object CreateField(string name, object value);
+
+
+
+
+
+
+#### Syntax for LINQ-index:
+
+
+```php
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
-| Parameters | Type | Description |
-|------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **name** | `string` | Name of the dynamic-index-field |
-| **value** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`False` - will set `FieldStorage.NO` (default value)
`True` - will set `FieldStorate.YES` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`None` - `FieldIndexing.Default` (default value)
`False` - `FieldIndexing.Exact`
`True` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+#### Syntax for JavaScript-index:
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
-| **Storage** | `FieldStorage` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing` | |
-| **TermVector** | `FieldTermVector` | |
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
+
+
+| Parameters | Type | Description |
+|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage::no()` (default value)
`true` - will set `FieldStorage::yes()` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing::default()` (default value)
`false` - `FieldIndexing::exact()`
`true` - `FieldIndexing::search()` |
+| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
+| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -544,17 +976,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-python.mdx b/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-python.mdx
index 69514a29e2..6862d18067 100644
--- a/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-python.mdx
+++ b/versioned_docs/version-7.0/indexes/content/_using-dynamic-fields-python.mdx
@@ -1,490 +1,886 @@
import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
-import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
-
-## Example - index any field under object
+
-
-
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, attributes: Dict[str, object] = None):
- self.Id = Id
-
- # The KEYS under the Attributes object will be dynamically indexed
- # Fields added to this object after index creation time will also get indexed
- self.attributes = attributes
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, Attributes: Dict[str, object] = None):
+ self.Id = Id
+
+ # The KEYS under the Attributes object will be dynamically indexed
+ # Fields added to this object after index creation time will also get indexed
+ self.Attributes = Attributes
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `Attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAttributeKey(AbstractIndexCreationTask):
- def __init__(self):
- super().__init__()
- self.map = (
- "from p in docs.Products select new {"
- "_ = p.attributes.Select(item => CreateField(item.Key, item.Value))"
- "}"
- )
-`}
-
-
-
-
-{`class Products_ByAttributeKey_JS(AbstractJavaScriptIndexCreationTask):
- def __init__(self):
- super().__init__()
- self.maps = {
- """
- map('Products', function (p) {
- return {
- _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key],
- { indexing: 'Search', storage: true, termVector: null }))
- };
- })
- """
- }
-`}
-
-
-
-
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+
+
+
+ ```python
+ class Products_ByAttributeKey(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from p in docs.Products select new { "
+ # Call 'CreateField' to generate dynamic-index-fields
+ # from the Attributes object keys.
+
+ # Using '_' is just a convention.
+ # Any other string can be used instead of '_'
+
+ # The actual field name will be 'item.Key'
+ # The actual field terms will be derived from 'item.Value'
+ "_ = p.Attributes.Select(item => CreateField(item.Key, item.Value)) "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Products_ByAttributeKey_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.Attributes)
+ .map(key => createField(key, p.Attributes[key]))
+ };
+ })
+ """
+ ]
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- * To get all documents with some 'size' use:
-
-
-
-{`matching_documents = list(
- session.query_index_type(Products_ByAttributeKey, Product)
- # 'size' is a dynamic-index-field that was indexed from the attributes object
- .where_equals("size", 42)
-)
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
-
-## Example - index any field
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByAttributeKey, Product)
+ # 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ .where_equals("Size", 42)
+ )
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _document_query_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `where_equals("Size", 42)` or RQL `where Size = 42`.
+
+
+
+
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, first_name: str = None, last_name: str = None, title: str = None):
- self.Id = Id
-
- # All KEYS in the document will be dynamically indexes
- # Fields added to the document after index creation time wil also get indexed
- self.first_name = first_name
- self.last_name = last_name
- self.title = title
- # ...
-`}
-
-
-
-
-
-{`// Sample document content
- \{
+
+
+ ```python
+ class Product:
+ def __init__(
+ self,
+ Id: str = None,
+ FirstName: str = None,
+ LastName: str = None,
+ Title: str = None,
+ ):
+ self.Id = Id
+
+ # All KEYS in the document will be dynamically indexed
+ # Fields added to the document after index creation time will also get indexed
+ self.FirstName = FirstName
+ self.LastName = LastName
+ self.Title = Title
+ # ...
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
"FirstName": "John",
"LastName": "Doe",
"Title": "Engineer",
// ...
-\}
-`}
-
-
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAnyField_JS(AbstractJavaScriptIndexCreationTask):
- def __init__(self):
- super().__init__()
- # This will index EVERY FIELD under the top level of the document
- self.maps = {
- """
- map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })
- """
- }
-`}
-
-
-
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
+
+
+
+ ```python
+ class Products_ByAnyField_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ # This will index EVERY FIELD under the top level of the document
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ })
+ """
+ ]
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`# 'last_name' is a dynamic-index-field that was indexed from the document
-matching_documents = list(
- session.query_index_type(Products_ByAnyField_JS, Product).where_equals("last_name", "Doe")
-)
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _LastName_ use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByAnyField_JS, Product)
+ # 'LastName' is a dynamic-index-field that was indexed from the document
+ .where_equals("LastName", "Doe")
+ )
+ ```
+
+
+ ```sql
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where LastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
+
+* **The document**:
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, ProductType: str = None, PricePerUnit: int = None):
+ self.Id = Id
+
+ # The VALUE of ProductType will be dynamically indexed
+ self.ProductType = ProductType
+ self.PricePerUnit = PricePerUnit
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "ProductType": "Electronics",
+ "PricePerUnit": 23
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will index the **value** of document field 'ProductType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```python
+ class Products_ByProductType(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from p in docs.Products select new { "
+ # Call 'CreateField' to generate the dynamic-index-fields
+ # The field name will be the value of document field 'ProductType'
+ # The field terms will be derived from document field 'PricePerUnit'
+ "_ = CreateField(p.ProductType, p.PricePerUnit) "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Products_ByProductType_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _: createField(p.ProductType, p.PricePerUnit)
+ };
+ })
+ """
+ ]
+ ```
+
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByProductType, Product)
+ # 'Electronics' is the dynamic-index-field that was indexed
+ # from document field 'ProductType'
+ .where_equals("Electronics", 23)
+ )
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
+
+
+* **The document**:
+
+
+ ```python
+ class Attribute:
+ def __init__(self, PropName: str = None, PropValue: str = None):
+ self.PropName = PropName
+ self.PropValue = PropValue
+
+
+ class Product:
+ def __init__(self, Id: str = None, Name: str = None, Attributes: List[Attribute] = None):
+ self.Id = Id
+ self.Name = Name
+
+ # For each element in this list,
+ # the VALUE of property 'PropName' will be dynamically indexed.
+ # e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ self.Attributes = Attributes
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Name": "SomeName",
+ "Attributes": [
+ {
+ "PropName": "Color",
+ "PropValue": "Blue"
+ },
+ {
+ "PropName": "Width",
+ "PropValue": "10"
+ },
+ {
+ "PropName": "Length",
+ "PropValue": "20"
+ },
+ // ...
+ ]
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will create a dynamic-index-field per item in the document's `Attributes` list.
+ New items added to the Attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
+ E.g., 'PropName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```python
+ class Attributes_ByName(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from a in docs.Products select new { "
+ # Define the dynamic-index-fields by calling 'CreateField'
+ # A dynamic-index-field will be generated for each item in 'Attributes'
+
+ # For each item, the field name will be the value of field 'PropName'
+ # The field terms will be derived from field 'PropValue'
+ "_ = a.Attributes.Select(item => CreateField(item.PropName, item.PropValue)), "
+
+ # A regular index field can be defined as well:
+ "Name = a.Name "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Attributes_ByName_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _: p.Attributes.map(item => createField(item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name: p.Name
+ };
+ })
+ """
+ ]
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Attributes_ByName, Product)
+ # 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ .where_equals("Width", 10)
+ )
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing.Search` in `CreateFieldOptions`.
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Indexing documents fields VALUES
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
-## Example - basic
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
-
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, Descriptions: Dict[str, str] = None):
+ self.Id = Id
+ self.Descriptions = Descriptions
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
-* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, product_type: str = None, price_per_unit: float = None):
- self.Id = Id
-
- # The VALUE of ProductType will be dynamically indexed
- self.product_type = product_type
- self.price_per_unit = price_per_unit
-`}
-
-
+* **The index**:
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+ The following index creates one dynamic field for each entry in the `Descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
-* **The index**:
- The below index will index the **value** of document field 'ProductType'.
-
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```python
+ class Products_ByLocalizedDescription(AbstractIndexCreationTask):
+ USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS = (
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery"
+ )
+
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ # Index each generated dynamic field for FTS
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
+ "}"
+ )
+
+ self._store_all_fields(FieldStorage.NO)
+
+ # Set this configuration key to true so that search() queries on dynamic fields
+ # will use the 'Default Search Analyzer' when the generated field name
+ # has no explicit analyzer configuration.
+ self.configuration = {
+ Products_ByLocalizedDescription.USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS: "true"
+ }
+ ```
+
+
+ ```python
+ class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
+ USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS = (
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery"
+ )
+
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (product) {
+ return {
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })
+ """
+ ]
+
+ # Apply a storage default to every generated field
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO)
+ }
+
+ # Set this configuration key to true so that search() queries on dynamic fields
+ # will use the 'Default Search Analyzer' when the generated field name
+ # has no explicit analyzer configuration.
+ self.configuration = {
+ Products_ByLocalizedDescription_JS.USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS: "true"
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```python
+ results = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByLocalizedDescription, Product)
+ .search("Description_English", "north wind")
+ )
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
+
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
-
-{`class Products_ByProductType(AbstractIndexCreationTask):
+```python
+class Products_ByLocalizedDescription(AbstractIndexCreationTask):
def __init__(self):
super().__init__()
+ self.map = (
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
+ "}"
+ )
- # Call 'CreateField' to generate the dynamic-index-fields
- # The field name will be the value of document field 'product_type'
- # The field terms will be derived from document field 'price_per_unit'
- self.map = "from p in docs.Products select new { _ = CreateField(p.product_type, p.price_per_unit)}"
-`}
-
+ self._store_all_fields(FieldStorage.NO)
+
+ # Configure an analyzer for a known generated dynamic field name
+ # ==============================================================
+ self._analyze("Description_English", "StopAnalyzer")
+```
-
-
-{`class Products_ByProductType_JS(AbstractJavaScriptIndexCreationTask):
+
+```python
+class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
def __init__(self):
super().__init__()
- self.maps = {
+ self.maps = [
"""
- map('Products', function (p) {
+ map('Products', function (product) {
return {
- _: createField(p.product_type, p.price_per_unit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})
"""
+ ]
+
+ # Configure an analyzer for a known generated dynamic field name
+ # ==============================================================
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO),
+ "Description_English":
+ IndexFieldOptions(analyzer="StopAnalyzer")
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`# 'electronics' is the dynamic-index-field that was indexed from the document 'product_type'
-matching_documents = list(
- session.advanced.document_query_from_index_type(Products_ByProductType, Product).where_equals(
- "electronics", 23
- )
-)
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
+```
-## Example - list
-
-
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-
-
-
-* **The document**:
-
-
-{`class Attribute:
- def __init__(self, prop_name: str = None, prop_value: str = None):
- self.prop_name = prop_name
- self.prop_value = prop_value
-
-
-class Product:
- def __init__(self, Id: str = None, name: str = None, attributes: List[Attribute] = None):
- self.Id = Id
- self.name = name
- # For each element in this list, the VALUE of property 'prop_name' will be dynamically indexed
- # e.g. color, width, length (in ex. below) will become dynamic-index-field
- self.attributes = attributes
-`}
-
-
-
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
-
-
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `width` will be a dynamic-index-field.
+#### Configure a fallback analyzer for all fields
-
-{`class Attributes_ByName(AbstractIndexCreationTask):
+```python
+class Products_ByLocalizedDescription(AbstractIndexCreationTask):
def __init__(self):
super().__init__()
self.map = (
- "from a in docs.Products select new "
- "{ _ = a.attributes.Select( item => CreateField(item.prop_name, item.prop_value)), name = a.name "
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
"}"
)
-`}
-
+
+ self._store_all_fields(FieldStorage.NO)
+
+ # Use this as a fallback for fields that do not have
+ # their own explicit analyzer configuration
+ # ==================================================
+ self._analyze(constants.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer")
+```
-
-
-{`class Attributes_ByName_JS(AbstractJavaScriptIndexCreationTask):
+
+```python
+class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
def __init__(self):
super().__init__()
- self.maps = {
+ self.maps = [
"""
- map('Products', function (p) {
+ map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})
"""
+ ]
+
+ # Use this as a fallback for fields that do not have
+ # their own explicit analyzer configuration
+ # ==================================================
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO, analyzer="StopAnalyzer")
}
-`}
-
-
-
-
-* **The query**:
- To get all documents matching a specific attribute property use:
-
-
-
-{`matching_documents = list(
- session.advanced.document_query_from_index_type(Attributes_ByName, Product).where_equals(
- "width", 10
- )
-)
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+
+The following applies when a `search()` query targets a **dynamic field**:
+
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `self._analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `self._analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+
+
+
-## CreateField syntax
+
#### Syntax for Index:
-
-
-{`object CreateField(string name, object value);
+
+```python
+CreateField(name, value)
-object CreateField(string name, object value, bool stored, bool analyzed);
+CreateField(name, value, stored, analyzed)
-object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+CreateField(name, value, CreateFieldOptions)
+```
#### Syntax for JavaScript-index:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **name** | `string` | Name of the dynamic-index-field |
-| **value** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`False` - will set `FieldStorage.NO` (default value)
`True` - will set `FieldStorate.YES` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`None` - `FieldIndexing.Default` (default value)
`False` - `FieldIndexing.Exact`
`True` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+| Parameters | Type | Description |
+|----------------|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
+| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -496,17 +892,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).


-
-
-
-
+
+
diff --git a/versioned_docs/version-7.0/indexes/querying/content/_searching-csharp.mdx b/versioned_docs/version-7.0/indexes/querying/content/_searching-csharp.mdx
index d20ef5a65e..f0be0e6ffd 100644
--- a/versioned_docs/version-7.0/indexes/querying/content/_searching-csharp.mdx
+++ b/versioned_docs/version-7.0/indexes/querying/content/_searching-csharp.mdx
@@ -16,11 +16,13 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
* [Searching with wildcards](../../../indexes/querying/searching.mdx#searching-with-wildcards)
* [When using RavenStandardAnalyzer or StandardAnalyzer or NGramAnalyzer](../../../indexes/querying/searching.mdx#when-usingoror)
@@ -28,6 +30,7 @@ import CodeBlock from '@theme/CodeBlock';
* [When using the Exact analyzer](../../../indexes/querying/searching.mdx#when-using-the-exact-analyzer)
+
## Indexing single field for FTS
#### The index:
@@ -262,7 +265,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly,
+* To search across ALL fields in a document without defining each one explicitly,
use the `AsJson` method in the _Map_ function to extract all property values and index them in a single searchable field.
* This approach makes the index robust to changes in the document schema.
@@ -377,7 +380,14 @@ where search(AllValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/versioned_docs/version-7.0/indexes/querying/content/_searching-java.mdx b/versioned_docs/version-7.0/indexes/querying/content/_searching-java.mdx
index 7d85246ced..4accf3f512 100644
--- a/versioned_docs/version-7.0/indexes/querying/content/_searching-java.mdx
+++ b/versioned_docs/version-7.0/indexes/querying/content/_searching-java.mdx
@@ -388,4 +388,11 @@ where search(allValues, "tofu")
+## Indexing dynamic fields for FTS
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
\ No newline at end of file
diff --git a/versioned_docs/version-7.0/indexes/querying/content/_searching-nodejs.mdx b/versioned_docs/version-7.0/indexes/querying/content/_searching-nodejs.mdx
index 4ca66b5877..cb73bfd7c0 100644
--- a/versioned_docs/version-7.0/indexes/querying/content/_searching-nodejs.mdx
+++ b/versioned_docs/version-7.0/indexes/querying/content/_searching-nodejs.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,11 +17,13 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
* [Searching with wildcards](../../../indexes/querying/searching.mdx#searching-with-wildcards)
* [When using RavenStandardAnalyzer or StandardAnalyzer or NGramAnalyzer](../../../indexes/querying/searching.mdx#when-usingoror)
@@ -29,6 +31,7 @@ import CodeBlock from '@theme/CodeBlock';
* [When using the Exact analyzer](../../../indexes/querying/searching.mdx#when-using-the-exact-analyzer)
+
## Indexing single field for FTS
#### The index:
@@ -163,7 +166,7 @@ where (search(employeeData, "Manager") or search(employeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available when using **a C# LINQ string** that is assigned to the `map` property in the Node.js index class,
as shown in the example below.
@@ -229,6 +232,14 @@ where search(AllValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/versioned_docs/version-7.0/indexes/querying/content/_searching-php.mdx b/versioned_docs/version-7.0/indexes/querying/content/_searching-php.mdx
index 55261ce19f..510a6f8752 100644
--- a/versioned_docs/version-7.0/indexes/querying/content/_searching-php.mdx
+++ b/versioned_docs/version-7.0/indexes/querying/content/_searching-php.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,14 +17,17 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
+
## Indexing single field for FTS
#### The index:
@@ -253,7 +256,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available in the **C# LINQ string** that is assigned to the `map` property in the PHP index class,
as shown in the example below.
@@ -332,6 +335,15 @@ where search(allValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
+
## Boosting search results
diff --git a/versioned_docs/version-7.0/indexes/querying/content/_searching-python.mdx b/versioned_docs/version-7.0/indexes/querying/content/_searching-python.mdx
index f06c29d94f..88c6aa452f 100644
--- a/versioned_docs/version-7.0/indexes/querying/content/_searching-python.mdx
+++ b/versioned_docs/version-7.0/indexes/querying/content/_searching-python.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,14 +17,17 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
+
## Indexing single field for FTS
#### The index:
@@ -167,7 +170,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available in the **C# LINQ string** that is assigned to the `map` property in the Python index class,
as shown in the example below.
@@ -238,6 +241,14 @@ where search(all_values, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/versioned_docs/version-7.0/indexes/using-dynamic-fields.mdx b/versioned_docs/version-7.0/indexes/using-dynamic-fields.mdx
index e9ffb33a07..e465ba5431 100644
--- a/versioned_docs/version-7.0/indexes/using-dynamic-fields.mdx
+++ b/versioned_docs/version-7.0/indexes/using-dynamic-fields.mdx
@@ -1,7 +1,8 @@
---
-title: "Indexes: Dynamic Index Fields"
-sidebar_label: Dynamic Fields
-sidebar_position: 28
+title: "Dynamic Index Fields"
+sidebar_label: "Dynamic Index Fields"
+description: "Index document fields dynamically in RavenDB when field names are unknown at index definition time, using the CreateField method."
+sidebar_position: 27
supported_languages: ["csharp", "java", "python", "php", "nodejs"]
see_also:
- title: "Boosting"
@@ -31,7 +32,6 @@ import UsingDynamicFieldsPython from './content/_using-dynamic-fields-python.mdx
import UsingDynamicFieldsPhp from './content/_using-dynamic-fields-php.mdx';
import UsingDynamicFieldsNodejs from './content/_using-dynamic-fields-nodejs.mdx';
-
diff --git a/versioned_docs/version-7.0/server/configuration/indexing-configuration.mdx b/versioned_docs/version-7.0/server/configuration/indexing-configuration.mdx
index a3f9fce727..7bde291911 100644
--- a/versioned_docs/version-7.0/server/configuration/indexing-configuration.mdx
+++ b/versioned_docs/version-7.0/server/configuration/indexing-configuration.mdx
@@ -102,6 +102,7 @@ import LanguageContent from "@site/src/components/LanguageContent";
[Indexing.OrderByTicksAutomaticallyWhenDatesAreInvolved](../../server/configuration/indexing-configuration.mdx#indexingorderbyticksautomaticallywhendatesareinvolved)
[Indexing.QueryClauseCache.Disabled](../../server/configuration/indexing-configuration.mdx#indexingqueryclausecachedisabled)
[Indexing.QueryClauseCache.RepeatedQueriesTimeFrameInSec](../../server/configuration/indexing-configuration.mdx#indexingqueryclausecacherepeatedqueriestimeframeinsec)
+ [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
[Indexing.ScratchSpaceLimitInMb](../../server/configuration/indexing-configuration.mdx#indexingscratchspacelimitinmb)
[Indexing.Static.SearchEngineType](../../server/configuration/indexing-configuration.mdx#indexingstaticsearchenginetype)
[Indexing.Throttling.TimeIntervalInMs](../../server/configuration/indexing-configuration.mdx#indexingthrottlingtimeintervalinms)
@@ -988,6 +989,33 @@ Queries that repeat within this time frame will be considered worth caching.
+## Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery
+
+* This setting controls which analyzer is used for the **query term** when a **`search()` query** targets a [Dynamic index field](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ that was indexed for full-text search, and no analyzer is explicitly configured for that field in the index definition.
+
+ * `false` (default):
+ The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) is used to analyze the **query term**.
+ This analyzer can be configured via the [Indexing.Analyzers.Default](../../server/configuration/indexing-configuration.mdx#indexinganalyzersdefault) configuration key.
+
+ * `true`:
+ The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) is used to analyze the **query term**.
+ This analyzer can be configured via the [Indexing.Analyzers.Search.Default](../../server/configuration/indexing-configuration.mdx#indexinganalyzerssearchdefault) configuration key.
+
+* See the table in [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ for the complete analyzer-selection rules based on this configuration key and the analyzer configured for the dynamic index field.
+
+* This configuration applies to both the Lucene and Corax search engines.
+ The default is `false` to preserve backward compatibility.
+
+---
+
+- **Type**: `bool`
+- **Default**: `false`
+- **Scope**: Server-wide, or per database, or per index
+
+
+
## Indexing.ScratchSpaceLimitInMb
* Amount of scratch space in megabytes that we allow to use for the index storage.
diff --git a/versioned_docs/version-7.1/indexes/assets/dynamic-index-fields-1.png b/versioned_docs/version-7.1/indexes/assets/dynamic-index-fields-1.png
index b13d9076f8..a20adda0ec 100644
Binary files a/versioned_docs/version-7.1/indexes/assets/dynamic-index-fields-1.png and b/versioned_docs/version-7.1/indexes/assets/dynamic-index-fields-1.png differ
diff --git a/versioned_docs/version-7.1/indexes/assets/dynamic-index-fields-2.png b/versioned_docs/version-7.1/indexes/assets/dynamic-index-fields-2.png
index dd2b4082ea..c5b1bc14bc 100644
Binary files a/versioned_docs/version-7.1/indexes/assets/dynamic-index-fields-2.png and b/versioned_docs/version-7.1/indexes/assets/dynamic-index-fields-2.png differ
diff --git a/versioned_docs/version-7.1/indexes/content/_using-analyzers-csharp.mdx b/versioned_docs/version-7.1/indexes/content/_using-analyzers-csharp.mdx
index 6022cfd145..2e824fea4b 100644
--- a/versioned_docs/version-7.1/indexes/content/_using-analyzers-csharp.mdx
+++ b/versioned_docs/version-7.1/indexes/content/_using-analyzers-csharp.mdx
@@ -24,7 +24,7 @@ import CodeBlock from '@theme/CodeBlock';
* [Understanding the role of analyzers](../../indexes/using-analyzers.mdx#understanding-the-role-of-analyzers)
* [Analyzers available in RavenDB](../../indexes/using-analyzers.mdx#analyzers-available-in-ravendb)
* [Setting analyzer for index-field](../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field)
- * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendb)
+ * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendbs-default-analyzers)
* [Disabling indexing for index-field](../../indexes/using-analyzers.mdx#disabling-indexing-for-index-field)
* [Creating custom analyzers](../../indexes/using-analyzers.mdx#creating-custom-analyzers)
* [Viewing the indexed terms](../../indexes/using-analyzers.mdx#viewing-the-indexed-terms)
diff --git a/versioned_docs/version-7.1/indexes/content/_using-analyzers-nodejs.mdx b/versioned_docs/version-7.1/indexes/content/_using-analyzers-nodejs.mdx
index 6afd3b6202..fae2cdd2b9 100644
--- a/versioned_docs/version-7.1/indexes/content/_using-analyzers-nodejs.mdx
+++ b/versioned_docs/version-7.1/indexes/content/_using-analyzers-nodejs.mdx
@@ -24,7 +24,7 @@ import CodeBlock from '@theme/CodeBlock';
* [Understanding the role of analyzers](../../indexes/using-analyzers.mdx#understanding-the-role-of-analyzers)
* [Analyzers available in RavenDB](../../indexes/using-analyzers.mdx#analyzers-available-in-ravendb)
* [Setting analyzer for index-field](../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field)
- * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendb)
+ * [RavenDB's default analyzers](../../indexes/using-analyzers.mdx#ravendbs-default-analyzers)
* [Disabling indexing for index-field](../../indexes/using-analyzers.mdx#disabling-indexing-for-index-field)
* [Creating custom analyzers](../../indexes/using-analyzers.mdx#creating-custom-analyzers)
* [Viewing the indexed terms](../../indexes/using-analyzers.mdx#viewing-the-indexed-terms)
diff --git a/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-csharp.mdx b/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-csharp.mdx
index b4c4f518df..5bf052d482 100644
--- a/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-csharp.mdx
+++ b/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-csharp.mdx
@@ -2,533 +2,923 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
-
-## Example - index any field under object
-
-
+
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // The KEYS under the Attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- public Dictionary Attributes \{ get; set; \}
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // The KEYS under the Attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ public Dictionary Attributes { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `Attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-{`public class Products_ByAttributeKey : AbstractIndexCreationTask
-{
- public Products_ByAttributeKey()
+
+
+ ```csharp
+ public class Products_ByAttributeKey : AbstractIndexCreationTask
{
- Map = products => from p in products
- select new
- {
- // Call 'CreateField' to generate dynamic-index-fields from the Attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
-
- // The actual field name will be item.Key
- // The actual field terms will be derived from item.Value
- _ = p.Attributes.Select(item => CreateField(item.Key, item.Value))
- };
+ public Products_ByAttributeKey()
+ {
+ Map = products => from p in products
+ select new
+ {
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the Attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'
+
+ // The actual field name will be 'item.Key'
+ // The actual field terms will be derived from 'item.Value'
+ _ = p.Attributes.Select(item => CreateField(item.Key, item.Value))
+ };
+ }
}
-}
-`}
-
-
-
-
-{`public class Products_ByAttributeKey_JS : AbstractJavaScriptIndexCreationTask
-{
- public Products_ByAttributeKey_JS()
+ ```
+
+
+ ```csharp
+ public class Products_ByAttributeKey_JS : AbstractJavaScriptIndexCreationTask
{
- Maps = new HashSet
+ public Products_ByAttributeKey_JS()
{
- @"map('Products', function (p) {
- return {
- _: Object.keys(p.Attributes).map(key => createField(key, p.Attributes[key],
- { indexing: 'Search', storage: true, termVector: null }))
- };
- })"
- };
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.Attributes)
+ .map(key => createField(key, p.Attributes[key]))
+ };
+ })"
+ };
+ }
}
-}
-`}
-
-
-
-
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- The `_` property is Not queryable but used only in the index definition syntax.
- * To get all documents with some 'Size' use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Size' is a dynamic-index-field that was indexed from the Attributes object
- .WhereEquals("Size", 42)
- .ToList();
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ .WhereEquals("Size", 42)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _DocumentQuery_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ A strongly typed LINQ query such as `Query().Where(p => p.Size == 42)` would not compile.
+ Use the string-based `WhereEquals("Size", 42)` or RQL `where Size = 42` instead.
+
-## Example - index any field
+
-
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- public string FirstName \{ get; set; \}
- public string LastName \{ get; set; \}
- public string Title \{ get; set; \}
- // ...
-\}
-`}
-
-
-
-
-
-{`// Sample document content
- \{
- "FirstName": "John",
- "LastName": "Doe",
- "Title": "Engineer",
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ public string FirstName { get; set; }
+ public string LastName { get; set; }
+ public string Title { get; set; }
// ...
-\}
-`}
-
-
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "FirstName": "John",
+ "LastName": "Doe",
+ "Title": "Engineer",
+ // ...
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
-
-
-
-{`public class Products_ByAnyField_JS : AbstractJavaScriptIndexCreationTask
-{
- public Products_ByAnyField_JS()
+
+
+ ```csharp
+ public class Products_ByAnyField_JS : AbstractJavaScriptIndexCreationTask
{
- // This will index EVERY FIELD under the top level of the document
- Maps = new HashSet
+ public Products_ByAnyField_JS()
{
- @"map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })"
- };
+ // This will index EVERY FIELD under the top level of the document
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ })"
+ };
+ }
}
-}
-`}
-
-
-
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'LastName' is a dynamic-index-field that was indexed from the document
- .WhereEquals("LastName", "Doe")
- .ToList();
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _LastName_ use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ .WhereEquals("LastName", "Doe")
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where LastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+### Example - basic
-## Indexing documents fields VALUES
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-## Example - basic
+* **The document**:
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ // The VALUE of ProductType will be dynamically indexed
+ public string ProductType { get; set; }
+ public int PricePerUnit { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "ProductType": "Electronics",
+ "PricePerUnit": 23
+ }
+ ```
+
-
+* **The index**:
+
+ The following index will index the **value** of document field 'ProductType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```csharp
+ public class Products_ByProductType : AbstractIndexCreationTask
+ {
+ public Products_ByProductType()
+ {
+ Map = products => from p in products
+ select new
+ {
+ // Call 'CreateField' to generate the dynamic-index-fields
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _ = CreateField(p.ProductType, p.PricePerUnit)
+ };
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Products_ByProductType_JS : AbstractJavaScriptIndexCreationTask
+ {
+ public Products_ByProductType_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _: createField(p.ProductType, p.PricePerUnit)
+ };
+ })"
+ };
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ .WhereEquals("Electronics", 23)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
+### Example - list
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
-
- // The VALUE of ProductType will be dynamically indexed
- public string ProductType \{ get; set; \}
- public int PricePerUnit \{ get; set; \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+ public string Name { get; set; }
+
+ // For each element in this list,
+ // the VALUE of property 'PropName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ public List Attributes { get; set; }
+ }
+
+ public class Attribute
+ {
+ public string PropName { get; set; }
+ public string PropValue { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Name": "SomeName",
+ "Attributes": [
+ {
+ "PropName": "Color",
+ "PropValue": "Blue"
+ },
+ {
+ "PropName": "Width",
+ "PropValue": "10"
+ },
+ {
+ "PropName": "Length",
+ "PropValue": "20"
+ },
+ ...
+ ]
+ }
+ ```
+
* **The index**:
- The below index will index the **value** of document field 'ProductType'.
+
+ The following index will create a dynamic-index-field per item in the document's `Attributes` list.
+ New items added to the Attributes list after index creation time will be dynamically indexed as well.
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
+ E.g., 'PropName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```csharp
+ public class Attributes_ByName : AbstractIndexCreationTask
+ {
+ public Attributes_ByName()
+ {
+ Map = products => from a in products
+ select new
+ {
+ // Define the dynamic-index-fields by calling 'CreateField'
+ // A dynamic-index-field will be generated for each item in 'Attributes'
+
+ // For each item, the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _ = a.Attributes.Select(item =>
+ CreateField(item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name = a.Name
+ };
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Attributes_ByName_JS : AbstractJavaScriptIndexCreationTask
+ {
+ public Attributes_ByName_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _: p.Attributes.map(item => createField(
+ item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name: p.Name
+ };
+ })"
+ };
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```csharp
+ IList matchingDocuments = session
+ .Advanced
+ .DocumentQuery()
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ .WhereEquals("Width", 10)
+ .ToList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing.Search` in `CreateFieldOptions`.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `AllFields` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `AllFields` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```csharp
+ public class Product
+ {
+ public string Id { get; set; }
+
+ public Dictionary Descriptions { get; set; }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `Descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```csharp
+ public class Products_ByLocalizedDescription : AbstractIndexCreationTask
+ {
+ private const string UseSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription()
+ {
+ Map = products => from product in products
+ select new
+ {
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ // Index each generated dynamic field for FTS
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
+ };
+
+ StoreAllFields(FieldStorage.No);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ Configuration[UseSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
+
+ ```csharp
+ public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
+ {
+ private const string UseSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription_JS()
+ {
+ Maps = new HashSet
+ {
+ @"map('Products', function (product) {
+ return {
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })"
+ };
+
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No
+ };
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ Configuration[UseSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```csharp
+ List results = session.Advanced
+ .DocumentQuery()
+ .Search("Description_English", "north wind")
+ .ToList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
-
-
-
-{`public class Products_ByProductType : AbstractIndexCreationTask
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `AllFields` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `AllFields` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
+
+```csharp
+public class Products_ByLocalizedDescription : AbstractIndexCreationTask
{
- public Products_ByProductType()
+ public Products_ByLocalizedDescription()
{
- Map = products => from p in products
+ Map = products => from product in products
select new
{
- // Call 'CreateField' to generate the dynamic-index-fields
- // The field name will be the value of document field 'ProductType'
- // The field terms will be derived from document field 'PricePerUnit'
- _ = CreateField(p.ProductType, p.PricePerUnit)
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
};
+
+ StoreAllFields(FieldStorage.No);
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ Analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`public class Products_ByProductType_JS : AbstractJavaScriptIndexCreationTask
+
+```csharp
+public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
{
- public Products_ByProductType_JS()
+ public Products_ByLocalizedDescription_JS()
{
Maps = new HashSet
{
- @"map('Products', function (p) {
+ @"map('Products', function (product) {
return {
- _: createField(p.ProductType, p.PricePerUnit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
};
+
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No
+ };
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ Fields["Description_English"] = new IndexFieldOptions
+ {
+ Analyzer = "StopAnalyzer"
+ };
}
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
- .WhereEquals("Electronics", 23)
- .ToList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
+```
-## Example - list
-
-
+#### Configure a fallback analyzer for all fields
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-
-
-
-* **The document**:
-
-
-{`public class Product
-\{
- public string Id \{ get; set; \}
- public string Name \{ get; set; \}
-
- // For each element in this list, the VALUE of property 'PropName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- public List Attributes \{ get; set; \}
-\}
-
-public class Attribute
-\{
- public string PropName \{ get; set; \}
- public string PropValue \{ get; set; \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
-
-
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`public class Attributes_ByName : AbstractIndexCreationTask
+
+
+```csharp
+public class Products_ByLocalizedDescription : AbstractIndexCreationTask
{
- public Attributes_ByName()
+ public Products_ByLocalizedDescription()
{
- Map = products => from a in products
+ Map = products => from product in products
select new
{
- // Define the dynamic-index-fields by calling CreateField
- // A dynamic-index-field will be generated for each item in the Attributes list
-
- // For each item, the field name will be the value of field 'PropName'
- // The field terms will be derived from field 'PropValue'
- _ = a.Attributes.Select(item => CreateField(item.PropName, item.PropValue)),
-
- // A regular index field can be defined as well:
- Name = a.Name
+ _ = product.Descriptions.Select(x =>
+ CreateField(
+ "Description_" + x.Key,
+ x.Value,
+ new CreateFieldOptions
+ {
+ Indexing = FieldIndexing.Search,
+ Storage = FieldStorage.No
+ }))
};
+
+ StoreAllFields(FieldStorage.No);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ Analyze(Constants.Documents.Indexing.Fields.AllFields, "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`public class Attributes_ByName_JS : AbstractJavaScriptIndexCreationTask
+
+```csharp
+public class Products_ByLocalizedDescription_JS : AbstractJavaScriptIndexCreationTask
{
- public Attributes_ByName_JS()
+ public Products_ByLocalizedDescription_JS()
{
Maps = new HashSet
{
- @"map('Products', function (p) {
+ @"map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.Descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
};
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ Fields[Constants.Documents.Indexing.Fields.AllFields] = new IndexFieldOptions
+ {
+ Storage = FieldStorage.No,
+ Analyzer = "StopAnalyzer"
+ };
}
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents matching a specific attribute property use:
-
-
-
-{`IList matchingDocuments = session
- .Advanced
- .DocumentQuery()
- // 'Width' is a dynamic-index-field that was indexed from the Attributes list
- .WhereEquals("Width", 10)
- .ToList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+
+The following applies when a `search()` query targets a **dynamic field**:
+
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `AllFields` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `AllFields` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `Analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `Analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+
-## CreateField syntax
+
+
+
#### Syntax for LINQ-index:
-
-
-{`object CreateField(string name, object value);
+
+```csharp
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
#### Syntax for JavaScript-index:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
| Parameters | Type | Description |
|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -540,11 +930,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
+
+
+
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

+
+
\ No newline at end of file
diff --git a/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-java.mdx b/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-java.mdx
index 17f3cbe360..d54ef6bea8 100644
--- a/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-java.mdx
+++ b/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-java.mdx
@@ -2,479 +2,918 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
+
-* Any value type can be indexed, string, number, date, etc.
+
+
+### Example - index every field under an object
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
+
-* In this page:
+* **The document**:
+
+
+ ```java
+ public class Product {
+ private String id;
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+ // The KEYS under the attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ private Map attributes;
-
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "color": "Red",
+ "size": 42
+ }
+ }
+ ```
+
-## Indexing documents fields KEYS
+* **The index**:
+
+ The following index will index any field under the `attributes` object from the document,
+ a dynamic-index-field will be created for each such field.
+ New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `color` & `size` will become the actual dynamic-index-fields.
+
+
+
+ ```java
+ public class Products_ByAttributeKey extends AbstractIndexCreationTask {
+ public Products_ByAttributeKey() {
+
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'.
+
+ // The actual field name will be 'item.Key'
+ // The actual field terms will be derived from 'item.Value'
+ map = "docs.Products.Select(p => new { " +
+ " _ = p.attributes.Select(item => " +
+ " this.CreateField(item.Key, item.Value)) " +
+ "})";
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByAttributeKey_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ " _: Object.keys(p.attributes) " +
+ " .map(key => createField(key, p.attributes[key])) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
-## Example - index any field under object
+* **The query**:
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _size_ use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByAttributeKey.class)
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ .whereEquals("size", 42)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey' where size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _DocumentQuery_ or _RQL_ because the field names (e.g. `size`, `color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `whereEquals("size", 42)` or RQL `where size = 42` instead.
+
-
+
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field
+
+The following example allows you to:
+ * Define an index on a collection **without** needing any common structure between the indexed documents.
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
+
+
+
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // The KEYS under the attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- private Dictionary attributes;
-
- // get + set implementation ...
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "attributes": \{
- "color": "Red",
- "size": 42
- \}
-\}
-`}
-
-
+
+
+ ```java
+ public class Product {
+ private String id;
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ private String firstName;
+ private String lastName;
+ private String title;
+ // ...
+
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer"
+ // ...
+ }
+ ```
+
* **The index**:
- The following index will index any field under the `attributes` object from the document,
- a dynamic-index-field will be created for each such field.
- New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The following index will index any field from the document,
+ a dynamic-index-field will be created for each field.
+ New fields added to the document after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+ The example uses an `AbstractJavaScriptIndexCreationTask` because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a map or collection.
+
+
+
+ ```java
+ public class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByAnyField_JS() {
+
+ // This will index EVERY FIELD under the top level of the document
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ " _: Object.keys(p).map(key => createField(key, p[key])) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- e.g. Keys `color` & `size` will become the actual dynamic-index-fields.
+* **The query**:
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByAnyField_JS.class)
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ .whereEquals("lastName", "Doe")
+ .toList();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
-
-
-
-{`public class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
- public Products_ByAttributeKey_JS() {
- // Call 'createField' to generate dynamic-index-fields from the attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
+
- // The actual field name will be the key
- // The actual field terms will be derived from p.attributes[key]
- setMaps(Sets.newHashSet(
- "map('Products', function (p) { " +
- " return { " +
- " _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], " +
- " { indexing: 'Search', storage: false, termVector: null })) " +
- " }; " +
- "}) "
- ));
- }
-}
-`}
-
-
-
+
+
+### Example - basic
-* **The query**:
- * You can now query the generated dynamic-index fields.
- Property `_` is Not queryable, it is only used in the index definition syntax.
- * To get all documents with some 'size' use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByAttributeKey_JS.class)
- .whereEquals("size", 42)
- .toList();
-`}
-
-
-
-
-{`// 'size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey/JS' where size = 42
-`}
-
-
-
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-## Example - index any field
+* **The document**:
+
+
+ ```java
+ public class Product {
+ private String id;
-
+ // The VALUE of productType will be dynamically indexed
+ private String productType;
+ private int pricePerUnit;
-* Define an index on a collection **without** needing any common structure between the indexed documents.
-* After index is deployed, any new field added to the document will be indexed as well.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
-
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```java
+ public class Products_ByProductType extends AbstractIndexCreationTask {
+ public Products_ByProductType() {
+
+ // Call 'CreateField' to generate the dynamic-index-field.
+ // The field name will be the value of document field 'productType'.
+ // The field terms will be derived from document field 'pricePerUnit'.
+ map = "docs.Products.Select(p => new { " +
+ " _ = this.CreateField(p.productType, p.pricePerUnit) " +
+ "})";
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByProductType_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ " _: createField(p.productType, p.pricePerUnit) " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
-
-Consider if that is a true necessity, as indexing every single field can end up costing time and disk space.
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Products_ByProductType.class)
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ .whereEquals("Electronics", 23)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- private String firstName;
- private String lastName;
- private String title;
- // ...
-
- // get + set implementation ...
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "firstName": "John",
- "lastName": "Doe",
- "title": "Engineer",
- // ...
-\}
-`}
-
-
+
+
+ ```java
+ public class Product {
+ private String id;
+ private String name;
+
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ private List attributes;
+
+ // getters and setters ...
+ }
-* **The index**:
- The following index will index any field from the document,
- a dynamic-index-field will be created for each field.
- New fields added to the document after index creation time will be dynamically indexed as well.
+ public class Attribute {
+ private String propName;
+ private String propValue;
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ }
+ // ...
+ ]
+ }
+ ```
+
-
-
-
-{`public class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
- public Products_ByAnyField_JS() {
+* **The index**:
- // This will index EVERY FIELD under the top level of the document
- setMaps(Sets.newHashSet(
- "map('Products', function (p) { " +
- " return { " +
- " _: Object.keys(p).map(key => createField(key, p[key], " +
- " { indexing: 'Search', storage: true, termVector: null })) " +
- " }; " +
- "}) "
- ));
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```java
+ public class Attributes_ByName extends AbstractIndexCreationTask {
+ public Attributes_ByName() {
+
+ // Define the dynamic-index-fields by calling 'CreateField'.
+ // A dynamic-index-field will be generated for each item in 'attributes'.
+
+ // For each item, the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'.
+ // A regular index field (Name) is defined as well.
+ map = "docs.Products.Select(p => new { " +
+ " _ = p.attributes.Select(item => " +
+ " this.CreateField(item.propName, item.propValue)), " +
+ " Name = p.name " +
+ "})";
+ }
}
-}
-`}
-
-
-
+ ```
+
+
+ ```java
+ public class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
+ public Attributes_ByName_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (p) { " +
+ " return { " +
+ // For each item,
+ // the field name will be the value of field 'propName'.
+ // The field terms will be derived from field 'propValue'.
+ " _: p.attributes.map(item => " +
+ " createField(item.propName, item.propValue)), " +
+ // A regular index field can be defined as well:
+ " Name: p.name " +
+ " }; " +
+ "})"
+ ));
+ }
+ }
+ ```
+
+
* **The query**:
- * To get all documents with some 'lastName' use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByAnyField_JS.class)
- .whereEquals("lastName", "Doe")
- .toList();
-`}
-
-
-
-
-{`// 'lastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where lastName = "Doe"
-`}
-
-
-
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```java
+ List matchingDocuments = session
+ .advanced()
+ .documentQuery(Product.class, Attributes_ByName.class)
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ .whereEquals("Width", 10)
+ .toList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `indexing: 'Search'` in the `createField` options object (`AbstractJavaScriptIndexCreationTask`)
+or `FieldIndexing.Search` in the `CreateFieldOptions` (`AbstractIndexCreationTask`).
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
-## Indexing documents fields VALUES
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Example - basic
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
-
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
-* **The document**:
-
-
-{`public class Product \{
- private String id;
-
- // The VALUE of productType will be dynamically indexed
- private String productType;
- private int pricePerUnit;
-
- // get + set implementation ...
-\}
-`}
-
-
+
+ ```java
+ public class Product {
+ private String id;
-
-
-{`// Sample document content
-\{
- "productType": "Electronics",
- "pricePerUnit": 23
-\}
-`}
-
-
+ private Map descriptions;
-* **The index**:
- The following index will index the **value** of document field 'productType'.
+ // getters and setters ...
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` map.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```java
+ public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+
+ private static final String USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ // Index each generated dynamic field for FTS
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
+ "})";
+
+ storeAllFields(FieldStorage.NO);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ getConfiguration().put(USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS, "true");
+ }
+ }
+ ```
+
+
+ ```java
+ public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+
+ private static final String USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ // Index each generated dynamic field for FTS
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
+
+ Map fields = new HashMap<>();
+
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
+ setFields(fields);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ getConfiguration().put(USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS, "true");
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```java
+ List results = session.advanced()
+ .documentQuery(Product.class, Products_ByLocalizedDescription.class)
+ .search("Description_English", "north wind")
+ .toList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
- This value will be the dynamic-index-field name on which you can query.
- e.g. Field value `Electronics` will be the dynamic-index-field.
+---
-
-
-
-{`public class Products_ByProductType extends AbstractIndexCreationTask {
- public Products_ByProductType() {
+
+
+### Configuring analyzers for dynamic fields
+
+The `CreateFieldOptions` (and the JavaScript `createField` options) do **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- map = "docs.Products.Select(p => new { " +
- " _ = this.CreateField(p.productType, p.pricePerUnit) " +
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
+
+```java
+public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
"})";
+
+ storeAllFields(FieldStorage.NO);
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Products_ByProductType.class)
- .whereEquals("Electronics", 23)
- .toList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-## Example - list
+
+```java
+public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
-
+ Map fields = new HashMap<>();
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
-
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ IndexFieldOptions englishOptions = new IndexFieldOptions();
+ englishOptions.setAnalyzer("StopAnalyzer");
+ fields.put("Description_English", englishOptions);
-* **The document**:
-
-
-{`public class Product \{
- private String id;
- private String name;
-
- // For each element in this list, the VALUE of property 'propName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- private List attributes;
-
- // get + set implementation ...
-\}
-
-public class Attribute \{
- private String propName;
- private String propValue;
-
- // get + set implementation ...
-\}
-`}
-
+ setFields(fields);
+ }
+}
+```
+
-
-
-{`// Sample document content
-\{
-name": "SomeName",
-attributes": [
- \{
- "propName": "Color",
- "propValue": "Blue"
- \},
- \{
- "propName": "Width",
- "propValue": "10"
- \},
- \{
- "propName": "Length",
- "propValue": "20"
- \},
- ...
-
-\}
-`}
-
-
+#### Configure a fallback analyzer for all fields
+
+
+
+```java
+public class Products_ByLocalizedDescription extends AbstractIndexCreationTask {
+ public Products_ByLocalizedDescription() {
+ map = "docs.Products.Select(product => new { " +
+ " _ = product.descriptions.Select(x => " +
+ " this.CreateField( " +
+ " \"Description_\" + x.Key, " +
+ " x.Value, " +
+ " new CreateFieldOptions { " +
+ " Indexing = FieldIndexing.Search, " +
+ " Storage = FieldStorage.No " +
+ " })) " +
+ "})";
-* **The index**:
- The following index will create a dynamic-index-field per item in the document's `attributes` list.
- New items added to the attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's propName **value**.
- E.g., 'propName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`public class Attributes_ByName extends AbstractIndexCreationTask {
- public Attributes_ByName() {
-
- // For each attribute item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- // A regular-index-field (Name) is defined as well
- map =
- "docs.Products.Select(p => new { " +
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " +
- " Name = p.name " +
- "})";
+ storeAllFields(FieldStorage.NO);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ analyze(Constants.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer");
}
}
-`}
-
+```
-
+
+```java
+public class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ public Products_ByLocalizedDescription_JS() {
+ setMaps(Sets.newHashSet(
+ "map('Products', function (product) { " +
+ " return { " +
+ " _: Object.keys(product.descriptions) " +
+ " .map(function (key) { " +
+ " return createField( " +
+ " 'Description_' + key, " +
+ " product.descriptions[key], " +
+ " { " +
+ " indexing: 'Search', " +
+ " storage: false " +
+ " }); " +
+ " }) " +
+ " }; " +
+ "})"
+ ));
-* **The query**:
- * To get all documents matching a specific attribute property use:
-
-
-
-{`List matchingDocuments = session
- .query(Product.class, Attributes_ByName.class)
- .whereEquals("Width", 10)
- .toList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+ Map fields = new HashMap<>();
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ IndexFieldOptions allFieldsOptions = new IndexFieldOptions();
+ allFieldsOptions.setStorage(FieldStorage.NO);
+ allFieldsOptions.setAnalyzer("StopAnalyzer");
+ fields.put(Constants.Documents.Indexing.Fields.ALL_FIELDS, allFieldsOptions);
+
+ setFields(fields);
+ }
+}
+```
+
+
+
+
+### Which analyzer is used for the query term?
+The following applies when a `search()` query targets a **dynamic field**:
-## CreateField syntax
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-#### Syntax for LINQ-index:
+
-
-
-{`object CreateField(string name, object value);
+
+
+
+
+#### Syntax for `AbstractIndexCreationTask`
+
+
+```csharp
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
-#### Syntax for JavaScript-index:
+#### Syntax for `AbstractJavaScriptIndexCreationTask`
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|----------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
+| Parameters | Type | Description |
+|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+* The `CreateField` syntax (and the `CreateFieldOptions` shape) above describes what is available inside the server-side `map` string of an `AbstractIndexCreationTask`,
+ since the Java client sends the `map` source to the server for compilation.
+ The JavaScript `createField` function is the equivalent for `AbstractJavaScriptIndexCreationTask` map sources.
+
* All above examples have used the character `_` in the dynamic-index-field definition.
However, using `_` is just a convention. Any other string can be used instead.
* This property is Not queryable, it is only used in the index definition syntax.
- The actual dynamic-index-fields that are generated are defined by the `CreateField` method.
+ The actual dynamic-index-fields that are generated are defined by the `CreateField` method (or the `createField` JS function).
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-nodejs.mdx b/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-nodejs.mdx
index b5df2df4a7..c14184c2b5 100644
--- a/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-nodejs.mdx
+++ b/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-nodejs.mdx
@@ -2,533 +2,710 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`createField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
+
-
-#### Example - index any field under object
-The following allows you to:
-
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
-**The document**:
-
-
-{`class Product \{
- constructor(id, attributes) \{
- this.id = id;
-
- // The KEYS under the attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- this.attributes = attributes;
- \}
-\}
-`}
-
-
+
+
+### Example - index every field under an object
-
-
-{`// Sample document content
-\{
- "attributes": \{
- "color": "Red",
- "size": 42
- \}
-\}
-`}
-
-
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
+
-**The index**:
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, attributes) {
+ this.id = id;
+
+ // The KEYS under the attributes object will be dynamically indexed
+ // Fields added to this object after index creation time will also get indexed
+ this.attributes = attributes;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "color": "Red",
+ "size": 42
+ }
+ }
+ ```
+
-* The following index will index any field under the `attributes` object from the document,
+* **The index**:
+
+ The following index will index any field under the `attributes` object from the document,
a dynamic-index-field will be created for each such field.
- New fields added to the object after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- e.g. Keys `color` & `size` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
- constructor() {
- super();
-
- const { createField } = this.mapUtils();
-
- this.map("Products", p => {
- return {
- // Call 'createField' to generate dynamic-index-fields from the attributes object keys
- // Using '_' is just a convention. Any other string can be used instead of '_'
-
- // The actual field name will be the key
- // The actual field terms will be derived from p.attributes[key]
- _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], {
- indexing: "Search",
- storage: false,
- termVector: null
- }))
- };
- });
+ New fields added to the object after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `color` & `size` will become the actual dynamic-index-fields.
+
+
+ ```js
+ class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // Call 'createField' to generate dynamic-index-fields
+ // from the attributes object keys.
+
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'
+
+ // The actual field name will be the key
+ // The actual field terms will be derived from p.attributes[key]
+ _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key]))
+ };
+ });
+ }
}
-}
-`}
-
-
-
-
-**The query**:
-
-* You can now query the generated dynamic-index fields.
- Property `_` is Not queryable, it is only used in the index definition syntax.
-
-* To get all documents with some 'size' use:
-
-
-
-
-{`const matchingDocuments = session.query({indexName: 'Products_ByAttributeKey'})
- // 'size' is a dynamic-index-field that was indexed from the attributes object
- .whereEquals('size', 42)
- .all();
-`}
-
-
-
-
-{`// 'size' is a dynamic-index-field that was indexed from the attributes object
-from index 'Products/ByAttributeKey' where size = 42
-`}
-
-
-
-
-
+ ```
+
+
+* **The query**:
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _size_ use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByAttributeKey/JS" })
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ .whereEquals("size", 42)
+ .all();
+ ```
+
+
+ ```sql
+ // 'size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey/JS' where size = 42
+ ```
+
+
+
+
+
+
+
+### Example - index every field
-#### Example - index any field
-The following allows you to:
-
-* Define an index on a collection **without** needing any common structure between the indexed documents.
-* After index is deployed, any new field added to the document will be indexed as well.
-
+The following example allows you to:
+ * Define an index on a collection **without** needing any common structure between the indexed documents.
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
+
+
-
-Consider if that is a true necessity, as indexing every single field can end up costing time and disk space.
-
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
-**The document**:
-
-
-{`class Product \{
- constructor(id, firstName, lastName, title) \{
- this.id = id;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- this.firstName = firstName;
- this.lastName = lastName;
- this.title = title;
- // ...
- \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "firstName": "John",
- "lastName": "Doe",
- "title": "Engineer",
- // ...
-\}
-`}
-
-
-**The index**:
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, firstName, lastName, title) {
+ this.id = id;
+
+ // All KEYS in the document will be dynamically indexed
+ // Fields added to the document after index creation time will also get indexed
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.title = title;
+ // ...
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer",
+ // ...
+ }
+ ```
+
-* The following index will index any field from the document,
+* **The index**:
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
- New fields added to the document after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the field **key**.
- e.g. Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+ New fields added to the document after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+
+ ```js
+ class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ // This will index EVERY FIELD under the top level of the document
+ this.map("Products", p => {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByAnyField/JS" })
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ .whereEquals("lastName", "Doe")
+ .all();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
-
-
-
-{`class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
- super();
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, productType, pricePerUnit) {
+ this.id = id;
+
+ // The VALUE of productType will be dynamically indexed
+ this.productType = productType;
+ this.pricePerUnit = pricePerUnit;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+ ```js
+ class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ _: createField(p.productType, p.pricePerUnit)
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Products/ByProductType/JS" })
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ .whereEquals("Electronics", 23)
+ .all();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType/JS' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
- const { createField } = this.mapUtils();
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
+
- this.map("Products", p => {
- return {
- // This will index EVERY FIELD under the top level of the document
- _: Object.keys(p).map(key => createField(key, p[key], {
- indexing: "Search",
- storage: true,
- termVector: null
- }))
- };
- });
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, name, attributes) {
+ this.id = id;
+ this.name = name;
+
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ this.attributes = attributes;
+ }
}
-}
-`}
-
-
-
-**The query**:
+ class Attribute {
+ constructor(propName, propValue) {
+ this.propName = propName;
+ this.propValue = propValue;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ },
+ ...
+ ]
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+ ```js
+ class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ this.map("Products", p => {
+ return {
+ // Define the dynamic-index-fields by calling 'createField'
+ // A dynamic-index-field will be generated for each item in 'attributes'
+
+ // For each item, the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'
+ _: p.attributes.map(item =>
+ createField(item.propName, item.propValue)),
+
+ // A regular index field can be defined as well:
+ name: p.name
+ };
+ });
+ }
+ }
+ ```
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```js
+ const matchingDocuments = await session
+ .query({ indexName: "Attributes/ByName/JS" })
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ .whereEquals("Width", 10)
+ .all();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName/JS' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `indexing: "Search"` in the `createField` options.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
-* To get all documents with some 'lastName' use:
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```js
+ class Product {
+ constructor(id, descriptions) {
+ this.id = id;
+ this.descriptions = descriptions;
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
+
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+ ```js
+ class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
+ super();
+
+ const { createField } = this.mapUtils();
+
+ const useSearchAnalyzerForDynamicFields =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ this.map("Products", product => {
+ return {
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: "Search",
+ storage: false
+ }))
+ };
+ });
+
+ this.storeAllFields("No");
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ this.configuration[useSearchAnalyzerForDynamicFields] = "true";
+ }
+ }
+ ```
+
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Products_ByAnyField_JS' })
- // 'lastName' is a dynamic-index-field that was indexed from the document
- .whereEquals('lastName', 'Doe')
- .all();
-`}
-
-
-
-
-{`// 'lastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where lastName = "Doe"
-`}
-
-
-
+* **Full-text search query**:
-
+ Query the generated dynamic field by its field name.
+ In this example, the query targets the generated field `Description_English`.
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Indexing documents fields VALUES
+
+
+ ```js
+ const results = await session
+ .query({ indexName: "Products/ByLocalizedDescription/JS" })
+ .search("Description_English", "north wind")
+ .all();
+ ```
+
-
-#### Example - basic
-This example shows:
-
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
-* For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---index-a-list-of-properties) below.
-**The document**:
-
-
-{`class Product \{
- constructor(id, productType, pricePerUnit) \{
- this.id = id;
-
- // The VALUE of productType will be dynamically indexed
- this.productType = productType;
- this.pricePerUnit = pricePerUnit;
- \}
-\}
-`}
-
-
+
+ ```sql
+ from index "Products/ByLocalizedDescription/JS"
+ where search(Description_English, "north wind")
+ ```
+
+
-
-
-{`// Sample document content
-\{
- "productType": "Electronics",
- "pricePerUnit": 23
-\}
-`}
-
-
+---
-**The index**:
+
+
+### Configuring analyzers for dynamic fields
-* The following index will index the **value** of document field 'productType'.
+The `createField` options object does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
-* This value will be the dynamic-index-field name on which you can query.
- e.g. Field value `Electronics` will be the dynamic-index-field.
+---
-
-
-
-{`class Products_ByProductType extends AbstractCsharpIndexCreationTask {
- constructor () {
- super();
+#### Configure analyzer for a specific dynamic field
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- this.map = "docs.Products.Select(p => new { " +
- " _ = this.CreateField(p.productType, p.pricePerUnit) " +
- "})";
- }
-}
-`}
-
-
-
-
-{`class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
+
+```js
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
super();
const { createField } = this.mapUtils();
- this.map("Products", p => {
+ this.map("Products", product => {
return {
- _: [
- // The field name will be the value of document field 'productType'
- // The field terms will be derived from document field 'pricePerUnit'
- createField(p.productType, p.pricePerUnit, {
- indexing: "Search",
- storage: false,
- termVector: null
- })
- ]
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ indexing: "Search",
+ storage: false
+ }))
};
});
- }
-}
-`}
-
-
-
-
-**The query**:
-
-* To get all documents of some product type having a specific price per unit use:
-
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Products_ByProductType' })
- // 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
- .whereEquals('Electronics', 23)
- .all();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'productType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-
-
-#### Example - list
-The following allows you to:
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-**The document**:
-
-
-{`class Product \{
- constructor(id, name, attributes) \{
- this.id = id;
- this.name = name;
-
- // For each element in this list, the VALUE of property 'propName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- this.attributes = attributes;
- \}
-\}
-
-class Attribute \{
- constructor(propName, propValue) \{
- this.propName = propName;
- this.propValue = propValue;
- \}
-\}
-`}
-
-
-
-
-
-{`// Sample document content
-\{
- "name": "SomeName",
- "attributes": [
- \{
- "propName": "Color",
- "propValue": "Blue"
- \},
- \{
- "propName": "Width",
- "propValue": "10"
- \},
- \{
- "propName": "Length",
- "propValue": "20"
- \},
- ...
- ]
-\}
-`}
-
-
-
-**The index**:
-
-* The following index will create a dynamic-index-field per item in the document's `attributes` list.
- New items added to the attributes list after index creation time will be dynamically indexed as well.
-
-* The actual dynamic-index-field name on which you can query will be the item's propName **value**.
- e.g. 'propName' value `Width` will be a dynamic-index-field.
-
-
-
-
-{`class Attributes_ByName extends AbstractCsharpIndexCreationTask
-{
- constructor () {
- super();
+ this.storeAllFields("No");
- // For each attribute item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- // A regular-index-field (Name) is defined as well
- this.map =
- "docs.Products.Select(p => new { " +
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " +
- " Name = p.name " +
- "})";
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ this.analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask {
- constructor () {
+
+#### Configure a fallback analyzer for all fields
+
+
+```js
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask {
+ constructor() {
super();
const { createField } = this.mapUtils();
- this.map("Products", p => {
+ this.map("Products", product => {
return {
- // For each item, the field name will be the value of field 'propName'
- // The field terms will be derived from field 'propValue'
- _: p.attributes.map(item => createField(item.propName, item.propValue, {
- indexing: "Search",
- storage: true,
- termVector: null
- })),
-
- // A regular-index-field can be defined as well:
- Name: p.name
+ _: Object.keys(product.descriptions).map(key =>
+ createField(
+ "Description_" + key,
+ product.descriptions[key],
+ {
+ indexing: "Search",
+ storage: false
+ }))
};
});
- }
-}
-`}
-
-
-
-
-**The query**:
-* To get all documents matching a specific attribute property use:
+ this.storeAllFields("No");
-
-
-
-{`const matchingDocuments = session.query({ indexName: 'Attributes/ByName' })
- // 'Width' is a dynamic-index-field that was indexed from the attributes list
- .whereEquals('Width', 10)
- .all();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ this.analyze(CONSTANTS.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer");
+ }
+}
+```
-
-
-
+
+
+
+
+### Which analyzer is used for the query term?
-## CreateField syntax
+The following applies when a `search()` query targets a **dynamic field**:
-#### Syntax for LINQ-index:
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `this.analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `this.analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-
-
-{`object CreateField(string name, object value);
+
-object CreateField(string name, object value, bool stored, bool analyzed);
+
-object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
-
+
-#### Syntax for JavaScript-index:
+#### Syntax:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|----------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **fieldName** | `string` | Name of the dynamic-index-field |
-| **fieldValue** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorate.Yes` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+| Parameters | Type | Description |
+|----------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **options** | `object` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
-| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| options object | | |
+|-----------------|--------------------|-----------------------------------------------------------------------------------|
+| **storage** | `boolean` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
+| **indexing** | `FieldIndexing` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **termVector** | `FieldTermVector` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -536,21 +713,19 @@ object CreateField(string name, object value, CreateFieldOptions options);
However, using `_` is just a convention. Any other string can be used instead.
* This property is Not queryable, it is only used in the index definition syntax.
- The actual dynamic-index-fields that are generated are defined by the `CreateField` method.
+ The actual dynamic-index-fields that are generated are defined by the `createField` method.
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-php.mdx b/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-php.mdx
index 09c58cc9fc..6992310715 100644
--- a/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-php.mdx
+++ b/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-php.mdx
@@ -2,537 +2,969 @@ import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
+
-* In this page:
+
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
-## Indexing documents fields KEYS
-
-## Example - index any field under object
+* **The document**:
+
+
+ ```php
+ use Ds\Map as DSMap;
-
+ class Product
+ {
+ public ?string $id = null;
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+ // The KEYS under the attributes object will be dynamically indexed.
+ // Fields added to this object after index creation time will also get indexed.
+ public ?DSMap $attributes = null;
-
-
-* **The document**:
-
-
-{`use Ds\\Map as DSMap;
-
-class Product
-\{
- private ?string $id = null;
-
- // The KEYS under the Attributes object will be dynamically indexed
- // Fields added to this object after index creation time will also get indexed
- public ?DSMap $attributes = null;
-\}
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-{`class Products_ByAttributeKey extends AbstractIndexCreationTask
-{
- public function __construct()
+
+
+ ```php
+ class Products_ByAttributeKey extends AbstractIndexCreationTask
{
- parent::__construct();
-
- $this->map = "from p in docs.Products select new {" .
- "_ = p.attributes.Select(item => CreateField(item.Key, item.Value))" .
- "}";
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Call 'CreateField' to generate dynamic-index-fields
+ // from the attributes object keys.
+ //
+ // Using '_' is just a convention.
+ // Any other string can be used instead of '_'.
+ //
+ // The actual field name will be 'item.Key'.
+ // The actual field terms will be derived from 'item.Value'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = p.attributes.Select(item => CreateField(item.Key, item.Value)) " .
+ "}";
+ }
}
-}
-`}
-
-
-
-
-{`class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask
-{
- public function __construct()
+ ```
+
+
+ ```php
+ class Products_ByAttributeKey_JS extends AbstractJavaScriptIndexCreationTask
{
- parent::__construct();
-
- $this->setMaps([
- "map('Products', function (p) { " .
- " return { " .
- " _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key], " .
- " { indexing: 'Search', storage: false, termVector: null })) " .
- " }; " .
- "}) "
- ]);
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.attributes)
+ .map(key => createField(key, p.attributes[key], null))
+ };
+ })"
+ ]);
+ }
}
-}
-`}
-
-
-
-
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- * To get all documents with some 'size' use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByAttributeKey::class)
- // 'Size' is a dynamic-index-field that was indexed from the Attributes object
- ->whereEquals("Size", 42)
- ->toList();
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
-
-## Example - index any field
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByAttributeKey::class)
+ // 'Size' is a dynamic-index-field that was indexed from the attributes object
+ ->whereEquals("Size", 42)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _documentQuery_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `whereEquals("Size", 42)` or RQL `where Size = 42` instead.
+
+
+
+
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`class Product
-\{
- private ?string $id = null;
-
- // All KEYS in the document will be dynamically indexed
- // Fields added to the document after index creation time will also get indexed
- public ?string $firstName = null;
- public ?string $lastName = null;
- public ?string $title = null;
-
- // ... getters and setters
-\}
-`}
-
-
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
-
-
-{`// Sample document content
- \{
- "FirstName": "John",
- "LastName": "Doe",
- "Title": "Engineer",
+ // All KEYS in the document will be dynamically indexed.
+ // Fields added to the document after index creation time will also get indexed.
+ public ?string $firstName = null;
+ public ?string $lastName = null;
+ public ?string $title = null;
// ...
-\}
-`}
-
-
+
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "firstName": "John",
+ "lastName": "Doe",
+ "title": "Engineer"
+ // ...
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask
-{
- public function __construct()
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `firstName` & `lastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
+
+
+
+ ```php
+ class Products_ByAnyField_JS extends AbstractJavaScriptIndexCreationTask
{
- parent::__construct();
-
- // This will index EVERY FIELD under the top level of the document
- $this->setMaps([
- "map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })"
- ]);
+ public function __construct()
+ {
+ parent::__construct();
+
+ // This will index EVERY FIELD under the top level of the document
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key], null))
+ };
+ })"
+ ]);
+ }
}
-}
-`}
-
-
-
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByAnyField_JS::class)
- // 'LastName' is a dynamic-index-field that was indexed from the document
- ->whereEquals("LastName", "Doe")
- ->toList();
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _lastName_ use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByAnyField_JS::class)
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ ->whereEquals("lastName", "Doe")
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'lastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where lastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
+* **The document**:
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
+ // The VALUE of productType will be dynamically indexed
+ public ?string $productType = null;
+ public ?int $pricePerUnit = null;
-## Indexing documents fields VALUES
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "productType": "Electronics",
+ "pricePerUnit": 23
+ }
+ ```
+
-## Example - basic
+* **The index**:
+
+ The following index will index the **value** of document field 'productType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
-
+
+
+ ```php
+ class Products_ByProductType extends AbstractIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Call 'CreateField' to generate the dynamic-index-fields.
+ // The field name will be the value of document field 'productType'.
+ // The field terms will be derived from document field 'pricePerUnit'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = CreateField(p.productType, p.pricePerUnit) " .
+ "}";
+ }
+ }
+ ```
+
+
+ ```php
+ class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'productType'
+ // The field terms will be derived from document field 'pricePerUnit'
+ _: createField(p.productType, p.pricePerUnit, null)
+ };
+ })"
+ ]);
+ }
+ }
+ ```
+
+
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Products_ByProductType::class)
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ ->whereEquals("Electronics", 23)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'productType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
* **The document**:
-
-
-{`class Product
-\{
- public ?string $id = null;
-
- // The VALUE of ProductType will be dynamically indexed
- public ?string $productType = null;
- public ?int $pricePerUnit = null;
-
- // ... getters and setters
-\}
-`}
-
-
+
+
+ ```php
+ class Product
+ {
+ public ?string $id = null;
+ public ?string $name = null;
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+ // For each element in this list,
+ // the VALUE of property 'propName' will be dynamically indexed.
+ // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ public ?AttributeList $attributes = null;
+
+ // ... getters and setters
+ }
+
+ class Attribute
+ {
+ public ?string $propName = null;
+ public ?string $propValue = null;
+
+ // ... getters and setters
+ }
+
+ class AttributeList extends TypedList
+ {
+ protected function __construct()
+ {
+ parent::__construct(Attribute::class);
+ }
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "name": "SomeName",
+ "attributes": [
+ {
+ "propName": "Color",
+ "propValue": "Blue"
+ },
+ {
+ "propName": "Width",
+ "propValue": "10"
+ },
+ {
+ "propName": "Length",
+ "propValue": "20"
+ }
+ // ...
+ ]
+ }
+ ```
+
* **The index**:
- The below index will index the **value** of document field 'ProductType'.
+
+ The following index will create a dynamic-index-field per item in the document's `attributes` list.
+ New items added to the attributes list after index creation time will be dynamically indexed as well.
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ The actual dynamic-index-field name on which you can query will be the item's propName **value**.
+ E.g., 'propName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```php
+ class Attributes_ByName extends AbstractIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ // Define the dynamic-index-fields by calling 'CreateField'.
+ // A dynamic-index-field will be generated for each item in 'attributes'.
+ //
+ // For each item, the field name will be the value of field 'propName'.
+ // The field terms will be derived from field 'propValue'.
+ $this->map =
+ "from p in docs.Products " .
+ "select new { " .
+ " _ = p.attributes.Select(item => CreateField(item.propName, item.propValue)), " .
+ " Name = p.name " .
+ "}";
+ }
+ }
+ ```
+
+
+ ```php
+ class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'propName'
+ // The field terms will be derived from field 'propValue'
+ _: p.attributes.map(item => createField(
+ item.propName, item.propValue, null)),
+
+ // A regular index field can be defined as well:
+ Name: p.name
+ };
+ })"
+ ]);
+ }
+ }
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```php
+ /** @var array $matchingDocuments */
+ $matchingDocuments = $session
+ ->advanced()
+ ->documentQuery(Product::class, Attributes_ByName::class)
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ ->whereEquals("Width", 10)
+ ->toList();
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing::search()` in `CreateFieldOptions`.
+
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
+
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
+
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
+
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```php
+ use Ds\Map as DSMap;
+
+ class Product
+ {
+ public ?string $id = null;
+ public ?DSMap $descriptions = null;
+
+ // ... getters and setters
+ }
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
+
+* **The index**:
+
+ The following index creates one dynamic field for each entry in the `descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
-
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```php
+ class Products_ByLocalizedDescription extends AbstractIndexCreationTask
+ {
+ private const USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ // Index each generated dynamic field for FTS
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
+
+ $this->storeAllFields(FieldStorage::no());
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ $this->getConfiguration()[self::USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS] = "true";
+ }
+ }
+ ```
+
+
+ ```php
+ class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
+ {
+ private const USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS =
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery";
+
+ public function __construct()
+ {
+ parent::__construct();
+
+ $this->setMaps([
+ "map('Products', function (product) {
+ return {
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })"
+ ]);
+
+ // Apply a storage default to every generated field
+ $fields = new IndexFieldOptionsArray();
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
+ $this->setFields($fields);
+
+ // Set this configuration key to true so that search() queries on dynamic fields
+ // will use the 'Default Search Analyzer' when the generated field name
+ // has no explicit analyzer configuration.
+ $this->getConfiguration()[self::USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS] = "true";
+ }
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```php
+ /** @var array $results */
+ $results = $session->advanced()
+ ->documentQuery(Product::class, Products_ByLocalizedDescription::class)
+ ->search("Description_English", "north wind")
+ ->toList();
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
+
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
+
+
-
-{`class Products_ByProductType extends AbstractIndexCreationTask
+```php
+class Products_ByLocalizedDescription extends AbstractIndexCreationTask
{
public function __construct()
{
parent::__construct();
- // Call 'CreateField' to generate the dynamic-index-fields
- // The field name will be the value of document field 'ProductType'
- // The field terms will be derived from document field 'PricePerUnit'
- $this->map = "docs.Products.Select(p => new { " .
- " _ = this.CreateField(p.productType, p.pricePerUnit) " .
- "})";
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
+
+ $this->storeAllFields(FieldStorage::no());
+
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ $this->analyze("Description_English", "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Products_ByProductType_JS extends AbstractJavaScriptIndexCreationTask
+
+```php
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
{
public function __construct()
{
parent::__construct();
$this->setMaps([
- "map('Products', function (p) {
+ "map('Products', function (product) {
return {
- _: createField(p.ProductType, p.PricePerUnit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
]);
- }
-}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Products_ByProductType::class)
-// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-->whereEquals("Electronics", 23)
-->toList();
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
-
-
-
-## Example - list
-
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
+ // Apply a storage default to every generated field +
+ // Configure an analyzer for a known generated dynamic field name
+ // ==============================================================
+ $fields = new IndexFieldOptionsArray();
-
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
-* **The document**:
-
-
-{`class Product
-\{
- public ?string $id = null;
- public ?string $name = null;
-
- // For each element in this list, the VALUE of property 'PropName' will be dynamically indexed
- // e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields
- public ?AttributeList $attributes = null;
-
- // ... getters and setters
-\}
-
-class Attribute
-\{
- public ?string $propName = null;
- public ?string $propValue = null;
-
- // ... getters and setters
-\}
-
-class AttributeList extends TypedList
-\{
- protected function __construct()
- \{
- parent::__construct(Attribute::class);
- \}
-\}
-`}
-
-
+ $englishFieldOptions = new IndexFieldOptions();
+ $englishFieldOptions->setAnalyzer("StopAnalyzer");
+ $fields->offsetSet("Description_English", $englishFieldOptions);
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
+ $this->setFields($fields);
+ }
+}
+```
+
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `width` will be a dynamic-index-field.
+#### Configure a fallback analyzer for all fields
-
+
-
-{`class Attributes_ByName extends AbstractIndexCreationTask
+```php
+class Products_ByLocalizedDescription extends AbstractIndexCreationTask
{
public function __construct()
{
parent::__construct();
- // Define the dynamic-index-fields by calling CreateField
- // A dynamic-index-field will be generated for each item in the Attributes list
+ $this->map =
+ "from product in docs.Products " .
+ "select new { " .
+ " _ = product.descriptions.Select(x => " .
+ " CreateField(" .
+ " \"Description_\" + x.Key, " .
+ " x.Value, " .
+ " new CreateFieldOptions { " .
+ " Indexing = FieldIndexing.Search, " .
+ " Storage = FieldStorage.No " .
+ " })) " .
+ "}";
- // For each item, the field name will be the value of field 'PropName'
- // The field terms will be derived from field 'PropValue'
+ $this->storeAllFields(FieldStorage::no());
- $this->map =
- "docs.Products.Select(p => new { " .
- " _ = p.attributes.Select(item => this.CreateField(item.propName, item.propValue)), " .
- " Name = p.name " .
- "})";
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ $this->analyze(DocumentsIndexingFields::ALL_FIELDS, "StopAnalyzer");
}
}
-`}
-
+```
-
-
-{`class Attributes_ByName_JS extends AbstractJavaScriptIndexCreationTask
+
+```php
+class Products_ByLocalizedDescription_JS extends AbstractJavaScriptIndexCreationTask
{
public function __construct()
{
parent::__construct();
$this->setMaps([
- "map('Products', function (p) {
+ "map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.descriptions)
+ .map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})"
]);
+
+ // Use this as a fallback for fields that do not have
+ // their own explicit analyzer configuration
+ // ==================================================
+ $fields = new IndexFieldOptionsArray();
+ $allFieldsOptions = new IndexFieldOptions();
+ $allFieldsOptions->setStorage(FieldStorage::no());
+ $allFieldsOptions->setAnalyzer("StopAnalyzer");
+ $fields->offsetSet(DocumentsIndexingFields::ALL_FIELDS, $allFieldsOptions);
+ $this->setFields($fields);
}
}
-`}
-
-
-
-
-* **The query**:
- To get all documents matching a specific attribute property use:
-
-
-
-{`/** @var array $matchingDocuments */
-$matchingDocuments = $session
- ->advanced()
- ->documentQuery(Product::class, Attributes_ByName::class)
- // 'Width' is a dynamic-index-field that was indexed from the Attributes list
- ->whereEquals("Width", 10)
- ->toList();
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+The following applies when a `search()` query targets a **dynamic field**:
-## CreateField syntax
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `$this->analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `$this->analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
-
-
-{`object CreateField(string name, object value);
+
+
+
+
+
+
+#### Syntax for LINQ-index:
+
+
+```php
+object CreateField(string name, object value);
object CreateField(string name, object value, bool stored, bool analyzed);
object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+```
-| Parameters | Type | Description |
-|------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **name** | `string` | Name of the dynamic-index-field |
-| **value** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`False` - will set `FieldStorage.NO` (default value)
`True` - will set `FieldStorate.YES` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`None` - `FieldIndexing.Default` (default value)
`False` - `FieldIndexing.Exact`
`True` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+#### Syntax for JavaScript-index:
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
-| **Storage** | `FieldStorage` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing` | |
-| **TermVector** | `FieldTermVector` | |
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
+
+
+| Parameters | Type | Description |
+|----------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage::no()` (default value)
`true` - will set `FieldStorage::yes()` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing::default()` (default value)
`false` - `FieldIndexing::exact()`
`true` - `FieldIndexing::search()` |
+| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
+| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -544,17 +976,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
-
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).
+

-
+

-
-
-
-
+
+
diff --git a/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-python.mdx b/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-python.mdx
index 69514a29e2..6862d18067 100644
--- a/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-python.mdx
+++ b/versioned_docs/version-7.1/indexes/content/_using-dynamic-fields-python.mdx
@@ -1,490 +1,886 @@
import Admonition from '@theme/Admonition';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
-import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
-* In RavenDB different documents can have different shapes.
- Documents are schemaless - new fields can be added or removed as needed.
-
-* For such dynamic data, you can define indexes with **dynamic-index-fields**.
-
-* This allows querying the index on fields that aren't yet known at index creation time,
- which is very useful when working on highly dynamic systems.
-
-* Any value type can be indexed, string, number, date, etc.
-
-* An index definition can contain both dynamic-index-fields and regular-index-fields.
-
-* In this page:
-
- * [Indexing documents fields KEYS](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-keys)
- * [Example - index any field under object](../../indexes/using-dynamic-fields.mdx#example---index-any-field-under-object)
- * [Example - index any field](../../indexes/using-dynamic-fields.mdx#example---index-any-field)
- * [Indexing documents fields VALUES](../../indexes/using-dynamic-fields.mdx#indexing-documents-fields-values)
- * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
- * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
- * [CreateField syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
- * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields--terms-view)
+* In RavenDB, different documents can have different shapes.
+ Documents are schemaless - new fields can be added or removed as needed.
+ For such dynamic data, you can define indexes with **dynamic-index-fields**.
+
+* Dynamic-index-fields are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time,
+ which is very useful when working with highly dynamic systems.
+
+* Any value type can be indexed, string, number, date, etc.
+ An index definition can contain both dynamic-index-fields and regular-index-fields.
+
+* In this article:
+ * [Indexing field KEYS](../../indexes/using-dynamic-fields.mdx#indexing-field-keys)
+ * [Example - index every field under an object](../../indexes/using-dynamic-fields.mdx#example---index-every-field-under-an-object)
+ * [Example - index every field](../../indexes/using-dynamic-fields.mdx#example---index-every-field)
+ * [Indexing field VALUES](../../indexes/using-dynamic-fields.mdx#indexing-field-values)
+ * [Example - basic](../../indexes/using-dynamic-fields.mdx#example---basic)
+ * [Example - list](../../indexes/using-dynamic-fields.mdx#example---list)
+ * [Indexing dynamic fields for full-text search](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ * [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields)
+ * [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ * [`CreateField` syntax](../../indexes/using-dynamic-fields.mdx#createfield-syntax)
+ * [Indexed fields & terms view](../../indexes/using-dynamic-fields.mdx#indexed-fields-terms-view)
-## Indexing documents fields KEYS
-
-## Example - index any field under object
+
-
-
-* Index any field that is under the some object from the document.
-* After index is deployed, any new field added to the this object will be indexed as well.
+
+
+### Example - index every field under an object
+
+The following example allows you to:
+ * Index any field that is under the same object from the document.
+ * After index is deployed, any new field added to this object will be indexed as well.
* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, attributes: Dict[str, object] = None):
- self.Id = Id
-
- # The KEYS under the Attributes object will be dynamically indexed
- # Fields added to this object after index creation time will also get indexed
- self.attributes = attributes
-`}
-
-
-
-
-{`// Sample document content
-\{
- "Attributes": \{
- "Color": "Red",
- "Size": 42
- \}
-\}
-`}
-
-
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, Attributes: Dict[str, object] = None):
+ self.Id = Id
+
+ # The KEYS under the Attributes object will be dynamically indexed
+ # Fields added to this object after index creation time will also get indexed
+ self.Attributes = Attributes
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Attributes": {
+ "Color": "Red",
+ "Size": 42
+ }
+ }
+ ```
+
* **The index**:
- The below index will index any field under the `Attributes` object from the document,
+
+ The following index will index any field under the `Attributes` object from the document,
a dynamic-index-field will be created for each such field.
New fields added to the object after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the attribute field **key**.
- E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAttributeKey(AbstractIndexCreationTask):
- def __init__(self):
- super().__init__()
- self.map = (
- "from p in docs.Products select new {"
- "_ = p.attributes.Select(item => CreateField(item.Key, item.Value))"
- "}"
- )
-`}
-
-
-
-
-{`class Products_ByAttributeKey_JS(AbstractJavaScriptIndexCreationTask):
- def __init__(self):
- super().__init__()
- self.maps = {
- """
- map('Products', function (p) {
- return {
- _: Object.keys(p.attributes).map(key => createField(key, p.attributes[key],
- { indexing: 'Search', storage: true, termVector: null }))
- };
- })
- """
- }
-`}
-
-
-
-
+ The actual dynamic-index-field name on which you can query will be the attribute field **key**.
+ E.g., Keys `Color` & `Size` will become the actual dynamic-index-fields.
+
+
+
+ ```python
+ class Products_ByAttributeKey(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from p in docs.Products select new { "
+ # Call 'CreateField' to generate dynamic-index-fields
+ # from the Attributes object keys.
+
+ # Using '_' is just a convention.
+ # Any other string can be used instead of '_'
+
+ # The actual field name will be 'item.Key'
+ # The actual field terms will be derived from 'item.Value'
+ "_ = p.Attributes.Select(item => CreateField(item.Key, item.Value)) "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Products_ByAttributeKey_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // The field name will be the key
+ // The field terms will be derived from the corresponding value
+ _: Object.keys(p.Attributes)
+ .map(key => createField(key, p.Attributes[key]))
+ };
+ })
+ """
+ ]
+ ```
+
+
* **The query**:
- * You can now query the generated dynamic-index fields.
- * To get all documents with some 'size' use:
-
-
-
-{`matching_documents = list(
- session.query_index_type(Products_ByAttributeKey, Product)
- # 'size' is a dynamic-index-field that was indexed from the attributes object
- .where_equals("size", 42)
-)
-`}
-
-
-
-
-{`// 'Size' is a dynamic-index-field that was indexed from the Attributes object
-from index 'Products/ByAttributeKey' where Size = 42
-`}
-
-
-
-
-## Example - index any field
-
-
+
+ You can now query the generated dynamic-index fields.
+ The `_` property is Not queryable but used only in the index definition syntax.
+
+ To get all documents with a specific _Size_ use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByAttributeKey, Product)
+ # 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ .where_equals("Size", 42)
+ )
+ ```
+
+
+ ```sql
+ // 'Size' is a dynamic-index-field that was indexed from the Attributes object
+ from index 'Products/ByAttributeKey' where Size = 42
+ ```
+
+
+
+
+ Dynamic index fields are queried with _document_query_ or _RQL_ because the field names (e.g. `Size`, `Color`)
+ are generated at indexing time and are not properties on the _Product_ class.
+
+ Use the string-based `where_equals("Size", 42)` or RQL `where Size = 42`.
+
+
+
+
+
+
+### Example - index every field
+
+The following example allows you to:
* Define an index on a collection **without** needing any common structure between the indexed documents.
- * After index is deployed, any new field added to the document will be indexed as well.
-
+ * After the index is deployed, any new field added to any document in the collection will be indexed as well.
-
+
-Consider whether this is really necessary, as indexing every single field can end up costing time and disk space.
+* Use this approach with care.
+* Indexing every field can increase indexing time, memory usage, and disk space,
+ especially for large or frequently updated documents.
* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, first_name: str = None, last_name: str = None, title: str = None):
- self.Id = Id
-
- # All KEYS in the document will be dynamically indexes
- # Fields added to the document after index creation time wil also get indexed
- self.first_name = first_name
- self.last_name = last_name
- self.title = title
- # ...
-`}
-
-
-
-
-
-{`// Sample document content
- \{
+
+
+ ```python
+ class Product:
+ def __init__(
+ self,
+ Id: str = None,
+ FirstName: str = None,
+ LastName: str = None,
+ Title: str = None,
+ ):
+ self.Id = Id
+
+ # All KEYS in the document will be dynamically indexed
+ # Fields added to the document after index creation time will also get indexed
+ self.FirstName = FirstName
+ self.LastName = LastName
+ self.Title = Title
+ # ...
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
"FirstName": "John",
"LastName": "Doe",
"Title": "Engineer",
// ...
-\}
-`}
-
-
+ }
+ ```
+
* **The index**:
- The below index will index any field from the document,
+
+ The following index will index any field from the document,
a dynamic-index-field will be created for each field.
New fields added to the document after index creation time will be dynamically indexed as well.
- The actual dynamic-index-field name on which you can query will be the field **key**.
- E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
-
-
-
-
-{`class Products_ByAnyField_JS(AbstractJavaScriptIndexCreationTask):
- def __init__(self):
- super().__init__()
- # This will index EVERY FIELD under the top level of the document
- self.maps = {
- """
- map('Products', function (p) {
- return {
- _: Object.keys(p).map(key => createField(key, p[key],
- { indexing: 'Search', storage: true, termVector: null }))
- }
- })
- """
- }
-`}
-
-
-
+ The actual dynamic-index-field name on which you can query will be the field **key**.
+ E.g., Keys `FirstName` & `LastName` will become the actual dynamic-index-fields.
+
+ The example uses a JavaScript index because it enumerates all top-level document fields at indexing time with `Object.keys(...)`.
+ LINQ indexes typically create dynamic fields from a known enumerable structure, such as a dictionary or collection.
+
+
+
+ ```python
+ class Products_ByAnyField_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ # This will index EVERY FIELD under the top level of the document
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ _: Object.keys(p).map(key => createField(key, p[key]))
+ };
+ })
+ """
+ ]
+ ```
+
+
* **The query**:
- * To get all documents with some 'LastName' use:
-
-
-
-{`# 'last_name' is a dynamic-index-field that was indexed from the document
-matching_documents = list(
- session.query_index_type(Products_ByAnyField_JS, Product).where_equals("last_name", "Doe")
-)
-`}
-
-
-
-
-{`// 'LastName' is a dynamic-index-field that was indexed from the document
-from index 'Products/ByAnyField/JS' where LastName = "Doe"
-`}
-
-
-
+
+ To get all documents with a specific _LastName_ use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByAnyField_JS, Product)
+ # 'LastName' is a dynamic-index-field that was indexed from the document
+ .where_equals("LastName", "Doe")
+ )
+ ```
+
+
+ ```sql
+ // 'LastName' is a dynamic-index-field that was indexed from the document
+ from index 'Products/ByAnyField/JS' where LastName = "Doe"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+### Example - basic
+
+
+The following example shows:
+ * Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
+ * Documents can then be queried based on those indexed values.
+ * For a more practical usage see the [Example](../../indexes/using-dynamic-fields.mdx#example---list) below.
+
+
+* **The document**:
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, ProductType: str = None, PricePerUnit: int = None):
+ self.Id = Id
+
+ # The VALUE of ProductType will be dynamically indexed
+ self.ProductType = ProductType
+ self.PricePerUnit = PricePerUnit
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "ProductType": "Electronics",
+ "PricePerUnit": 23
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will index the **value** of document field 'ProductType'.
+
+ This value will be the dynamic-index-field name on which you can query.
+ E.g., Field value `Electronics` will be the dynamic-index-field.
+
+
+
+ ```python
+ class Products_ByProductType(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from p in docs.Products select new { "
+ # Call 'CreateField' to generate the dynamic-index-fields
+ # The field name will be the value of document field 'ProductType'
+ # The field terms will be derived from document field 'PricePerUnit'
+ "_ = CreateField(p.ProductType, p.PricePerUnit) "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Products_ByProductType_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // The field name will be the value of document field 'ProductType'
+ // The field terms will be derived from document field 'PricePerUnit'
+ _: createField(p.ProductType, p.PricePerUnit)
+ };
+ })
+ """
+ ]
+ ```
+
+
+
+* **The query**:
+
+ To get all documents of some product type having a specific price per unit use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByProductType, Product)
+ # 'Electronics' is the dynamic-index-field that was indexed
+ # from document field 'ProductType'
+ .where_equals("Electronics", 23)
+ )
+ ```
+
+
+ ```sql
+ // 'Electronics' is the dynamic-index-field that was indexed
+ // from document field 'ProductType'
+ from index 'Products/ByProductType' where Electronics = 23
+ ```
+
+
+
+
+
+
+
+### Example - list
+
+
+The following example allows you to:
+ * Index **values** from items in a list
+ * After index is deployed, any item added to this list in the document will be dynamically indexed as well.
+
+
+* **The document**:
+
+
+ ```python
+ class Attribute:
+ def __init__(self, PropName: str = None, PropValue: str = None):
+ self.PropName = PropName
+ self.PropValue = PropValue
+
+
+ class Product:
+ def __init__(self, Id: str = None, Name: str = None, Attributes: List[Attribute] = None):
+ self.Id = Id
+ self.Name = Name
+
+ # For each element in this list,
+ # the VALUE of property 'PropName' will be dynamically indexed.
+ # e.g. Color, Width, Length (in ex. below) will become dynamic-index-fields.
+ self.Attributes = Attributes
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Name": "SomeName",
+ "Attributes": [
+ {
+ "PropName": "Color",
+ "PropValue": "Blue"
+ },
+ {
+ "PropName": "Width",
+ "PropValue": "10"
+ },
+ {
+ "PropName": "Length",
+ "PropValue": "20"
+ },
+ // ...
+ ]
+ }
+ ```
+
+
+* **The index**:
+
+ The following index will create a dynamic-index-field per item in the document's `Attributes` list.
+ New items added to the Attributes list after index creation time will be dynamically indexed as well.
+
+ The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
+ E.g., 'PropName' value `Width` will be a dynamic-index-field.
+
+
+
+ ```python
+ class Attributes_ByName(AbstractIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from a in docs.Products select new { "
+ # Define the dynamic-index-fields by calling 'CreateField'
+ # A dynamic-index-field will be generated for each item in 'Attributes'
+
+ # For each item, the field name will be the value of field 'PropName'
+ # The field terms will be derived from field 'PropValue'
+ "_ = a.Attributes.Select(item => CreateField(item.PropName, item.PropValue)), "
+
+ # A regular index field can be defined as well:
+ "Name = a.Name "
+ "}"
+ )
+ ```
+
+
+ ```python
+ class Attributes_ByName_JS(AbstractJavaScriptIndexCreationTask):
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (p) {
+ return {
+ // For each item,
+ // the field name will be the value of field 'PropName'
+ // The field terms will be derived from field 'PropValue'
+ _: p.Attributes.map(item => createField(item.PropName, item.PropValue)),
+
+ // A regular index field can be defined as well:
+ Name: p.Name
+ };
+ })
+ """
+ ]
+ ```
+
+
+
+* **The query**:
+
+ To get all documents matching a specific attribute property use:
+
+
+
+ ```python
+ matching_documents = list(
+ session.advanced
+ .document_query_from_index_type(Attributes_ByName, Product)
+ # 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ .where_equals("Width", 10)
+ )
+ ```
+
+
+ ```sql
+ // 'Width' is a dynamic-index-field that was indexed from the Attributes list
+ from index 'Attributes/ByName' where Width = 10
+ ```
+
+
+
+
+
+
+
+
+
+
+
+Dynamic fields can be indexed for [Full-text search](../../indexes/querying/searching.mdx) by setting `FieldIndexing.Search` in `CreateFieldOptions`.
+* **At indexing time**:
+ At indexing time, RavenDB analyzes the dynamic field value and creates the indexed terms.
+ The analyzer used at indexing time is resolved from the index definition.
+ You can configure an analyzer for a specific generated field name, or configure `ALL_FIELDS` as a fallback.
+ See [Configuring analyzers for dynamic fields](../../indexes/using-dynamic-fields.mdx#configuring-analyzers-for-dynamic-fields) below.
+ * If the generated dynamic field name has an explicit analyzer configuration, that analyzer is used.
+ * Otherwise, if `ALL_FIELDS` has an analyzer configuration, RavenDB uses it as a fallback.
+ * If no analyzer is configured for the field, RavenDB uses the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
-## Indexing documents fields VALUES
+* **At querying time**:
+ For full-text search to return the expected results, the analyzer used at indexing time and the analyzer used for the query term should produce compatible terms.
-## Example - basic
+ When a `search()` query targets a dynamic field that does **not** have an explicit analyzer configuration for its generated field name,
+ RavenDB uses the [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) to analyze the query term by default.
-
+ Set the [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
+ configuration key to `true` to make RavenDB use the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) as the fallback analyzer for the query term instead.
-* Only the **basic concept** of creating a dynamic-index-field from the **value** of a document field.
-* Documents can then be queried based on those indexed values.
+ This configuration can be set at different scopes: server-wide, per database, or per index.
+ The example below sets it at the index scope, in the index definition.
+
+ For a summary of how RavenDB resolves the analyzer used for the query term,
+ see [Which analyzer is used for the query term](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term) below.
+
+---
+
+The following example indexes localized product descriptions as dynamic fields and queries one of those generated fields using full-text search:
+
+* **The document**:
+
+
+ ```python
+ class Product:
+ def __init__(self, Id: str = None, Descriptions: Dict[str, str] = None):
+ self.Id = Id
+ self.Descriptions = Descriptions
+ ```
+
+
+
+ ```json
+ // Sample document content
+ {
+ "Descriptions": {
+ "English": "North wind jacket",
+ "French": "Veste vent du nord"
+ }
+ }
+ ```
+
-* **The document**:
-
-
-{`class Product:
- def __init__(self, Id: str = None, product_type: str = None, price_per_unit: float = None):
- self.Id = Id
-
- # The VALUE of ProductType will be dynamically indexed
- self.product_type = product_type
- self.price_per_unit = price_per_unit
-`}
-
-
+* **The index**:
-
-
-{`// Sample document content
-\{
- "ProductType": "Electronics",
- "PricePerUnit": 23
-\}
-`}
-
-
+ The following index creates one dynamic field for each entry in the `Descriptions` dictionary.
+ For example, the key `English` creates the dynamic field `Description_English`.
-* **The index**:
- The below index will index the **value** of document field 'ProductType'.
-
- This value will be the dynamic-index-field name on which you can query.
- E.g., Field value `Electronics` will be the dynamic-index-field.
+ Each generated dynamic field is indexed for **full-text search**.
+
+
+
+ ```python
+ class Products_ByLocalizedDescription(AbstractIndexCreationTask):
+ USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS = (
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery"
+ )
+
+ def __init__(self):
+ super().__init__()
+ self.map = (
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ # Index each generated dynamic field for FTS
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
+ "}"
+ )
+
+ self._store_all_fields(FieldStorage.NO)
+
+ # Set this configuration key to true so that search() queries on dynamic fields
+ # will use the 'Default Search Analyzer' when the generated field name
+ # has no explicit analyzer configuration.
+ self.configuration = {
+ Products_ByLocalizedDescription.USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS: "true"
+ }
+ ```
+
+
+ ```python
+ class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
+ USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS = (
+ "Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery"
+ )
+
+ def __init__(self):
+ super().__init__()
+ self.maps = [
+ """
+ map('Products', function (product) {
+ return {
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ // Index each generated dynamic field for FTS
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
+ };
+ })
+ """
+ ]
+
+ # Apply a storage default to every generated field
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO)
+ }
+
+ # Set this configuration key to true so that search() queries on dynamic fields
+ # will use the 'Default Search Analyzer' when the generated field name
+ # has no explicit analyzer configuration.
+ self.configuration = {
+ Products_ByLocalizedDescription_JS.USE_SEARCH_ANALYZER_FOR_DYNAMIC_FIELDS: "true"
+ }
+ ```
+
+
+
+* **Full-text search query**:
+
+ Query the generated dynamic field by its field name.
+
+ In this example, the query targets the generated field `Description_English`.
+
+ Since `Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery` is set to `true`,
+ the searched term `"north wind"` is analyzed with the [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer).
+
+
+
+ ```python
+ results = list(
+ session.advanced
+ .document_query_from_index_type(Products_ByLocalizedDescription, Product)
+ .search("Description_English", "north wind")
+ )
+ ```
+
+
+
+ ```sql
+ from index "Products/ByLocalizedDescription"
+ where search(Description_English, "north wind")
+ ```
+
+
+
+---
+
+
+
+### Configuring analyzers for dynamic fields
+
+`CreateFieldOptions` does **not** let you specify a custom analyzer directly.
+However, you can still configure which analyzer RavenDB will use for dynamic fields in the index definition by either:
+
+* Configuring an analyzer for a specific generated dynamic field name.
+* Configuring `ALL_FIELDS` as a fallback for fields that do not have their own explicit analyzer configuration.
+
+Use `ALL_FIELDS` with care, since it can affect any field that does not have its own explicit analyzer configuration.
+
+---
+
+#### Configure analyzer for a specific dynamic field
-
-{`class Products_ByProductType(AbstractIndexCreationTask):
+```python
+class Products_ByLocalizedDescription(AbstractIndexCreationTask):
def __init__(self):
super().__init__()
+ self.map = (
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
+ "}"
+ )
- # Call 'CreateField' to generate the dynamic-index-fields
- # The field name will be the value of document field 'product_type'
- # The field terms will be derived from document field 'price_per_unit'
- self.map = "from p in docs.Products select new { _ = CreateField(p.product_type, p.price_per_unit)}"
-`}
-
+ self._store_all_fields(FieldStorage.NO)
+
+ # Configure an analyzer for a known generated dynamic field name
+ # ==============================================================
+ self._analyze("Description_English", "StopAnalyzer")
+```
-
-
-{`class Products_ByProductType_JS(AbstractJavaScriptIndexCreationTask):
+
+```python
+class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
def __init__(self):
super().__init__()
- self.maps = {
+ self.maps = [
"""
- map('Products', function (p) {
+ map('Products', function (product) {
return {
- _: createField(p.product_type, p.price_per_unit,
- { indexing: 'Search', storage: true, termVector: null })
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})
"""
+ ]
+
+ # Configure an analyzer for a known generated dynamic field name
+ # ==============================================================
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO),
+ "Description_English":
+ IndexFieldOptions(analyzer="StopAnalyzer")
}
-`}
-
-
-
-
-* **The query**:
- * To get all documents of some product type having a specific price per unit use:
-
-
-
-{`# 'electronics' is the dynamic-index-field that was indexed from the document 'product_type'
-matching_documents = list(
- session.advanced.document_query_from_index_type(Products_ByProductType, Product).where_equals(
- "electronics", 23
- )
-)
-`}
-
-
-
-
-{`// 'Electronics' is the dynamic-index-field that was indexed from document field 'ProductType'
-from index 'Products/ByProductType' where Electronics = 23
-`}
-
+```
-## Example - list
-
-
-
-* Index **values** from items in a list
-* After index is deployed, any item added this list in the document will be dynamically indexed as well.
-
-
-
-* **The document**:
-
-
-{`class Attribute:
- def __init__(self, prop_name: str = None, prop_value: str = None):
- self.prop_name = prop_name
- self.prop_value = prop_value
-
-
-class Product:
- def __init__(self, Id: str = None, name: str = None, attributes: List[Attribute] = None):
- self.Id = Id
- self.name = name
- # For each element in this list, the VALUE of property 'prop_name' will be dynamically indexed
- # e.g. color, width, length (in ex. below) will become dynamic-index-field
- self.attributes = attributes
-`}
-
-
-
-
-
-{`// Sample document content
-\{
-Name": "SomeName",
-Attributes": [
- \{
- "PropName": "Color",
- "PropValue": "Blue"
- \},
- \{
- "PropName": "Width",
- "PropValue": "10"
- \},
- \{
- "PropName": "Length",
- "PropValue": "20"
- \},
- ...
-
-\}
-`}
-
-
-
-* **The index**:
- The below index will create a dynamic-index-field per item in the document's `Attributes` list.
- New items added to the Attributes list after index creation time will be dynamically indexed as well.
-
- The actual dynamic-index-field name on which you can query will be the item's PropName **value**.
- E.g., 'PropName' value `width` will be a dynamic-index-field.
+#### Configure a fallback analyzer for all fields
-
-{`class Attributes_ByName(AbstractIndexCreationTask):
+```python
+class Products_ByLocalizedDescription(AbstractIndexCreationTask):
def __init__(self):
super().__init__()
self.map = (
- "from a in docs.Products select new "
- "{ _ = a.attributes.Select( item => CreateField(item.prop_name, item.prop_value)), name = a.name "
+ "from product in docs.Products select new { "
+ " _ = product.Descriptions.Select(x => "
+ " CreateField("
+ " \"Description_\" + x.Key, "
+ " x.Value, "
+ " new CreateFieldOptions { "
+ " Indexing = FieldIndexing.Search, "
+ " Storage = FieldStorage.No "
+ " })) "
"}"
)
-`}
-
+
+ self._store_all_fields(FieldStorage.NO)
+
+ # Use this as a fallback for fields that do not have
+ # their own explicit analyzer configuration
+ # ==================================================
+ self._analyze(constants.Documents.Indexing.Fields.ALL_FIELDS, "StopAnalyzer")
+```
-
-
-{`class Attributes_ByName_JS(AbstractJavaScriptIndexCreationTask):
+
+```python
+class Products_ByLocalizedDescription_JS(AbstractJavaScriptIndexCreationTask):
def __init__(self):
super().__init__()
- self.maps = {
+ self.maps = [
"""
- map('Products', function (p) {
+ map('Products', function (product) {
return {
- _: p.Attributes.map(item => createField(item.PropName, item.PropValue,
- { indexing: 'Search', storage: true, termVector: null })),
- Name: p.Name
+ _: Object.keys(product.Descriptions).map(function (key) {
+ return createField(
+ 'Description_' + key,
+ product.Descriptions[key],
+ {
+ indexing: 'Search',
+ storage: 'No'
+ });
+ })
};
})
"""
+ ]
+
+ # Use this as a fallback for fields that do not have
+ # their own explicit analyzer configuration
+ # ==================================================
+ self.fields = {
+ constants.Documents.Indexing.Fields.ALL_FIELDS:
+ IndexFieldOptions(storage=FieldStorage.NO, analyzer="StopAnalyzer")
}
-`}
-
-
-
-
-* **The query**:
- To get all documents matching a specific attribute property use:
-
-
-
-{`matching_documents = list(
- session.advanced.document_query_from_index_type(Attributes_ByName, Product).where_equals(
- "width", 10
- )
-)
-`}
-
-
-
-
-{`// 'Width' is a dynamic-index-field that was indexed from the Attributes list
-from index 'Attributes/ByName' where Width = 10
-`}
-
+```
+
+
+
+
+### Which analyzer is used for the query term?
+
+The following applies when a `search()` query targets a **dynamic field**:
+
+| Index configuration | [Configuration key](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery) | Analyzer used for the query term |
+| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
+| No analyzer is explicitly configured for the generated field name | `false` | The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) |
+| No analyzer is explicitly configured for the generated field name | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `false` | The analyzer resolved by the normal field fallback path,
e.g. `WhitespaceAnalyzer` |
+| `ALL_FIELDS` is configured with a specific analyzer,
e.g. `WhitespaceAnalyzer` | `true` | The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) |
+| The generated field name is explicitly configured,
e.g. `self._analyze("Description_English", "StopAnalyzer")` | `false` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+| The generated field name is explicitly configured,
e.g. `self._analyze("Description_English", "StopAnalyzer")` | `true` | The explicitly configured analyzer,
e.g. `StopAnalyzer` |
+
+
+
-## CreateField syntax
+
#### Syntax for Index:
-
-
-{`object CreateField(string name, object value);
+
+```python
+CreateField(name, value)
-object CreateField(string name, object value, bool stored, bool analyzed);
+CreateField(name, value, stored, analyzed)
-object CreateField(string name, object value, CreateFieldOptions options);
-`}
-
+CreateField(name, value, CreateFieldOptions)
+```
#### Syntax for JavaScript-index:
-
-
-{`createField(fieldName, fieldValue, options); // returns object
-`}
-
+
+```js
+createField(fieldName, fieldValue, options); // returns object
+```
-| Parameters | Type | Description |
-|------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| **name** | `string` | Name of the dynamic-index-field |
-| **value** | `object` | Value of the dynamic-index-field
The field Terms are derived from this value. |
-| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`False` - will set `FieldStorage.NO` (default value)
`True` - will set `FieldStorate.YES` |
-| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`None` - `FieldIndexing.Default` (default value)
`False` - `FieldIndexing.Exact`
`True` - `FieldIndexing.Search` |
-| **options** | `CreateFieldOptions` | Dynamic-index-field options |
+| Parameters | Type | Description |
+|----------------|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **fieldName** | `string` | Name of the dynamic-index-field |
+| **fieldValue** | `object` | Value of the dynamic-index-field
The field terms are derived from this value. |
+| **stored** | `bool` | Sets [FieldStorage](../../indexes/storing-data-in-index.mdx)
`false` - will set `FieldStorage.No` (default value)
`true` - will set `FieldStorage.Yes` |
+| **analyzed** | `bool` | Sets [FieldIndexing](../../indexes/using-analyzers.mdx)
`null` - `FieldIndexing.Default` (default value)
`false` - `FieldIndexing.Exact`
`true` - `FieldIndexing.Search` |
+| **options** | `CreateFieldOptions` | Dynamic-index-field options |
-| CreateFieldOptions | | |
-|--------------------|--------------------|----------------------------------------------------------------------------|
+| CreateFieldOptions | | |
+|--------------------|--------------------|-----------------------------------------------------------------------------------|
| **Storage** | `FieldStorage?` | Learn about [storing data](../../indexes/storing-data-in-index.mdx) in the index. |
-| **Indexing** | `FieldIndexing?` | Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
-| **TermVector** | `FieldTermVector?` | Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
+| **Indexing** | `FieldIndexing?` | Sets the field indexing behavior.
Learn about [using analyzers](../../indexes/using-analyzers.mdx) in the index. |
+| **TermVector** | `FieldTermVector?` | Sets the field term-vector behavior.
Learn about [term vectors](../../indexes/using-term-vectors.mdx) in the index. |
@@ -496,17 +892,15 @@ object CreateField(string name, object value, CreateFieldOptions options);
+
+
+
-
-## Indexed fields & terms view
-
-The generated dynamic-index-fields and their indexed terms can be viewed in the **Terms View**.
-Below are sample index fields & their terms generated from the last example.
+The generated dynamic index fields and their indexed terms can be viewed in the **Terms View** in Studio.
+Below are sample index fields & their terms generated from [this example](../../indexes/using-dynamic-fields.mdx#example---list).


-
-
-
-
+
+
diff --git a/versioned_docs/version-7.1/indexes/querying/content/_searching-csharp.mdx b/versioned_docs/version-7.1/indexes/querying/content/_searching-csharp.mdx
index d20ef5a65e..f0be0e6ffd 100644
--- a/versioned_docs/version-7.1/indexes/querying/content/_searching-csharp.mdx
+++ b/versioned_docs/version-7.1/indexes/querying/content/_searching-csharp.mdx
@@ -16,11 +16,13 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
* [Searching with wildcards](../../../indexes/querying/searching.mdx#searching-with-wildcards)
* [When using RavenStandardAnalyzer or StandardAnalyzer or NGramAnalyzer](../../../indexes/querying/searching.mdx#when-usingoror)
@@ -28,6 +30,7 @@ import CodeBlock from '@theme/CodeBlock';
* [When using the Exact analyzer](../../../indexes/querying/searching.mdx#when-using-the-exact-analyzer)
+
## Indexing single field for FTS
#### The index:
@@ -262,7 +265,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly,
+* To search across ALL fields in a document without defining each one explicitly,
use the `AsJson` method in the _Map_ function to extract all property values and index them in a single searchable field.
* This approach makes the index robust to changes in the document schema.
@@ -377,7 +380,14 @@ where search(AllValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/versioned_docs/version-7.1/indexes/querying/content/_searching-java.mdx b/versioned_docs/version-7.1/indexes/querying/content/_searching-java.mdx
index 7d85246ced..4accf3f512 100644
--- a/versioned_docs/version-7.1/indexes/querying/content/_searching-java.mdx
+++ b/versioned_docs/version-7.1/indexes/querying/content/_searching-java.mdx
@@ -388,4 +388,11 @@ where search(allValues, "tofu")
+## Indexing dynamic fields for FTS
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
\ No newline at end of file
diff --git a/versioned_docs/version-7.1/indexes/querying/content/_searching-nodejs.mdx b/versioned_docs/version-7.1/indexes/querying/content/_searching-nodejs.mdx
index 4ca66b5877..cb73bfd7c0 100644
--- a/versioned_docs/version-7.1/indexes/querying/content/_searching-nodejs.mdx
+++ b/versioned_docs/version-7.1/indexes/querying/content/_searching-nodejs.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,11 +17,13 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
* [Searching with wildcards](../../../indexes/querying/searching.mdx#searching-with-wildcards)
* [When using RavenStandardAnalyzer or StandardAnalyzer or NGramAnalyzer](../../../indexes/querying/searching.mdx#when-usingoror)
@@ -29,6 +31,7 @@ import CodeBlock from '@theme/CodeBlock';
* [When using the Exact analyzer](../../../indexes/querying/searching.mdx#when-using-the-exact-analyzer)
+
## Indexing single field for FTS
#### The index:
@@ -163,7 +166,7 @@ where (search(employeeData, "Manager") or search(employeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available when using **a C# LINQ string** that is assigned to the `map` property in the Node.js index class,
as shown in the example below.
@@ -229,6 +232,14 @@ where search(AllValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/versioned_docs/version-7.1/indexes/querying/content/_searching-php.mdx b/versioned_docs/version-7.1/indexes/querying/content/_searching-php.mdx
index 55261ce19f..510a6f8752 100644
--- a/versioned_docs/version-7.1/indexes/querying/content/_searching-php.mdx
+++ b/versioned_docs/version-7.1/indexes/querying/content/_searching-php.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,14 +17,17 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
+
## Indexing single field for FTS
#### The index:
@@ -253,7 +256,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available in the **C# LINQ string** that is assigned to the `map` property in the PHP index class,
as shown in the example below.
@@ -332,6 +335,15 @@ where search(allValues, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
+
## Boosting search results
diff --git a/versioned_docs/version-7.1/indexes/querying/content/_searching-python.mdx b/versioned_docs/version-7.1/indexes/querying/content/_searching-python.mdx
index f06c29d94f..88c6aa452f 100644
--- a/versioned_docs/version-7.1/indexes/querying/content/_searching-python.mdx
+++ b/versioned_docs/version-7.1/indexes/querying/content/_searching-python.mdx
@@ -5,7 +5,7 @@ import CodeBlock from '@theme/CodeBlock';
-* Prior to reading this article, please refer to [full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
+* Prior to reading this article, please refer to [Full-Text search with dynamic queries](../../../client-api/session/querying/text-search/full-text-search.mdx)
to learn about the `search` method.
* **All capabilities** provided by `search` with a dynamic query can also be used when querying a static-index.
@@ -17,14 +17,17 @@ import CodeBlock from '@theme/CodeBlock';
See examples below.
* You can configure which analyzer will be used to tokenize this field.
- See [selecting an analyzer](../../../indexes/using-analyzers.mdx#selecting-an-analyzer-for-a-field).
+ Learn more in [Setting analyzer for index-field](../../../indexes/using-analyzers.mdx#setting-analyzer-for-index-field).
+
* In this article:
* [Indexing single field for FTS](../../../indexes/querying/searching.mdx#indexing-single-field-for-fts)
* [Indexing multiple fields for FTS](../../../indexes/querying/searching.mdx#indexing-multiple-fields-for-fts)
- * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-(using-asjson))
+ * [Indexing all fields for FTS (using AsJson)](../../../indexes/querying/searching.mdx#indexing-all-fields-for-fts-using-asjson)
+ * [Indexing dynamic fields for FTS](../../../indexes/querying/searching.mdx#indexing-dynamic-fields-for-fts)
* [Boosting search results](../../../indexes/querying/searching.mdx#boosting-search-results)
+
## Indexing single field for FTS
#### The index:
@@ -167,7 +170,7 @@ where (search(EmployeeData, "Manager") or search(EmployeeData, "French Spanish",
## Indexing all fields for FTS (using AsJson)
-* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
+* To search across ALL fields in a document without defining each one explicitly, use the `AsJson` method,
which is available in the **C# LINQ string** that is assigned to the `map` property in the Python index class,
as shown in the example below.
@@ -238,6 +241,14 @@ where search(all_values, "tofu")
+## Indexing dynamic fields for FTS
+
+* [Dynamic index fields](../../../indexes/using-dynamic-fields.mdx) are created at indexing time, with names and values derived from document content,
+ rather than being predefined as fixed index fields in the index definition.
+ This allows you to query the index by fields that are not known at index definition or deployment time.
+
+* Dynamic index fields can be configured for full-text search just like regular index fields.
+ Learn more in [Indexing dynamic fields for full-text search](../../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search).
## Boosting search results
diff --git a/versioned_docs/version-7.1/indexes/using-dynamic-fields.mdx b/versioned_docs/version-7.1/indexes/using-dynamic-fields.mdx
index 7e6fe3a7ca..e465ba5431 100644
--- a/versioned_docs/version-7.1/indexes/using-dynamic-fields.mdx
+++ b/versioned_docs/version-7.1/indexes/using-dynamic-fields.mdx
@@ -1,6 +1,7 @@
---
-title: "Indexes: Dynamic Index Fields"
-sidebar_label: Dynamic Fields
+title: "Dynamic Index Fields"
+sidebar_label: "Dynamic Index Fields"
+description: "Index document fields dynamically in RavenDB when field names are unknown at index definition time, using the CreateField method."
sidebar_position: 27
supported_languages: ["csharp", "java", "python", "php", "nodejs"]
see_also:
@@ -31,7 +32,6 @@ import UsingDynamicFieldsPython from './content/_using-dynamic-fields-python.mdx
import UsingDynamicFieldsPhp from './content/_using-dynamic-fields-php.mdx';
import UsingDynamicFieldsNodejs from './content/_using-dynamic-fields-nodejs.mdx';
-
diff --git a/versioned_docs/version-7.1/server/configuration/indexing-configuration.mdx b/versioned_docs/version-7.1/server/configuration/indexing-configuration.mdx
index 2e1f67f6a6..3ff0ff574f 100644
--- a/versioned_docs/version-7.1/server/configuration/indexing-configuration.mdx
+++ b/versioned_docs/version-7.1/server/configuration/indexing-configuration.mdx
@@ -103,6 +103,7 @@ import LanguageContent from "@site/src/components/LanguageContent";
[Indexing.OrderByTicksAutomaticallyWhenDatesAreInvolved](../../server/configuration/indexing-configuration.mdx#indexingorderbyticksautomaticallywhendatesareinvolved)
[Indexing.QueryClauseCache.Disabled](../../server/configuration/indexing-configuration.mdx#indexingqueryclausecachedisabled)
[Indexing.QueryClauseCache.RepeatedQueriesTimeFrameInSec](../../server/configuration/indexing-configuration.mdx#indexingqueryclausecacherepeatedqueriestimeframeinsec)
+ [Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery](../../server/configuration/indexing-configuration.mdx#indexingqueryingusesearchanalyzerfordynamicfieldsifnotsetexplicitlyinsearchquery)
[Indexing.ScratchSpaceLimitInMb](../../server/configuration/indexing-configuration.mdx#indexingscratchspacelimitinmb)
[Indexing.Static.SearchEngineType](../../server/configuration/indexing-configuration.mdx#indexingstaticsearchenginetype)
[Indexing.Throttling.TimeIntervalInMs](../../server/configuration/indexing-configuration.mdx#indexingthrottlingtimeintervalinms)
@@ -1008,6 +1009,33 @@ Queries that repeat within this time frame will be considered worth caching.
+## Indexing.Querying.UseSearchAnalyzerForDynamicFieldsIfNotSetExplicitlyInSearchQuery
+
+* This setting controls which analyzer is used for the **query term** when a **`search()` query** targets a [Dynamic index field](../../indexes/using-dynamic-fields.mdx#indexing-dynamic-fields-for-full-text-search)
+ that was indexed for full-text search, and no analyzer is explicitly configured for that field in the index definition.
+
+ * `false` (default):
+ The [Default analyzer](../../indexes/using-analyzers.mdx#using-the-default-analyzer) is used to analyze the **query term**.
+ This analyzer can be configured via the [Indexing.Analyzers.Default](../../server/configuration/indexing-configuration.mdx#indexinganalyzersdefault) configuration key.
+
+ * `true`:
+ The [Default search analyzer](../../indexes/using-analyzers.mdx#using-the-default-search-analyzer) is used to analyze the **query term**.
+ This analyzer can be configured via the [Indexing.Analyzers.Search.Default](../../server/configuration/indexing-configuration.mdx#indexinganalyzerssearchdefault) configuration key.
+
+* See the table in [Which analyzer is used for the query term?](../../indexes/using-dynamic-fields.mdx#which-analyzer-is-used-for-the-query-term)
+ for the complete analyzer-selection rules based on this configuration key and the analyzer configured for the dynamic index field.
+
+* This configuration applies to both the Lucene and Corax search engines.
+ The default is `false` to preserve backward compatibility.
+
+---
+
+- **Type**: `bool`
+- **Default**: `false`
+- **Scope**: Server-wide, or per database, or per index
+
+
+
## Indexing.ScratchSpaceLimitInMb
* Amount of scratch space in megabytes that we allow to use for the index storage.