🚨 Announcing Vendure v2 Beta

ElasticsearchOptions

ElasticsearchOptions

Configuration options for the ElasticsearchPlugin.

Signature

interface ElasticsearchOptions {
  host?: string;
  port?: number;
  connectionAttempts?: number;
  connectionAttemptInterval?: number;
  clientOptions?: ClientOptions;
  indexPrefix?: string;
  indexSettings?: object;
  indexMappingProperties?: {
        [indexName: string]: object;
    };
  batchSize?: number;
  searchConfig?: SearchConfig;
  customProductMappings?: {
        [fieldName: string]: CustomMapping<[Product, ProductVariant[], LanguageCode]>;
    };
  customProductVariantMappings?: {
        [fieldName: string]: CustomMapping<[ProductVariant, LanguageCode]>;
    };
  bufferUpdates?: boolean;
  hydrateProductRelations?: Array<EntityRelationPaths<Product>>;
  hydrateProductVariantRelations?: Array<EntityRelationPaths<ProductVariant>>;
  extendSearchInputType?: {
        [name: string]: PrimitiveTypeVariations<GraphQlPrimitive>;
    };
  extendSearchSortType?: string[];
}

Members

host

property
type:
string
default:
'http://localhost'
The host of the Elasticsearch server. May also be specified in clientOptions.node.

port

property
type:
number
default:
9200
The port of the Elasticsearch server. May also be specified in clientOptions.node.

connectionAttempts

property
type:
number
default:
10
Maximum amount of attempts made to connect to the ElasticSearch server on startup.

connectionAttemptInterval

property
type:
number
default:
5000
Interval in milliseconds between attempts to connect to the ElasticSearch server on startup.

clientOptions

property
type:
ClientOptions
Options to pass directly to the Elasticsearch Node.js client. For example, to set authentication or other more advanced options. Note that if the node or nodes option is specified, it will override the values provided in the host and port options.

indexPrefix

property
type:
string
default:
'vendure-'
Prefix for the indices created by the plugin.

indexSettings

property
v1.2.0
type:
object
default:
{}

These options are directly passed to index settings. To apply some settings indices will be recreated.

Example

// Configuring an English stemmer
indexSettings: {
  analysis: {
    analyzer: {
      custom_analyzer: {
        tokenizer: 'standard',
        filter: [
          'lowercase',
          'english_stemmer'
        ]
      }
    },
    filter : {
      english_stemmer : {
        type : 'stemmer',
        name : 'english'
      }
    }
  }
},

A more complete example can be found in the discussion thread How to make elastic plugin to search by substring with stemming.

indexMappingProperties

property
v1.2.0
type:
{ [indexName: string]: object; }
default:
{}

This option allow to redefine or define new properties in mapping. More about elastic mapping After changing this option indices will be recreated.

Example

// Configuring custom analyzer for the `productName` field.
indexMappingProperties: {
  productName: {
    type: 'text',
    analyzer:'custom_analyzer',
    fields: {
      keyword: {
        type: 'keyword',
        ignore_above: 256,
      }
    }
  }
}

To reference a field defined by customProductMappings or customProductVariantMappings, you will need to prefix the name with 'product-<name>' or 'variant-<name>' respectively, e.g.:

Example

customProductMappings: {
   variantCount: {
       graphQlType: 'Int!',
       valueFn: (product, variants) => variants.length,
   },
},
indexMappingProperties: {
  'product-variantCount': {
    type: 'integer',
  }
}

batchSize

property
type:
number
default:
2000
Batch size for bulk operations (e.g. when rebuilding the indices).

searchConfig

property
type:
SearchConfig
Configuration of the internal Elasticsearch query.

customProductMappings

property
type:
{ [fieldName: string]: CustomMapping<[Product, ProductVariant[], LanguageCode]>; }

Custom mappings may be defined which will add the defined data to the Elasticsearch index and expose that data via the SearchResult GraphQL type, adding a new customMappings, customProductMappings & customProductVariantMappings fields.

