diff --git includes/callback_add_aggregation.inc includes/callback_add_aggregation.inc
new file mode 100644
index 0000000..3082f18
--- /dev/null
+++ includes/callback_add_aggregation.inc
@@ -0,0 +1,307 @@
+<?php
+
+/**
+ * Search API data alteration callback that adds an URL field for all items.
+ */
+class SearchApiAlterAddAggregation extends SearchApiAbstractAlterCallback {
+
+  public function configurationForm() {
+    // Workaround for http://drupal.org/node/1015798
+    $form['#attached']['css'][] = drupal_get_path('module', 'search_api') . '/search_api.admin.css';
+
+    $fields = empty($this->index->options['fields']) ? _search_api_admin_get_fields($this->index, $this->index->entityWrapper()) : $this->index->options;
+    $fields = $fields['fields'];
+    $field_options = array();
+    foreach ($fields as $name => $field) {
+      $field_options[$name] = $field['name'];
+    }
+    $additional = empty($this->options['fields']) ? array() : $this->options['fields'];
+
+    $types = $this->getTypes();
+    $type_descriptions = $this->getTypes('description');
+    $tmp = array();
+    foreach ($types as $type => $name) {
+      $tmp[$type] = array(
+        '#type' => 'item',
+        '#description' => $type_descriptions[$type],
+      );
+    }
+    $type_descriptions = $tmp;
+
+    $form['#id'] = 'edit-callbacks-search-api-alter-add-aggregation-settings';
+    $form['description'] = array(
+      '#markup' => t('<p>This data alteration lets you define additional fields that will be added to this index. ' .
+        'Each of these new fields will be an aggregation of one or more existing fields.</p>' .
+        '<p>To add a new aggregated field, click the "Add new field" button and then fill out the form.</p>' .
+        '<p>To remove a previously defined field, click the "Remove field" button.</p>' .
+        '<p>You can also change the names or contained fields of existing aggregated fields.</p>'),
+    );
+    $form['fields']['#prefix'] = '<div id="search-api-alter-add-aggregation-field-settings">';
+    $form['fields']['#suffix'] = '</div>';
+    if (isset($this->changes)) {
+      $form['fields']['#prefix'] .= '<div class="messages warning">All changes in the form will not be saved until the <em>Save configuration</em> button at the form bottom is clicked.</div>';
+    }
+    foreach ($additional as $name => $field) {
+      $form['fields'][$name] = array(
+        '#type' => 'fieldset',
+        '#title' => $field['name'] ? $field['name'] : t('New field'),
+        '#collapsible' => TRUE,
+        '#collapsed' => (boolean) $field['name'],
+      );
+      $form['fields'][$name]['name'] = array(
+        '#type' => 'textfield',
+        '#title' => t('New field name'),
+        '#default_value' => $field['name'],
+        '#required' => TRUE,
+      );
+      $form['fields'][$name]['type'] = array(
+        '#type' => 'select',
+        '#title' => t('Aggregation type'),
+        '#options' => $types,
+        '#default_value' => $field['type'],
+        '#required' => TRUE,
+      );
+      $form['fields'][$name]['type_descriptions'] = $type_descriptions;
+      foreach (array_keys($types) as $type) {
+        $form['fields'][$name]['type_descriptions'][$type]['#states']['visible'][':input[name="callbacks[search_api_alter_add_aggregation][settings][fields][' . $name . '][type]"]']['value'] = $type;
+      }
+      $form['fields'][$name]['fields'] = array(
+        '#type' => 'checkboxes',
+        '#title' => t('Contained fields'),
+        '#options' => $field_options,
+        '#default_value' => $field['fields'],
+        '#attributes' => array('class' => array('search-api-alter-add-aggregation-fields')),
+        '#required' => TRUE,
+      );
+      $form['fields'][$name]['actions'] = array(
+        '#type' => 'actions',
+        'remove' => array(
+          '#type' => 'submit',
+          '#value' => t('Remove field'),
+          '#submit' => array('_search_api_add_aggregation_field_submit'),
+          '#limit_validation_errors' => array(),
+          '#name' => 'search_api_add_aggregation_remove_' . $name,
+          '#ajax' => array(
+            'callback' => '_search_api_add_aggregation_field_ajax',
+            'wrapper' => 'search-api-alter-add-aggregation-field-settings',
+          ),
+        ),
+      );
+    }
+    $form['actions']['#type'] = 'actions';
+    $form['actions']['add_field'] = array(
+      '#type' => 'submit',
+      '#value' => t('Add new field'),
+      '#submit' => array('_search_api_add_aggregation_field_submit'),
+      '#limit_validation_errors' => array(),
+      '#ajax' => array(
+        'callback' => '_search_api_add_aggregation_field_ajax',
+        'wrapper' => 'search-api-alter-add-aggregation-field-settings',
+      ),
+    );
+    return $form;
+  }
+
+  public function configurationFormValidate(array $form, array &$values, array &$form_state) {
+    if (empty($values['fields'])) {
+      return;
+    }
+    foreach ($values['fields'] as $name => $field) {
+      if ($field['name'] && !$field['fields']) {
+        form_error($form['fields'][$name]['fields'], t('You have to select at least one field to aggregate. If you want to remove an aggregated field, please delete its name.'));
+      }
+    }
+  }
+
+  public function configurationFormSubmit(array $form, array &$values, array &$form_state) {
+    if (empty($values['fields'])) {
+      return;
+    }
+    foreach ($values['fields'] as $name => $field) {
+      if (!$field['name']) {
+        unset($values['fields'][$name]);
+      }
+    }
+    $this->options = $values;
+    return $values;
+  }
+
+  public function alterItems(array &$items) {
+    if (!$items) {
+      return;
+    }
+    if (isset($this->options['fields'])) {
+      $types = $this->getTypes('type');
+      foreach ($items as $item) {
+        $wrapper = $this->index->entityWrapper($item);
+        foreach ($this->options['fields'] as $name => $field) {
+          $required_fields = array();
+          foreach ($field['fields'] as $f) {
+            if (!isset($required_fields[$f])) {
+              $required_fields[$f]['type'] = $types[$field['type']];
+            }
+          }
+          $fields = search_api_extract_fields($wrapper, $required_fields);
+          $values = array();
+          foreach ($fields as $f) {
+            if (isset($f['value'])) {
+              $values[] = $f['value'];
+            }
+          }
+          $values = $this->flattenArray($values);
+          if ($field['name']) {
+            $this->reductionType = $field['type'];
+            $item->$name = array_reduce($values, array($this, 'reduce'), NULL);
+            if ($field['type'] == 'count' && !$item->$name) {
+              $item->$name = 0;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Helper method for reducing an array to a single value.
+   */
+  public function reduce($a, $b) {
+    switch ($this->reductionType) {
+      case 'fulltext':
+        return isset($a) ? $a . "\n\n" . $b : $b;
+      case 'sum':
+        return $a + $b;
+      case 'count':
+        return $a + 1;
+      case 'max':
+        return isset($a) ? max($a, $b) : $b;
+      case 'min':
+        return isset($a) ? min($a, $b) : $b;
+      case 'first':
+        return isset($a) ? $a : $b;
+    }
+  }
+
+  /**
+   * Helper method for flattening a multi-dimensional array.
+   */
+  protected function flattenArray(array $data) {
+    $ret = array();
+    foreach ($data as $item) {
+      if (!isset($item)) {
+        continue;
+      }
+      if (is_scalar($item)) {
+        $ret[] = $item;
+      }
+      else {
+        $ret = array_merge($ret, $this->flattenArray($item));
+      }
+    }
+    return $ret;
+  }
+
+  public function propertyInfo() {
+    $types = $this->getTypes('type');
+    $ret = array();
+    if (isset($this->options['fields'])) {
+      foreach ($this->options['fields'] as $name => $field) {
+        $ret[$name] = array(
+          'label' => $field['name'],
+          'description' => $this->fieldDescription($field),
+          'type' => $types[$field['type']],
+        );
+      }
+    }
+    return $ret;
+  }
+
+  /**
+   * Helper method for creating a field description.
+   */
+  protected function fieldDescription(array $field) {
+    $fields = array();
+    foreach ($field['fields'] as $f) {
+      if ($f !== 0) {
+        $fields[] = isset($this->index->options['fields'][$f]) ? $this->index->options['fields'][$f]['name'] : $f;
+      }
+    }
+    $type = $this->getTypes();
+    $type = $type[$field['type']];
+    return t('A @type aggregation of the following fields: @fields.', array('@type' => $type, '@fields' => implode(', ', $fields)));
+  }
+
+  /**
+   * Helper method for getting all available aggregation types.
+   *
+   * @param $descriptions
+   *   If TRUE, get type descriptions instead of names.
+   */
+  protected function getTypes($info = 'name') {
+    switch ($info) {
+      case 'name':
+        return array(
+          'fulltext' => t('Fulltext'),
+          'sum' => t('Sum'),
+          'count' => t('Count'),
+          'max' => t('Maximum'),
+          'min' => t('Minimum'),
+          'first' => t('First'),
+        );
+      case 'type':
+        return array(
+          'fulltext' => 'text',
+          'sum' => 'integer',
+          'count' => 'integer',
+          'max' => 'integer',
+          'min' => 'integer',
+          'first' => 'string',
+        );
+      case 'description':
+        return array(
+          'fulltext' => t('The Fulltext aggregation concatenates the text data of all contained fields.'),
+          'sum' => t('The Sum aggregation adds the values of all contained fields numerically.'),
+          'count' => t('The Count aggregation takes the total number of contained field values as the aggregated field value.'),
+          'max' => t('The Maximum aggregation computes the numerically largest contained field value.'),
+          'min' => t('The Minimum aggregation computes the numerically smallest contained field value.'),
+          'first' => t('The First aggregation will simply keep the first encountered field value. This is helpful foremost when you know that a list field will only have a single value.'),
+        );
+    }
+  }
+
+  /**
+   * Submit helper callback for buttons in the callback's configuration form.
+   */
+  public function formButtonSubmit(array $form, array &$form_state) {
+    $button_name = $form_state['triggering_element']['#name'];
+    if ($button_name == 'op') {
+      for ($i = 1; isset($this->options['fields']['search_api_aggregation_' . $i]); ++$i) {
+      }
+      $this->options['fields']['search_api_aggregation_' . $i] = array(
+        'name' => '',
+        'type' => 'fulltext',
+        'fields' => array(),
+      );
+    }
+    else {
+      $field = substr($button_name, 31);
+      unset($this->options['fields'][$field]);
+    }
+    $form_state['rebuild'] = TRUE;
+    $this->changes = TRUE;
+  }
+
+}
+
+/**
+ * Submit function for buttons in the callback's configuration form.
+ */
+function _search_api_add_aggregation_field_submit(array $form, array &$form_state) {
+  $form_state['callbacks']['search_api_alter_add_aggregation']->formButtonSubmit($form, $form_state);
+}
+
+/**
+ * AJAX submit function for buttons in the callback's configuration form.
+ */
+function _search_api_add_aggregation_field_ajax(array $form, array &$form_state) {
+  return $form['callbacks']['settings']['search_api_alter_add_aggregation']['fields'];
+}
diff --git includes/callback_add_fulltext.inc includes/callback_add_fulltext.inc
deleted file mode 100644
index 02b5ddf..0000000
--- includes/callback_add_fulltext.inc
+++ /dev/null
@@ -1,219 +0,0 @@
-<?php
-
-/**
- * Search API data alteration callback that adds an URL field for all items.
- */
-class SearchApiAlterAddFulltext extends SearchApiAbstractAlterCallback {
-
-  public function configurationForm() {
-    // Workaround for http://drupal.org/node/1015798
-    $form['#attached']['css'][] = drupal_get_path('module', 'search_api') . '/search_api.admin.css';
-
-    $fields = empty($this->index->options['fields']) ? _search_api_admin_get_fields($this->index, $this->index->entityWrapper()) : $this->index->options;
-    $fields = $fields['fields'];
-    $field_options = array();
-    foreach ($fields as $name => $field) {
-      $field_options[$name] = $field['name'];
-    }
-    $additional = empty($this->options['fields']) ? array() : $this->options['fields'];
-
-    $form['#id'] = 'edit-callbacks-search-api-alter-add-fulltext-settings';
-    $form['description'] = array(
-      '#markup' => t('<p>This data alteration lets you define additional fields that will be added to this index. ' .
-        'Each of these new fields will be a fulltext aggregation of one or more existing fields.</p>' .
-        '<p>To add a new aggregated field, click the "Add new field" button and then fill out the form.</p>' .
-        '<p>To remove a previously defined field, click the "Remove field" button.</p>' .
-        '<p>You can also change the names or contained fields of existing aggregated fields.</p>'),
-    );
-    if (isset($this->changes)) {
-      $form['description']['#markup'] .= '<div class="messages warning">All changes in the form will not be saved until the <em>Save configuration</em> button at the form bottom is clicked.</div>';
-    }
-    $form['fields']['#prefix'] = '<div id="search-api-alter-add-fulltext-field-settings">';
-    $form['fields']['#suffix'] = '</div>';
-    foreach ($additional as $name => $field) {
-      $form['fields'][$name] = array(
-        '#type' => 'fieldset',
-        '#title' => $field['name'] ? $field['name'] : t('New field'),
-        '#collapsible' => TRUE,
-        '#collapsed' => (boolean) $field['name'],
-      );
-      $form['fields'][$name]['name'] = array(
-        '#type' => 'textfield',
-        '#title' => t('New field name'),
-        '#default_value' => $field['name'],
-        '#required' => TRUE,
-      );
-      $form['fields'][$name]['fields'] = array(
-        '#type' => 'checkboxes',
-        '#title' => t('Contained fields'),
-        '#options' => $field_options,
-        '#default_value' => $field['fields'],
-        '#attributes' => array('class' => array('search-api-alter-add-fulltext-fields')),
-        '#required' => TRUE,
-      );
-      $form['fields'][$name]['actions'] = array(
-        '#type' => 'actions',
-        'remove' => array(
-          '#type' => 'submit',
-          '#value' => t('Remove field'),
-          '#submit' => array('_search_api_add_fulltext_field_submit'),
-          '#limit_validation_errors' => array(),
-          '#name' => 'search_api_add_fulltext_remove_' . $name,
-          '#ajax' => array(
-            'callback' => '_search_api_add_fulltext_field_ajax',
-            'wrapper' => 'search-api-alter-add-fulltext-field-settings',
-          ),
-        ),
-      );
-    }
-    $form['actions']['#type'] = 'actions';
-    $form['actions']['add_field'] = array(
-      '#type' => 'submit',
-      '#value' => t('Add new field'),
-      '#submit' => array('_search_api_add_fulltext_field_submit'),
-      '#limit_validation_errors' => array(),
-      '#ajax' => array(
-        'callback' => '_search_api_add_fulltext_field_ajax',
-        'wrapper' => 'search-api-alter-add-fulltext-field-settings',
-      ),
-    );
-    return $form;
-  }
-
-  public function configurationFormValidate(array $form, array &$values, array &$form_state) {
-    if (empty($values['fields'])) {
-      return;
-    }
-    foreach ($values['fields'] as $name => $field) {
-      if ($field['name'] && !$field['fields']) {
-        form_error($form['fields'][$name]['fields'], t('You have to select at least one field to aggregate. If you want to remove an aggregated field, please delete its name.'));
-      }
-    }
-  }
-
-  public function configurationFormSubmit(array $form, array &$values, array &$form_state) {
-    if (empty($values['fields'])) {
-      return;
-    }
-    foreach ($values['fields'] as $name => $field) {
-      if (!$field['name']) {
-        unset($values['fields'][$name]);
-      }
-    }
-    $this->options = $values;
-    return $values;
-  }
-
-  public function alterItems(array &$items) {
-    if (!$items) {
-      return;
-    }
-    $required_fields = array();
-    if (isset($this->options['fields'])) {
-      foreach ($this->options['fields'] as $name => $field) {
-        foreach ($field['fields'] as $f) {
-          if (!isset($required_fields[$f])) {
-            $required_fields[$f]['type'] = 'text';
-          }
-        }
-      }
-      foreach ($items as $item) {
-        $wrapper = $this->index->entityWrapper($item);
-        $fields = search_api_extract_fields($wrapper, $required_fields);
-        foreach ($this->options['fields'] as $name => $field) {
-          if ($field['name']) {
-            $item->$name = '';
-            foreach ($field['fields'] as $f) {
-              if (isset($fields[$f]['value'])) {
-                $item->$name .= ($item->$name ? "\n\n" : '') . $this->collapseArray($fields[$f]['value']);
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  /**
-   * Helper method for collapsing array values into a string.
-   */
-  protected function collapseArray($data) {
-    if (!is_array($data)) {
-      return $data;
-    }
-    if (!$data) {
-      return '';
-    }
-    $ret = array();
-    foreach ($data as $item) {
-      $item = $this->collapseArray($item);
-      if ($item) {
-        $ret[] = $item;
-      }
-    }
-    return implode("\n", $ret);
-  }
-
-  public function propertyInfo() {
-    $ret = array();
-    if (isset($this->options['fields'])) {
-      foreach ($this->options['fields'] as $name => $field) {
-        $ret[$name] = array(
-          'label' => $field['name'],
-          'description' => $this->fieldDescription($field),
-          'type' => 'text',
-        );
-      }
-    }
-    return $ret;
-  }
-
-  /**
-   * Helper method for creating a field description.
-   */
-  protected function fieldDescription(array $field) {
-    $fields = array();
-    foreach ($field['fields'] as $f) {
-      if ($f !== 0) {
-        $fields[] = isset($this->index->options['fields'][$f]) ? $this->index->options['fields'][$f]['name'] : $f;
-      }
-    }
-    return t('A fulltext aggregation of the following fields: @fields.', array('@fields' => implode(', ', $fields)));
-  }
-
-  /**
-   * Submit helper callback for buttons in the callback's configuration form.
-   */
-  public function formButtonSubmit(array $form, array &$form_state) {
-    $button_name = $form_state['triggering_element']['#name'];
-    if ($button_name == 'op') {
-      for ($i = 1; isset($this->options['fields']['search_api_fulltext_' . $i]); ++$i) {
-      }
-      $this->options['fields']['search_api_fulltext_' . $i] = array(
-        'name' => '',
-        'fields' => $form_state['index']->getFulltextFields(),
-      );
-    }
-    else {
-      $field = substr($button_name, 31);
-      unset($this->options['fields'][$field]);
-    }
-    $form_state['rebuild'] = TRUE;
-    $this->changes = TRUE;
-  }
-
-}
-
-/**
- * Submit function for buttons in the callback's configuration form.
- */
-function _search_api_add_fulltext_field_submit(array $form, array &$form_state) {
-  $form_state['callbacks']['search_api_alter_add_fulltext']->formButtonSubmit($form, $form_state);
-}
-
-/**
- * AJAX submit function for buttons in the callback's configuration form.
- */
-function _search_api_add_fulltext_field_ajax(array $form, array &$form_state) {
-  return $form['callbacks']['settings']['search_api_alter_add_fulltext']['fields'];
-}
diff --git search_api.admin.css search_api.admin.css
index 992a578..63eb0ea 100644
--- search_api.admin.css
+++ search_api.admin.css
@@ -34,7 +34,7 @@ input.search-api-cron-limit {
   text-align: right;
 }
 
-.search-api-alter-add-fulltext-fields {
+.search-api-alter-add-aggregation-fields {
   max-height: 12em;
   overflow: auto;
 }
diff --git search_api.info search_api.info
index d067918..d444c92 100644
--- search_api.info
+++ search_api.info
@@ -7,7 +7,7 @@ package = Search
 
 files[] = search_api.test
 files[] = includes/callback.inc
-files[] = includes/callback_add_fulltext.inc
+files[] = includes/callback_add_aggregation.inc
 files[] = includes/callback_add_url.inc
 files[] = includes/callback_add_viewed_entity.inc
 files[] = includes/callback_bundle_filter.inc
diff --git search_api.install search_api.install
index 9a1412a..ebf5f5b 100644
--- search_api.install
+++ search_api.install
@@ -644,3 +644,37 @@ function search_api_update_7105() {
     }
   }
 }
+
+/**
+ * Update the settings for the "Aggregated fields" data alteration.
+ */
+function search_api_update_7106() {
+  $rows = db_select('search_api_index', 'i')
+    ->fields('i', array('id', 'options'))
+    ->execute()
+    ->fetchAllKeyed();
+  foreach ($rows as $id => $options) {
+    $opt = unserialize($options);
+    $callbacks = &$opt['data_alter_callbacks'];
+    if (isset($callbacks['search_api_alter_add_fulltext'])) {
+      $callbacks['search_api_alter_add_aggregation'] = $callbacks['search_api_alter_add_fulltext'];
+      unset($callbacks['search_api_alter_add_fulltext']);
+      if (!empty($callbacks['search_api_alter_add_aggregation']['settings']['fields'])) {
+        foreach ($callbacks['search_api_alter_add_aggregation']['settings']['fields'] as $field => &$info) {
+          if (!isset($info['type'])) {
+            $info['type'] = 'fulltext';
+          }
+        }
+      }
+    }
+    $opt = serialize($opt);
+    if ($opt != $options) {
+      db_update('search_api_index')
+        ->fields(array(
+          'options' => $opt,
+        ))
+        ->condition('id', $id)
+        ->execute();
+    }
+  }
+}
diff --git search_api.module search_api.module
index 6d93942..390c2f0 100644
--- search_api.module
+++ search_api.module
@@ -614,10 +614,10 @@ function search_api_search_api_alter_callback_info() {
     'description' => t("Adds the item's URL to the indexed data."),
     'class' => 'SearchApiAlterAddUrl',
   );
-  $callbacks['search_api_alter_add_fulltext'] = array(
-    'name' => t('Aggregated fulltext fields'),
-    'description' => t('Gives you the ability to define additional fulltext fields, containing the text data from one or more other fields.'),
-    'class' => 'SearchApiAlterAddFulltext',
+  $callbacks['search_api_alter_add_aggregation'] = array(
+    'name' => t('Aggregated fields'),
+    'description' => t('Gives you the ability to define additional fields, containing data from one or more other fields.'),
+    'class' => 'SearchApiAlterAddAggregation',
   );
   $callbacks['search_api_alter_add_viewed_entity'] = array(
     'name' => t('Complete entity view'),
