<commit_before>import getFunctionScores from './elasticsearch/score'
import getMultiMatchConfig from './elasticsearch/multimatch'
import getBoosts from './elasticsearch/boost'
import getMapping from './elasticsearch/mapping'
import cloneDeep from 'lodash-es/cloneDeep'
import config from 'config'

export async function prepareElasticsearchQueryBody (searchQuery) {
  const bodybuilder = await import(/* webpackChunkName: "bodybuilder" */ 'bodybuilder')
  const optionsPrfeix = '_options'
  const queryText = searchQuery.getSearchText()
  const rangeOperators = ['gt', 'lt', 'gte', 'lte', 'moreq', 'from', 'to']
  let query = bodybuilder.default()

  // process applied filters
  const appliedFilters = cloneDeep(searchQuery.getAppliedFilters()) // copy as function below modifies the object
  if (appliedFilters.length > 0) {
    let hasCatalogFilters = false

    // apply default filters
    appliedFilters.forEach(filter => {
      if (filter.scope === 'default') {
        if (Object.keys(filter.value).every(v => rangeOperators.includes(v))) {
          // process range filters
          query = query.filter('range', filter.attribute, filter.value)
        } else {
          // process terms filters
          filter.value = filter.value[Object.keys(filter.value)[0]]
          if (!Array.isArray(filter.value)) {
            filter.value = [filter.value]
          }
          query = query.filter('terms', getMapping(filter.attribute), filter.value)
        }
      } else if (filter.scope === 'catalog') {
        hasCatalogFilters = true
      }
    })

    // apply catalog scope filters
    let attrFilterBuilder = (filterQr, attrPostfix = '') => {
      appliedFilters.forEach(catalogfilter => {
        const valueKeys = Object.keys(catalogfilter.value)
        if (catalogfilter.scope === 'catalog' && valueKeys.length) {
          const isRange = valueKeys.filter(value => rangeOperators.indexOf(value) !== -1)
          if (isRange.length) {
            let rangeAttribute = catalogfilter.attribute
            // filter by product fiunal price
            if (rangeAttribute === 'price') {
              rangeAttribute = 'final_price'
            }
            // process range filters
            filterQr = filterQr.andFilter('range', rangeAttribute, catalogfilter.value)
          } else {
            // process terms filters
            let newValue = catalogfilter.value[Object.keys(catalogfilter.value)[0]]
            if (!Array.isArray(newValue)) {
              newValue = [newValue]
            }
            if (attrPostfix === '') {
              filterQr = filterQr.andFilter('terms', getMapping(catalogfilter.attribute), newValue)
            } else {
              filterQr = filterQr.andFilter('terms', catalogfilter.attribute + attrPostfix, newValue)
            }
          }
        }
      })
      return filterQr
    }

    if (hasCatalogFilters) {
      query = query.orFilter('bool', (b) => attrFilterBuilder(b))
        .orFilter('bool', (b) => attrFilterBuilder(b, optionsPrfeix).filter('match', 'type_id', 'configurable')) // the queries can vary based on the product type
    }
  }

  // Add aggregations for catalog filters
  const allFilters = searchQuery.getAvailableFilters()
  if (allFilters.length > 0) {
    for (let attrToFilter of allFilters) {
      if (attrToFilter.scope === 'catalog') {
        if (attrToFilter.field !== 'price') {
          let aggregationSize = { size: config.products.filterAggregationSize[attrToFilter.field] || config.products.filterAggregationSize.default }
          query = query.aggregation('terms', getMapping(attrToFilter.field), aggregationSize)
          query = query.aggregation('terms', attrToFilter.field + optionsPrfeix, aggregationSize)
        } else {
          query = query.aggregation('terms', attrToFilter.field)
          query.aggregation('range', 'price', config.products.priceFilters)
        }
      }
    }
  }
  // Get searchable fields based on user-defined config.
  let getQueryBody = function (b) {
    let searchableAttributes = config.elasticsearch.hasOwnProperty('searchableAttributes') ? config.elasticsearch.searchableAttributes : {'name': {'boost': 1}}
    let searchableFields = [
    ]
    for (const attribute of Object.keys(searchableAttributes)) {
      searchableFields.push(attribute + '^' + getBoosts(attribute))
    }
    return b.orQuery('multi_match', 'fields', searchableFields, getMultiMatchConfig(queryText))<commit_msg>Fixed typo mistake<commit_after>import getFunctionScores from './elasticsearch/score'
import getMultiMatchConfig from './elasticsearch/multimatch'
import getBoosts from './elasticsearch/boost'
import getMapping from './elasticsearch/mapping'
import cloneDeep from 'lodash-es/cloneDeep'
import config from 'config'

export async function prepareElasticsearchQueryBody (searchQuery) {
  const bodybuilder = await import(/* webpackChunkName: "bodybuilder" */ 'bodybuilder')
  const optionsPrefix = '_options'
  const queryText = searchQuery.getSearchText()
  const rangeOperators = ['gt', 'lt', 'gte', 'lte', 'moreq', 'from', 'to']
  let query = bodybuilder.default()

  // process applied filters
  const appliedFilters = cloneDeep(searchQuery.getAppliedFilters()) // copy as function below modifies the object
  if (appliedFilters.length > 0) {
    let hasCatalogFilters = false

    // apply default filters
    appliedFilters.forEach(filter => {
      if (filter.scope === 'default') {
        if (Object.keys(filter.value).every(v => rangeOperators.includes(v))) {
          // process range filters
          query = query.filter('range', filter.attribute, filter.value)
        } else {
          // process terms filters
          filter.value = filter.value[Object.keys(filter.value)[0]]
          if (!Array.isArray(filter.value)) {
            filter.value = [filter.value]
          }
          query = query.filter('terms', getMapping(filter.attribute), filter.value)
        }
      } else if (filter.scope === 'catalog') {
        hasCatalogFilters = true
      }
    })

    // apply catalog scope filters
    let attrFilterBuilder = (filterQr, attrPostfix = '') => {
      appliedFilters.forEach(catalogfilter => {
        const valueKeys = Object.keys(catalogfilter.value)
        if (catalogfilter.scope === 'catalog' && valueKeys.length) {
          const isRange = valueKeys.filter(value => rangeOperators.indexOf(value) !== -1)
          if (isRange.length) {
            let rangeAttribute = catalogfilter.attribute
            // filter by product fiunal price
            if (rangeAttribute === 'price') {
              rangeAttribute = 'final_price'
            }
            // process range filters
            filterQr = filterQr.andFilter('range', rangeAttribute, catalogfilter.value)
          } else {
            // process terms filters
            let newValue = catalogfilter.value[Object.keys(catalogfilter.value)[0]]
            if (!Array.isArray(newValue)) {
              newValue = [newValue]
            }
            if (attrPostfix === '') {
              filterQr = filterQr.andFilter('terms', getMapping(catalogfilter.attribute), newValue)
            } else {
              filterQr = filterQr.andFilter('terms', catalogfilter.attribute + attrPostfix, newValue)
            }
          }
        }
      })
      return filterQr
    }

    if (hasCatalogFilters) {
      query = query.orFilter('bool', (b) => attrFilterBuilder(b))
        .orFilter('bool', (b) => attrFilterBuilder(b, optionsPrefix).filter('match', 'type_id', 'configurable')) // the queries can vary based on the product type
    }
  }

  // Add aggregations for catalog filters
  const allFilters = searchQuery.getAvailableFilters()
  if (allFilters.length > 0) {
    for (let attrToFilter of allFilters) {
      if (attrToFilter.scope === 'catalog') {
        if (attrToFilter.field !== 'price') {
          let aggregationSize = { size: config.products.filterAggregationSize[attrToFilter.field] || config.products.filterAggregationSize.default }
          query = query.aggregation('terms', getMapping(attrToFilter.field), aggregationSize)
          query = query.aggregation('terms', attrToFilter.field + optionsPrefix, aggregationSize)
        } else {
          query = query.aggregation('terms', attrToFilter.field)
          query.aggregation('range', 'price', config.products.priceFilters)
        }
      }
    }
  }
  // Get searchable fields based on user-defined config.
  let getQueryBody = function (b) {
    let searchableAttributes = config.elasticsearch.hasOwnProperty('searchableAttributes') ? config.elasticsearch.searchableAttributes : {'name': {'boost': 1}}
    let searchableFields = [
    ]
    for (const attribute of Object.keys(searchableAttributes)) {
      searchableFields.push(attribute + '^' + getBoosts(attribute))
    }
    return b.orQuery('multi_match', 'fields', searchableFields, getMultiMatchConfig(queryText))
{'fraction_non_alphanumeric': 0.1188474044175356, 'fraction_numerical': 0.0013454423141607804, 'mean_word_length': 2.8732088580112896, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '669158', 'n_tokens_mistral': 2386, 'n_tokens_neox': 2397, 'n_words': 549}