The graphQlType property may be one of String, Int, Float, Boolean, ID or list versions thereof ([String!] etc) and can be appended with a ! to indicate non-nullable fields.

The public (default = true) property is used to reveal or hide the property in the GraphQL API schema. If this property is set to false it’s not accessible in the customMappings field but it’s still getting parsed to the elasticsearch index.

This config option defines custom mappings which are accessible when the “groupByProduct” input options is set to true. In addition, custom variant mappings can be accessed by using the customProductVariantMappings field, which is always available.

Example

customProductMappings: {
   variantCount: {
       graphQlType: 'Int!',
       valueFn: (product, variants) => variants.length,
   },
   reviewRating: {
       graphQlType: 'Float',
       public: true,
       valueFn: product => (product.customFields as any).reviewRating,
   },
   priority: {
       graphQlType: 'Int!',
       public: false,
       valueFn: product => (product.customFields as any).priority,
   },
}

Example

query SearchProducts($input: SearchInput!) {
    search(input: $input) {
        totalItems
        items {
            productId
            productName
            customProductMappings {
                variantCount
                reviewRating
            }
            customMappings {
                ...on CustomProductMappings {
                    variantCount
                    reviewRating
                }
            }
        }
    }
}

customProductVariantMappings

property
type:
{ [fieldName: string]: CustomMapping<[ProductVariant, LanguageCode]>; }

This config option defines custom mappings which are accessible when the “groupByProduct” input options is set to false. In addition, custom product mappings can be accessed by using the customProductMappings field, which is always available.

Example

query SearchProducts($input: SearchInput!) {
    search(input: $input) {
        totalItems
        items {
            productId
            productName
            customProductVariantMappings {
                weight
            }
            customMappings {
                ...on CustomProductVariantMappings {
                    weight
                }
            }
        }
    }
}

bufferUpdates

property
v1.3.0
type:
boolean
default:
false

If set to true, updates to Products, ProductVariants and Collections will not immediately trigger an update to the search index. Instead, all these changes will be buffered and will only be run via a call to the runPendingSearchIndexUpdates mutation in the Admin API.

This is very useful for installations with a large number of ProductVariants and/or Collections, as the buffering allows better control over when these expensive jobs are run, and also performs optimizations to minimize the amount of work that needs to be performed by the worker.

hydrateProductRelations

property
v1.3.0
default:
[]

Additional product relations that will be fetched from DB while reindexing. This can be used in combination with customProductMappings to ensure that the required relations are joined before the product object is passed to the valueFn.

Example

{
  hydrateProductRelations: ['assets.asset'],
  customProductMappings: {
    assetPreviews: {
      graphQlType: '[String!]',
      // Here we can be sure that the `product.assets` array is populated
      // with an Asset object
      valueFn: (product) => product.assets.map(a => a.asset.preview),
    }
  }
}

hydrateProductVariantRelations

property
v1.3.0
default:
[]
Additional variant relations that will be fetched from DB while reindexing. See hydrateProductRelations for more explanation and a usage example.

extendSearchInputType

property
v1.3.0
type:
{ [name: string]: PrimitiveTypeVariations<GraphQlPrimitive>; }
default:
{}

Allows the SearchInput type to be extended with new input fields. This allows arbitrary data to be passed in, which can then be used e.g. in the mapQuery() function or custom scriptFields functions.

Example

extendSearchInputType: {
  longitude: 'Float',
  latitude: 'Float',
  radius: 'Float',
}

This allows the search query to include these new fields:

Example

query {
  search(input: {
    longitude: 101.7117,
    latitude: 3.1584,
    radius: 50.00
  }) {
    items {
      productName
    }
  }
}

extendSearchSortType

property
v1.4.0
type:
string[]
default:
[]

Adds a list of sort parameters. This is mostly important to make the correct sort order values available inside input parameter of the mapSort option.

Example

extendSearchSortType: ["distance"]

will extend the SearchResultSortParameter input type like this:

Example

extend input SearchResultSortParameter {
     distance: SortOrder
}

SearchConfig

Configuration options for the internal Elasticsearch query which is generated when performing a search.

Signature

interface SearchConfig {
  facetValueMaxSize?: number;
  collectionMaxSize?: number;
  totalItemsMaxSize?: number | boolean;
  multiMatchType?: 'best_fields' | 'most_fields' | 'cross_fields' | 'phrase' | 'phrase_prefix' | 'bool_prefix';
  boostFields?: BoostFieldsConfig;
  priceRangeBucketInterval?: number;
  mapQuery?: (
        query: any,
        input: ElasticSearchInput,
        searchConfig: DeepRequired<SearchConfig>,
        channelId: ID,
        enabledOnly: boolean,
    ) => any;
  scriptFields?: { [fieldName: string]: CustomScriptMapping<[ElasticSearchInput]> };
  mapSort?: (sort: ElasticSearchSortInput, input: ElasticSearchInput) => ElasticSearchSortInput;
}

Members

facetValueMaxSize

property
type:
number
default:
50
The maximum number of FacetValues to return from the search query. Internally, this value sets the “size” property of an Elasticsearch aggregation.

collectionMaxSize

property
v1.1.0
type:
number
default:
50
The maximum number of Collections to return from the search query. Internally, this value sets the “size” property of an Elasticsearch aggregation.

totalItemsMaxSize

property
v1.2.0
type:
number | boolean
default:
10000
The maximum number of totalItems to return from the search query. Internally, this value sets the “track_total_hits” property of an Elasticsearch query. If this parameter is set to “True”, accurate count of totalItems will be returned. If this parameter is set to “False”, totalItems will be returned as 0. If this parameter is set to integer, accurate count of totalItems will be returned not bigger than integer.

multiMatchType

property
type:
'best_fields' | 'most_fields' | 'cross_fields' | 'phrase' | 'phrase_prefix' | 'bool_prefix'
default:
'best_fields'
Defines the multi match type used when matching against a search term.

boostFields

property
Set custom boost values for particular fields when matching against a search term.

priceRangeBucketInterval

property
type:
number

The interval used to group search results into buckets according to price range. For example, setting this to 2000 will group into buckets every $20.00:

{
  "data": {
    "search": {
      "totalItems": 32,
      "priceRange": {
        "buckets": [
          {
            "to": 2000,
            "count": 21
          },
          {
            "to": 4000,
            "count": 7
          },
          {
            "to": 6000,
            "count": 3
          },
          {
            "to": 12000,
            "count": 1
          }
        ]
      }
    }
  }
}

mapQuery

property
type:
( query: any, input: ElasticSearchInput, searchConfig: DeepRequired<SearchConfig>, channelId: ID, enabledOnly: boolean, ) => any

This config option allows the the modification of the whole (already built) search query. This allows for e.g. wildcard / fuzzy searches on the index.

Example

mapQuery: (query, input, searchConfig, channelId, enabledOnly){
  if(query.bool.must){
    delete query.bool.must;
  }
  query.bool.should = [
    {
      query_string: {
        query: "*" + term + "*",
        fields: [
          `productName^${searchConfig.boostFields.productName}`,
          `productVariantName^${searchConfig.boostFields.productVariantName}`,
        ]
      }
    },
    {
      multi_match: {
        query: term,
        type: searchConfig.multiMatchType,
        fields: [
          `description^${searchConfig.boostFields.description}`,
          `sku^${searchConfig.boostFields.sku}`,
        ],
      },
    },
  ];

  return query;
}

scriptFields

property
v1.3.0
type:
{ [fieldName: string]: CustomScriptMapping<[ElasticSearchInput]> }

Sets script_fields inside the elasticsearch body which allows returning a script evaluation for each hit.

The script field definition consists of three properties:

  • graphQlType: This is the type that will be returned when this script field is queried via the GraphQL API. It may be one of String, Int, Float, Boolean, ID or list versions thereof ([String!] etc) and can be appended with a ! to indicate non-nullable fields.
  • context: determines whether this script field is available when grouping by product. Can be product, variant or both.
  • scriptFn: This is the function to run on each hit. Should return an object with a script property, as covered in the Elasticsearch script fields docs

Example

extendSearchInputType: {
  latitude: 'Float',
  longitude: 'Float',
},
indexMappingProperties: {
  // The `product-location` field corresponds to the `location` customProductMapping
  // defined below. Here we specify that it would be index as a `geo_point` type,
  // which will allow us to perform geo-spacial calculations on it in our script field.
  'product-location': {
    type: 'geo_point', // contains function arcDistance
  },
},
customProductMappings: {
  location: {
    graphQlType: 'String',
    valueFn: (product: Product) => {
      // Assume that the Product entity has this customField defined
      const custom = product.customFields.location;
      return `${custom.latitude},${custom.longitude}`;
    },
  }
},
searchConfig: {
  scriptFields: {
    distance: {
      graphQlType: 'Float!',
      // Run this script only when grouping results by product
      context: 'product',
      scriptFn: (input) => {
        // The SearchInput was extended with latitude and longitude
        // via the `extendSearchInputType` option above.
        const lat = input.latitude;
        const lon = input.longitude;
        return {
          script: `doc['product-location'].arcDistance(${lat}, ${lon})`,
        }
      }
    }
  }
}

mapSort

property
v1.4.0
type:
(sort: ElasticSearchSortInput, input: ElasticSearchInput) => ElasticSearchSortInput
default:
{}

Allows extending the sort input of the elasticsearch body as covered in Elasticsearch sort docs

The sort input parameter contains the ElasticSearchSortInput generated for the default sort parameters “name” and “price”. If neither of those are applied it will be empty.

Example

mapSort: (sort, input) => {
    // Assuming `extendSearchSortType: ["priority"]`
    // Assuming priority is never undefined
    const { priority } = input.sort;
    return [
         ...sort,
         {
             // The `product-priority` field corresponds to the `priority` customProductMapping
             // Depending on the index type, this field might require a
             // more detailed input (example: 'productName.keyword')
             ["product-priority"]: {
                 order: priority === SortOrder.ASC ? 'asc' : 'desc'
             }
         }
     ];
}

A more generic example would be a sort function based on a product location like this:

Example

extendSearchInputType: {
  latitude: 'Float',
  longitude: 'Float',
},
extendSearchSortType: ["distance"],
indexMappingProperties: {
  // The `product-location` field corresponds to the `location` customProductMapping
  // defined below. Here we specify that it would be index as a `geo_point` type,
  // which will allow us to perform geo-spacial calculations on it in our script field.
  'product-location': {
    type: 'geo_point',
  },
},
customProductMappings: {
  location: {
    graphQlType: 'String',
    valueFn: (product: Product) => {
      // Assume that the Product entity has this customField defined
      const custom = product.customFields.location;
      return `${custom.latitude},${custom.longitude}`;
    },
  }
},
searchConfig: {
     mapSort: (sort, input) => {
         // Assuming distance is never undefined
         const { distance } = input.sort;
         return [
             ...sort,
             {
                 ["_geo_distance"]: {
                     "product-location": [
                         input.longitude,
                         input.latitude
                     ],
                     order: distance === SortOrder.ASC ? 'asc' : 'desc',
                     unit: "km"
                 }
             }
         ];
     }
}

BoostFieldsConfig

Configuration for boosting the scores of given fields when performing a search against a term.

Boosting a field acts as a score multiplier for matches against that field.

Signature

interface BoostFieldsConfig {
  productName?: number;
  productVariantName?: number;
  description?: number;
  sku?: number;
}

Members

productName

property
type:
number
default:
1
Defines the boost factor for the productName field.

productVariantName

property
type:
number
default:
1
Defines the boost factor for the productVariantName field.

description

property
type:
number
default:
1
Defines the boost factor for the description field.

sku

property
type:
number
default:
1
Defines the boost factor for the sku field.