diff --git .gitignore .gitignore
new file mode 100644
index 0000000..cf4274f
--- /dev/null
+++ .gitignore
@@ -0,0 +1 @@
+SolrPhpClient
diff --git apachesolr.admin.inc apachesolr.admin.inc
index 6d6dc01..b90039e 100644
--- apachesolr.admin.inc
+++ apachesolr.admin.inc
@@ -6,7 +6,119 @@
  *   Administrative pages for the Apache Solr framework.
  */
 
-function apachesolr_settings() {
+/**
+ * Form builder for adding/editing a Solr server used as a menu callback.
+ */
+function apachesolr_server_edit_form(&$form, &$form_state, $server = NULL) {
+  if (empty($server)) {
+    $server = array('asid' => NULL, 'server_id' => '', 'name' => '', 'scheme' => NULL, 'host' => '', 'port' => '', 'path' => '', 'service_class' => '');
+  }
+
+  $form['asid'] = array(
+    '#type' => 'value',
+    '#value' => $server['asid'],
+  );
+  $form['host'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Solr host name'),
+    '#default_value' => $server['host'],
+    '#description' => t('Host name of your Solr server, e.g. <code>localhost</code> or <code>example.com</code>.'),
+    '#required' => TRUE,
+  );
+  $form['port'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Solr port'),
+    '#size' => 5,
+    '#maxlength' => 5,
+    '#default_value' => $server['port'],
+    '#description' => t('Port on which the Solr server listens. The Jetty example server is 8983, while Tomcat is 8080 by default.'),
+    '#required' => TRUE,
+  );
+  $form['path'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Solr path'),
+    '#default_value' => $server['path'],
+    '#description' => t('Path that identifies the Solr request handler to be used.'),
+    '#required' => TRUE,
+  );
+  $is_default = $server['server_id'] == variable_get('apachesolr_default_server', 'solr');
+  $form['make_default'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Make this Solr server the default'),
+    '#default_value' => $is_default,
+    '#disabled' => $is_default,
+    '#description' => $is_default ? t('Select this option for a different server to make this one non-default.') : '',
+  );
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Description'),
+    '#default_value' => $server['name'],
+    '#description' => t('Short description of your Solr server.'),
+    '#required' => TRUE,
+  );
+  $form['server_id'] = array(
+    '#type' => 'machine_name',
+    '#title' => t('Server id'),
+    '#machine_name' => array(
+      'exists' => 'apachesolr_server_id_load',
+    ),
+    '#default_value' => $server['server_id'],
+    '#description' => t('Unique, machine-readable identifier Solr server.'),
+    '#required' => TRUE,
+  );
+  $form['save'] = array(
+    '#type' => 'submit',
+    '#validate' =>array('apachesolr_server_save_validate'),
+    '#submit' =>array('apachesolr_server_save_submit'),
+    '#value' => t('Save'),
+  );
+  if (!empty($server['asid']) && !$is_default) {
+    $form['delete'] = array(
+      '#type' => 'submit',
+      '#validate' =>array('apachesolr_server_delete_validate'),
+      '#submit' =>array('apachesolr_server_delete_submit'),
+      '#value' => t('Delete'),
+    );
+  }
+  return $form;
+}
+
+function apachesolr_server_delete_validate($form, &$form_state) {
+  drupal_set_message(__FUNCTION__);
+}
+
+function apachesolr_server_delete_submit($form, &$form_state) {
+  drupal_set_message(__FUNCTION__);
+  cache_clear_all('apachesolr:servers', 'cache_apachesolr');
+  $form_state['redirect'] = 'admin/config/search/apachesolr';
+}
+
+function apachesolr_server_save_validate($form, &$form_state) {
+  // Normalize the path to have just a leading slash.
+  $form_state['values']['path'] = '/' . trim($form_state['values']['path'], '/');
+  if (isset($form['port']) && isset($form_state['values']['port'])) {
+    $port = $form_state['values']['port'];
+    // TODO: Port range should be 0-65535, but 0 crashes apachesolr
+    if (!ctype_digit($port) || $port < 1 || $port > 65535) {
+      form_set_error('port', t('The port has to be an integer between 1 and 65535.'));
+    }
+  }
+  $asid = db_query('SELECT asid FROM {apachesolr_server} WHERE host = :host AND port = :port AND path = :path', array(':host' => $form_state['values']['host'], ':port' => $form_state['values']['port'], ':path' => $form_state['values']['path']))->fetchField();
+  if ($asid && $asid != $form_state['values']['asid']) {
+    form_set_error('host', t('This combination of host, port, and path is already defined as one of your servers.'));
+  }
+}
+
+function apachesolr_server_save_submit($form, &$form_state) {
+  apachesolr_server_save($form_state['values']);
+  cache_clear_all('apachesolr:servers', 'cache_apachesolr');
+  $form_state['redirect'] = 'admin/config/search/apachesolr';
+}
+
+/**
+ * Form builder for general settings used as a menu callback.
+ */
+function apachesolr_settings($form, &$form_state) {
   $form = array();
   $collapse_host = TRUE;
 
@@ -36,28 +148,30 @@ function apachesolr_settings() {
     '#collapsible' => TRUE,
     '#collapsed' => $collapse_host,
   );
-
-  $form['apachesolr_host_settings']['apachesolr_host'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Solr host name'),
-    '#default_value' => variable_get('apachesolr_host', 'localhost'),
-    '#description' => t('Host name of your Solr server, e.g. <code>localhost</code> or <code>example.com</code>.'),
-    '#required' => TRUE,
-  );
-  $form['apachesolr_host_settings']['apachesolr_port'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Solr port'),
-    '#default_value' => variable_get('apachesolr_port', '8983'),
-    '#description' => t('Port on which the Solr server listens. The Jetty example server is 8983, while Tomcat is 8080 by default.'),
-    '#required' => TRUE,
+  $id = variable_get('apachesolr_default_server', 'solr');
+  $servers = apachesolr_load_all_servers();
+  $rows = array();
+  $headers = NULL;
+  // @todo - make this pretty.
+  foreach ($servers as $server_id => $data) {
+    if (!$headers) {
+      $headers = array_keys($data);
+    }
+    foreach ($data as $key => $value) {
+      $data[$key] = check_plain($value);
+    }
+    $data['asid'] = l(t('edit'), 'admin/config/search/apachesolr/server/' . $data['asid'] .'/edit');
+    $rows[] = array_values($data);
+  }
+  $form['apachesolr_host_settings']['table'] = array(
+    '#theme' => 'table',
+    '#header' => $headers,
+    '#rows' => $rows,
   );
-  $form['apachesolr_host_settings']['apachesolr_path'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Solr path'),
-    '#default_value' => variable_get('apachesolr_path', '/solr'),
-    '#description' => t('Path that identifies the Solr request handler to be used.'),
+  $form['apachesolr_host_settings']['add'] = array(
+    '#markup' => l(t('Add new server'), 'admin/config/search/apachesolr/server/add'),
   );
-
+  
   $numbers = drupal_map_assoc(array(1, 5, 10, 20, 50, 100, 200));
   $form['apachesolr_cron_limit'] = array(
     '#type' => 'select',
@@ -116,6 +230,7 @@ function apachesolr_settings() {
     '#options' => array(APACHESOLR_READ_WRITE => t('Read and write (normal)'), APACHESOLR_READ_ONLY => t('Read only')),
     '#description' => t('<em>Read only</em> stops this site from sending updates to your search index. Useful for development sites.'),
   );
+  $form['#submit'][] = 'apachesolr_settings_submit';
   return system_settings_form($form);
 }
 
@@ -123,13 +238,14 @@ function apachesolr_settings() {
  * Validation function for the apachesolr_settings form.
  */
 function apachesolr_settings_validate($form, &$form_state) {
-  if (isset($form['apachesolr_port'])) {
-    $port = $form_state['values']['apachesolr_port'];
-    // TODO: Port range should be 0-65535, but 0 crashes apachesolr
-    if (!ctype_digit($port) || $port < 1 || $port > 65535) {
-      form_set_error('apachesolr_port', t('The port has to be an integer between 1 and 65535.'));
-    }
-  }
+}
+
+/**
+ * Validation function for the apachesolr_settings form.
+ */
+function apachesolr_settings_submit($form, &$form_state) {
+  apachesolr_server_save($form_state['values']['apachesolr_host_settings']);
+  unset($form_state['values']['apachesolr_host_settings']);
 }
 
 /**
diff --git apachesolr.apachesolr.inc apachesolr.apachesolr.inc
new file mode 100755
index 0000000..a4abe2d
--- /dev/null
+++ apachesolr.apachesolr.inc
@@ -0,0 +1,2 @@
+<?php
+
diff --git apachesolr.api.php apachesolr.api.php
new file mode 100755
index 0000000..991e1b0
--- /dev/null
+++ apachesolr.api.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Define various Field API Fields that can be indexed, and how.
+ *
+ * @todo Pwolanin, please fill in proper definitions here of what the keys do. :-)
+ *
+ * @return array
+ */
+function field_apachesolr_field_mappings() {
+  $mappings = array(
+    'list' => array(
+      'display_callback' => 'apachesolr_fields_list_display_callback',
+      'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
+      'index_type' => 'string',
+    ),
+    'list_number' => array(
+      'display_callback' => 'apachesolr_fields_list_display_callback',
+      'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
+      'index_type' => 'string',
+    ),
+    'list_text' => array(
+      'display_callback' => 'apachesolr_fields_list_display_callback',
+      'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
+      'index_type' => 'string',
+    ),
+    'list_boolean' => array(
+      'display_callback' => 'apachesolr_fields_list_display_callback',
+      'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
+      'index_type' => 'string',
+    ),
+    'taxonomy_term_reference' => array(
+      'display_callback' => 'apachesolr_search_taxonomy_get_term',
+      'indexing_callback' => 'apachesolr_term_reference_indexing_callback',
+      'index_type' => 'integer',
+      'facet_block_callback' => 'apachesolr_search_taxonomy_facet_block',
+      'name_callback' => 'apacehsolr_term_reference_name',
+    ),
+  );
+
+  return $mappings;
+}
+
+/**
+ * Alter hook for apachesolr_field_mappings().
+ */
+function apachesolr_apachesolr_field_mappings_alter(&$mappings) {
+
+}
diff --git apachesolr.index.inc apachesolr.index.inc
old mode 100644
new mode 100755
index 3bbcd09..0aeed49
--- apachesolr.index.inc
+++ apachesolr.index.inc
@@ -7,16 +7,6 @@
  */
 
 /**
- * Strip html tags and also control characters that cause Jetty/Solr to fail.
- */
-function apachesolr_clean_text($text) {
-  // Add spaces before stripping tags to avoid running words together.
-  $text = filter_xss(str_replace(array('<', '>'), array(' <', '> '), $text), array());
-  // Decode entities and then make safe any < or > characters.
-  return htmlspecialchars(html_entity_decode($text, ENT_NOQUOTES, 'UTF-8'), ENT_NOQUOTES, 'UTF-8');
-}
-
-/**
  * Given a node, return a document representing that node.
  */
 function apachesolr_node_to_document($node, $namespace) {
@@ -113,7 +103,7 @@ function apachesolr_node_to_document($node, $namespace) {
     }
 
     // Handle fields including taxonomy.
-    $indexed_fields = apachesolr_node_fields();
+    $indexed_fields = apachesolr_entity_fields('node');
     foreach ($indexed_fields as $index_key => $field_info) {
       $field_name = $field_info['field']['field_name'];
       // See if the node has fields that can be indexed
@@ -221,10 +211,10 @@ function apachesolr_vocab_name($vid) {
 /**
  * Callback that converts list module field into an array
  */
-function apachesolr_fields_list_indexing_callback($node, $field_name, $index_key, $field_info) {
+function apachesolr_fields_list_indexing_callback($entity, $field_name, $index_key, $field_info) {
   $fields = array();
-  if (!empty($node->{$field_name})) {
-    $field = $node->$field_name;
+  if (!empty($entity->{$field_name})) {
+    $field = $entity->$field_name;
     list($lang, $values) = each($field);
     foreach ($values as $fval) {
       $fields[] = array(
diff --git apachesolr.info apachesolr.info
index a1ab2ae..bffc43a 100644
--- apachesolr.info
+++ apachesolr.info
@@ -11,3 +11,4 @@ files[] = apachesolr.admin.inc
 files[] = apachesolr.index.inc
 files[] = apachesolr.taxonomy.inc
 files[] = Drupal_Apache_Solr_Service.php
+files[] = SolrPhpClient/Apache/Solr/Service.php
diff --git apachesolr.install apachesolr.install
index fae7235..f3eac55 100644
--- apachesolr.install
+++ apachesolr.install
@@ -83,8 +83,9 @@ function apachesolr_install() {
   // Create one MLT block.
   require_once(drupal_get_path('module', 'apachesolr') .'/apachesolr.admin.inc');
   apachesolr_mlt_save_block(array('name' => t('More like this')));
-
-  drupal_set_message(t('Search is enabled. Your site is <a href="!index_settings_link">currently 0% indexed</a>.', array('!index_settings_link' => url('admin/config/search/apachesolr/index'))));
+  db_insert('apachesolr_server')->fields(array('server_id' => 'solr', 'name' => 'Apache Solr server', 'host' => 'localhost', 'port' => '8983', 'path' => '/solr'))->execute();
+  variable_set('apachesolr_default_server', 'solr');
+  drupal_set_message(t('Apache Solr is enabled. Visit the <a href="!settings_link">settings page</a>.', array('!settings_link' => url('admin/config/search/apachesolr'))));
 }
 
 /**
@@ -129,6 +130,70 @@ function apachesolr_schema() {
   $table['description'] = 'Cache table for apachesolr to store Luke data and indexing information.';
   $schema['cache_apachesolr'] = $table;
 
+  $schema['apachesolr_server'] = array(
+    'description' => 'The Solr server table.',
+    'fields' => array(
+      'asid' => array(
+        'description' => 'Integer primary key.',
+        'type' => 'serial',
+        'not null' => TRUE
+      ),
+     'server_id' => array(
+        'description' => 'Unique identifier for the server',
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => TRUE,
+      ),
+      'name' => array(
+        'description' => 'Human-readable name for the server',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'scheme' => array(
+        'description' => 'Preferred scheme for the registered server',
+        'type' => 'varchar',
+        'length' => 10,
+        'not null' => TRUE,
+        'default' => 'http'
+      ),
+      'host' => array(
+        'description' => 'Host name for the registered server',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'port' => array(
+        'description' => 'Port number for the registered server',
+        'type' => 'varchar',
+        'length' => 10,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'path' => array(
+        'description' => 'Path to the registered server',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'service_class' => array(
+        'description' => 'Optional class name to use for connection',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+    ),
+    'primary key' => array('asid'),
+    'unique keys' => array(
+      'server_id' => array('server_id'),
+      'host_post_path' => array('host', 'port', 'path'),
+    ),
+  );
+
   return $schema;
 }
 
@@ -136,9 +201,7 @@ function apachesolr_schema() {
  * Implements hook_uninstall().
  */
 function apachesolr_uninstall() {
-  variable_del('apachesolr_host');
-  variable_del('apachesolr_port');
-  variable_del('apachesolr_path');
+  variable_del('apachesolr_default_server');
   variable_del('apachesolr_rows');
   variable_del('apachesolr_facet_query_limits');
   variable_del('apachesolr_facet_query_limit_default');
@@ -259,3 +322,88 @@ function apachesolr_update_6005() {
   db_create_table($ret, 'cache_apachesolr', $table);
   return $ret;
 }
+
+/**
+ * Add a table to track Solr servers.
+ */
+function apachesolr_update_7000() {
+
+  $schema['apachesolr_server'] = array(
+    'description' => 'The Solr server table.',
+    'fields' => array(
+      'asid' => array(
+        'description' => 'Integer primary key (for possible use with Fields and Entity APIs)',
+        'type' => 'serial',
+        'not null' => TRUE
+      ),
+     'server_id' => array(
+        'description' => 'Unique identifier for the server',
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => TRUE,
+      ),
+      'name' => array(
+        'description' => 'Human-readable name for the server',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'scheme' => array(
+        'description' => 'Preferred scheme for the registered server',
+        'type' => 'varchar',
+        'length' => 10,
+        'not null' => TRUE,
+        'default' => 'http'
+      ),
+      'host' => array(
+        'description' => 'Host name for the registered server',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'port' => array(
+        'description' => 'Port number for the registered server',
+        'type' => 'varchar',
+        'length' => 10,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'path' => array(
+        'description' => 'Path to the registered server',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'service_class' => array(
+        'description' => 'Optional class name to use for connection',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+    ),
+    'primary key' => array('asid'),
+    'unique keys' => array(
+      'server_id' => array('server_id'),
+      'host_post_path' => array('host', 'port', 'path'),
+    ),
+  );
+  db_create_table('apachesolr_server', $schema['apachesolr_server']);
+  // Insert into the table the current single server record.
+  $host = variable_get('apachesolr_host', 'localhost');
+  $port = variable_get('apachesolr_port', '8983');
+  $path = variable_get('apachesolr_path', '/solr');
+  db_insert('apachesolr_server')->fields(array('server_id' => 'solr', 'name' => 'Apache Solr server', 'host' => $host, 'port' => $port, 'path' => $path))->execute();
+  variable_set('apachesolr_default_server', 'solr');
+  variable_del('apachesolr_host');
+  variable_del('apachesolr_port');
+  variable_del('apachesolr_path');
+  $value = variable_get('apachesolr_service_class', NULL);
+  if (is_array($value)) {
+    list($module, $filepath, $class) = $value;
+    variable_set('apachesolr_service_class', $class);
+  }
+}
diff --git apachesolr.module apachesolr.module
old mode 100644
new mode 100755
index 043e672..8bd80c8
--- apachesolr.module
+++ apachesolr.module
@@ -19,7 +19,22 @@ function apachesolr_menu() {
     'description'        => 'Administer Apache Solr.',
     'page callback'      => 'drupal_get_form',
     'page arguments'     => array('apachesolr_settings'),
-    'access callback'    => 'user_access',
+    'access arguments'   => array('administer search'),
+    'file'               => 'apachesolr.admin.inc',
+  );
+  $items['admin/config/search/apachesolr/server/%apachesolr_server_asid/edit'] = array(
+    'title'              => 'Apache Solr search server edit',
+    'description'        => 'Edit Apache Solr server.',
+    'page callback'      => 'drupal_get_form',
+    'page arguments'     => array('apachesolr_server_edit_form', 5),
+    'access arguments'   => array('administer search'),
+    'file'               => 'apachesolr.admin.inc',
+  );
+  $items['admin/config/search/apachesolr/server/add'] = array(
+    'title'              => 'Apache Solr search server add',
+    'description'        => 'Add Apache Solr server.',
+    'page callback'      => 'drupal_get_form',
+    'page arguments'     => array('apachesolr_server_edit_form', NULL),
     'access arguments'   => array('administer search'),
     'file'               => 'apachesolr.admin.inc',
   );
@@ -304,10 +319,16 @@ function apachesolr_rebuild_index_table($type = NULL) {
     // Populate table
     $sel_query = db_select('node', 'n')
       ->fields('n', array('nid', 'status'));
-    $sel_query->leftJoin('node_comment_statistics', 'c', 'n.nid = c.nid');
-    $sel_query->addExpression('GREATEST(n.created, n.changed, COALESCE(c.last_comment_timestamp, 0))', 'changed');
 
-    db_insert('apachesolr_search_node')->fields(array('nid', 'status', 'changed'))
+    $insert_fields = array('nid', 'status');
+    // Check if the module is enabled, if so use the timestamp from the latest comment
+    if (module_exists('comment')) {
+      $sel_query->leftJoin('node_comment_statistics', 'c', 'n.nid = c.nid');
+      $sel_query->addExpression('GREATEST(n.created, n.changed, COALESCE(c.last_comment_timestamp, 0))', 'changed');
+      $insert_fields[] = 'changed';
+    }
+
+    db_insert('apachesolr_search_node')->fields($insert_fields)
       ->from($sel_query)
       ->execute();
 
@@ -1518,34 +1539,89 @@ function apachesolr_has_searched($searched = NULL) {
 
 /**
  * Factory method for solr singleton object. Structure allows for an arbitrary
- * number of solr objects to be used based on the host, port, path combination.
+ * number of solr objects to be used based on a name whie maps to 
+ * the host, port, path combination.
  * Get an instance like this:
  *   $solr = apachesolr_get_solr();
  *
  * @throws Exception
  */
-function apachesolr_get_solr($host = NULL, $port = NULL, $path = NULL) {
-  static $solr_cache;
+function apachesolr_get_solr($id = NULL) {
+  $solr_cache = &drupal_static(__FUNCTION__);
 
-  if (empty($host)) {
-    $host = variable_get('apachesolr_host', 'localhost');
-  }
-  if (empty($port)) {
-    $port = variable_get('apachesolr_port', '8983');
+  if (empty($solr_cache['servers'])) {
+    $solr_cache['servers'] = apachesolr_load_all_servers();
   }
-  if (empty($path)) {
-    $path = variable_get('apachesolr_path', '/solr');
+
+  if (empty($id) || empty($solr_cache['servers'][$id])) {
+    $id = variable_get('apachesolr_default_server', 'solr');
   }
 
-  if (empty($solr_cache[$host][$port][$path])) {
-    list($module, $filepath, $class) = variable_get('apachesolr_service_class', array('apachesolr', 'Drupal_Apache_Solr_Service.php', 'Drupal_Apache_Solr_Service'));
-    include_once(drupal_get_path('module', $module) .'/'. $filepath);
+  $host = $solr_cache['servers'][$id]['host'];
+  $port = $solr_cache['servers'][$id]['port'];
+  $server = $host . ':' . $port;
+  $path = $solr_cache['servers'][$id]['path'];
+  $class = $solr_cache['servers'][$id]['service_class'];
+
+  if (empty($solr_cache['instances'][$server][$path])) {
+    // Use the default class if none is specified.
+    if (empty($class)) {
+      $class = variable_get('apachesolr_service_class', 'Drupal_Apache_Solr_Service');
+    }
+    // Takes advantage of auto-loading.
     $solr = new $class($host, $port, $path);
     // Set a non-default behavior.
     $solr->setCollapseSingleValueArrays(FALSE);
-    $solr_cache[$host][$port][$path] = $solr;
+    $solr_cache['instances'][$server][$path] = $solr;
+  }
+  return $solr_cache['instances'][$server][$path];
+}
+
+function apachesolr_load_all_servers() {
+  // Use cache_get to avoid DB when using memcache, etc.
+  $cache = cache_get('apachesolr:servers', 'cache_apachesolr');
+  if (isset($cache->data)) {
+    $servers = $cache->data;
+  }
+  else {
+    $servers = db_query('SELECT * FROM {apachesolr_server}')->fetchAllAssoc('server_id', PDO::FETCH_ASSOC);
+    cache_set('apachesolr:servers', $servers, 'cache_apachesolr');
+  }
+  return $servers;
+}
+
+function apachesolr_server_id_load($server_id) {
+  return db_query('SELECT * FROM {apachesolr_server} WHERE server_id = :server_id', array(':server_id' => $server_id))->fetchAssoc();
+}
+
+function apachesolr_server_asid_load($asid) {
+  if (!is_numeric($asid)) {
+    return FALSE;
+  }
+  return db_query('SELECT * FROM {apachesolr_server} WHERE asid = :asid', array(':asid' => (int) $asid))->fetchAssoc();
+}
+
+function apachesolr_server_save($server) {
+  $default = array('asid' => NULL, 'server_id' => '', 'name' => '', 'scheme' => NULL, 'host' => '', 'port' => '', 'path' => '', 'service_class' => '');
+  // Remove any unexpected fields.
+  // @todo - getthis from the schema, or maybe use drupal_write_record().
+  $server = array_intersect_key($server, $default);
+  if (!empty($server['asid'])) {
+    $asid = $server['asid'];
+    unset($server['asid']);
+    db_update('apachesolr_server')
+      ->fields($server)
+      ->condition('asid', $asid)
+      ->execute();
+  }
+  else {
+    $server_id = $server['server_id'];
+    unset($server['server_id']);
+    db_merge('apachesolr_server')
+      ->fields($server)
+      ->key(array('server_id' => $server_id))
+      ->execute();
   }
-  return $solr_cache[$host][$port][$path];
 }
 
 /**
@@ -1797,7 +1873,7 @@ function apachesolr_field_name_map($field_name) {
         $map['im_vid_'. $vocab->vid] = t('Taxonomy term IDs from the %name vocabulary', array('%name' => $vocab->name));
       }
     }
-    foreach (apachesolr_node_fields() as $field_nm => $field_info) {
+    foreach (apachesolr_entity_fields('node') as $field_nm => $field_info) {
       $map[apachesolr_index_key($field_info)] = t('Field of type @type: %label', array('@type' => $field_info['field']['type'], '%label' => $field_info['display_name']));
     }
     drupal_alter('apachesolr_field_name_map', $map);
@@ -1808,53 +1884,15 @@ function apachesolr_field_name_map($field_name) {
 /**
  * Returns array containing information about node fields that should be indexed
  */
-function apachesolr_node_fields() {
-  static $fields = NULL;
+function apachesolr_entity_fields($entity_type = 'node') {
+  static $fields = array();
+  $fields = &drupal_static(__FUNCTION__, array());
 
-  if (!isset($fields)) {
-    $fields = array();
-    $mappings = array(
-      'list' => array(
-        'display_callback' => 'apachesolr_fields_list_display_callback',
-        'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
-        'index_type' => 'string',
-      ),
-      'list_number' => array(
-        'display_callback' => 'apachesolr_fields_list_display_callback',
-        'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
-        'index_type' => 'string',
-      ),
-      'list_text' => array(
-        'display_callback' => 'apachesolr_fields_list_display_callback',
-        'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
-        'index_type' => 'string',
-      ),
-      'list_boolean' => array(
-        'display_callback' => 'apachesolr_fields_list_display_callback',
-        'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
-        'index_type' => 'string',
-      ),
-      'taxonomy_term_reference' => array(
-        'display_callback' => 'apachesolr_search_taxonomy_get_term',
-        'indexing_callback' => 'apachesolr_term_reference_indexing_callback',
-        'index_type' => 'integer',
-        'facet_block_callback' => 'apachesolr_search_taxonomy_facet_block',
-        'name_callback' => 'apacehsolr_term_reference_name',
-      ),
-      'node_reference' => array(
-        'display_callback' => 'apachesolr_cck_nodereference_field_callback',
-        'indexing_callback' => 'apachesolr_cck_nodereference_indexing_callback',
-        'index_type' => 'integer',
-      ),
-      'user_reference' => array(
-        'display_callback' => 'apachesolr_cck_userreference_field_callback',
-        'indexing_callback' => 'apachesolr_cck_userreference_indexing_callback',
-        'index_type' => 'integer',
-      ),
-    );
+  if (!isset($fields[$entity_type])) {
+    $fields[$entity_type] = array();
+
+    $mappings = module_invoke_all('apachesolr_field_mappings');
 
-    // Allow other modules to add or alter mappings.
-    drupal_alter('apachesolr_field_mappings', $mappings);
     foreach (array_keys($mappings) as $key) {
       // Set all values with defaults.
       $mappings[$key] += array(
@@ -1867,12 +1905,14 @@ function apachesolr_node_fields() {
         'multiple' => TRUE,
       );
     }
-    // We are only concerned about fields on node entities.
+
+    // Allow other modules to add or alter mappings.
+    drupal_alter('apachesolr_field_mappings', $mappings);
     $modules = system_get_info('module');
-    $instances = field_info_instances('node');
+    $instances = field_info_instances($entity_type);
     foreach (field_info_fields() as $field_name => $field) {
       $row = array();
-      if (isset($field['bundles']['node']) && (isset($mappings['per-field'][$field_name]) || isset($mappings[$field['type']]))) {
+      if (isset($field['bundles'][$entity_type]) && (isset($mappings['per-field'][$field_name]) || isset($mappings[$field['type']]))) {
         // Find the mapping.
         if (isset($mappings['per-field'][$field_name])) {
           $row = $mappings['per-field'][$field_name];
@@ -1885,7 +1925,7 @@ function apachesolr_node_fields() {
         // Since we use the index key as the block delta in apachesolr_search, we need a name
         // to build whatever the index key is that is used for faceting.
         // @todo: for fields like taxonomy we are indexing multiple Solr fields
-        // per node field, but are keying on a single Solr field name here.
+        // per entity field, but are keying on a single Solr field name here.
         $function = $row['name_callback'];
         if ($function && function_exists($function)) {
           $row['name'] = $function($field);
@@ -1896,21 +1936,32 @@ function apachesolr_node_fields() {
         $row['module_name'] = $modules[$field['module']]['name'];
         // Set display name
         $display_name = array();
-        foreach ($field['bundles']['node'] as $node_type) {
-          if ($instances[$node_type][$field_name]['display']['search_index'] != 'hidden') {
-            $row['display_name'] = $instances[$node_type][$field_name]['label'];
-            $row['content_types'][] = $node_type;
+        foreach ($field['bundles'][$entity_type] as $bundle) {
+          if (empty($instances[$bundle][$field_name]['display']['search_index']) || $instances[$bundle][$field_name]['display']['search_index'] != 'hidden') {
+            $row['display_name'] = $instances[$bundle][$field_name]['label'];
+            $row['bundles'][] = $bundle;
           }
         }
         // Only add to the $fields array if some instances are displayed for the search index.
-        if (!empty($row['content_types'])) {
+        if (!empty($row['bundles'])) {
           // Use the Solr index key as the array key.
-          $fields[apachesolr_index_key($row)] = $row;
+          $fields[$entity_type][apachesolr_index_key($row)] = $row;
         }
       }
     }
   }
-  return $fields;
+  return $fields[$entity_type];
+}
+
+
+/**
+ * Strip html tags and also control characters that cause Jetty/Solr to fail.
+ */
+function apachesolr_clean_text($text) {
+  // Add spaces before stripping tags to avoid running words together.
+  $text = filter_xss(str_replace(array('<', '>'), array(' <', '> '), $text), array());
+  // Decode entities and then make safe any < or > characters.
+  return htmlspecialchars(html_entity_decode($text, ENT_NOQUOTES, 'UTF-8'), ENT_NOQUOTES, 'UTF-8');
 }
 
 function apacehsolr_term_reference_name($field) {
@@ -1986,6 +2037,92 @@ function apachesolr_cck_userreference_field_callback($facet, $options) {
 }
 
 /**
+ * Generalizes calling quazi-method callbacks on entities.
+ *
+ * The callbacks are defined in the entity's info array definition.
+ *
+ * @param stdClass $entity
+ *   The entity on which to call this quasi-method.
+ * @param string $entity_type
+ *   The type of entity we have. Drupal doesn't tell us this automatically.
+ * @param string $callback
+ *   The name of the callback we want to call.
+ * @param array $arguments
+ * @return mixed
+ *   NULL if the callback wasn't found.  If it was, whatever that callback returns
+ *   is returned.
+ */
+function apachesolr_entity_callback($entity, $entity_type, $callback, $arguments = array()) {
+  $info = entity_get_info($entity_type);
+  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+
+  $callback_function = apachesolr_entity_get_callback($entity_type, $callback, $bundle);
+
+  if (function_exists($callback_function)) {
+    return call_user_func_array($callback_function, $arguments);
+  }
+
+  return NULL;
+}
+
+/**
+ * Returns the callback function appropriate for a given entity type/bundle.
+ *
+ * @param string $entity_type
+ *   The entity type for which we want to know the approprite callback.
+ * @param string $callback
+ *   The callback for which we want the appropriate function.
+ * @param string $bundle
+ *   If specified, the bundle of the entity in question.  Some callbacks may
+ *   be overridden on a bundle-level.  Not specified only the entity-level
+ *   callback will be checked.
+ * @return string
+ *   The function name for this callback, or NULL if not specified.
+ */
+function apachesolr_entity_get_callback($entity_type, $callback, $bundle = NULL) {
+  $info = entity_get_info($entity_type);
+
+  // A bundle-specific callback takes precedence over the generic one for the
+  // entity type.
+  if ($bundle && isset($info['bundles'][$bundle]['apachesolr'][$callback])) {
+    $callback_function = $info['bundles'][$bundle]['apachesolr'][$callback];
+  }
+  elseif (isset($info['apachesolr'][$callback])) {
+    $callback_function = $info['apachesolr'][$callback];
+  }
+  else {
+    $callback_function = NULL;
+  }
+
+  return $callback_function;
+}
+
+/**
+ * Determines if we should index the provided entity.
+ *
+ * Whether or not a given entity is indexed is determined on a per-bundle basis.
+ * Entities/Bundles that have no index flag are presumed to not get indexed.
+ *
+ * @param stdClass $entity
+ *   The entity we may or may not want to index.
+ * @param string $type
+ *   The type of entity.
+ * @return boolean
+ *   TRUE if this entity should be indexed, FALSE otherwise.
+ */
+function apachesolr_entity_should_index($entity, $type) {
+  $info = entity_get_info($type);
+  list($id, $vid, $bundle) = entity_extract_ids($type, $entity);
+
+  if ($bundle && isset($info['bundles'][$bundle]['apachesolr']['index']) && $info['bundles'][$bundle]['apachesolr']['index']) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+
+/**
  * Implements hook_theme().
  */
 function apachesolr_theme() {
@@ -2040,7 +2177,7 @@ function apachesolr_theme() {
  *
  * @return An array of response documents, or NULL
  */
-function apachesolr_mlt_suggestions($settings, $id) {
+function apachesolr_mlt_suggestions($settings, $id, $solr = NULL) {
 
   try {
     $fields = array(
@@ -2052,8 +2189,8 @@ function apachesolr_mlt_suggestions($settings, $id) {
       'mlt_boost' => 'mlt.boost',
       'mlt_qf' => 'mlt.qf',
     );
-    // @TODO: some way to specify a Solr object?
-    $query = apachesolr_drupal_query('id:' . $id);
+    // We can optionally specify a Solr object.
+    $query = apachesolr_drupal_query('id:' . $id, '', '', '', $solr);
     $query->params = array(
       'qt' => 'mlt',
       'fl' => 'nid,title,path,url',
@@ -2110,6 +2247,77 @@ function apachesolr_form_block_admin_display_form_alter(&$form) {
 }
 
 /**
+ * Implements hook_hook_info().
+ */
+function apachesolr_hook_info() {
+  $hooks['apachesolr_field_mappings'] = array(
+    'group' => 'apachesolr',
+  );
+  $hooks['apachesolr_field_mappings_alter'] = array(
+    'group' => 'apachesolr',
+  );
+
+  return $hooks;
+}
+
+/**
+ * Implements hook_apachesolr_field_mappings().
+ */
+function field_apachesolr_field_mappings() {
+  $mappings = array(
+    'list' => array(
+      'display_callback' => 'apachesolr_fields_list_display_callback',
+      'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
+      'index_type' => 'string',
+    ),
+    'list_number' => array(
+      'display_callback' => 'apachesolr_fields_list_display_callback',
+      'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
+      'index_type' => 'string',
+    ),
+    'list_text' => array(
+      'display_callback' => 'apachesolr_fields_list_display_callback',
+      'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
+      'index_type' => 'string',
+    ),
+    'list_boolean' => array(
+      'display_callback' => 'apachesolr_fields_list_display_callback',
+      'indexing_callback' => 'apachesolr_fields_list_indexing_callback',
+      'index_type' => 'boolean',
+    ),
+    'taxonomy_term_reference' => array(
+      'display_callback' => 'apachesolr_search_taxonomy_get_term',
+      'indexing_callback' => 'apachesolr_term_reference_indexing_callback',
+      'index_type' => 'integer',
+      'facet_block_callback' => 'apachesolr_search_taxonomy_facet_block',
+      'name_callback' => 'apacehsolr_term_reference_name',
+    ),
+  );
+
+  return $mappings;
+}
+
+/**
+ * Implements hook_apachesolr_field_mappings().
+ */
+function content_apachesolr_field_mappings() {
+  $mappings = array(
+    'node_reference' => array(
+      'display_callback' => 'apachesolr_cck_nodereference_field_callback',
+      'indexing_callback' => 'apachesolr_cck_nodereference_indexing_callback',
+      'index_type' => 'integer',
+    ),
+    'user_reference' => array(
+      'display_callback' => 'apachesolr_cck_userreference_field_callback',
+      'indexing_callback' => 'apachesolr_cck_userreference_indexing_callback',
+      'index_type' => 'integer',
+    ),
+  );
+
+  return $mappings;
+}
+
+/**
  * Returns a list of blocks. Used by hook_block
  */
 function apachesolr_mlt_list_blocks() {
diff --git apachesolr_nodeaccess/apachesolr_nodeaccess.info apachesolr_nodeaccess/apachesolr_nodeaccess.info
new file mode 100644
index 0000000..4c211af
--- /dev/null
+++ apachesolr_nodeaccess/apachesolr_nodeaccess.info
@@ -0,0 +1,8 @@
+; $Id: apachesolr_nodeaccess.info,v 1.1.2.4 2009/01/27 20:12:52 pwolanin Exp $
+name = Apache Solr node access
+description = Integrates the node access system with Apache Solr search
+dependencies[] = apachesolr
+package = Apache Solr
+core = 7.x
+
+files[] = apachesolr_nodeaccess.module
diff --git apachesolr_nodeaccess/apachesolr_nodeaccess.module apachesolr_nodeaccess/apachesolr_nodeaccess.module
new file mode 100644
index 0000000..ffe18d9
--- /dev/null
+++ apachesolr_nodeaccess/apachesolr_nodeaccess.module
@@ -0,0 +1,138 @@
+<?php
+// $Id$
+
+/**
+ * Implements apachesolr_update_index
+ */
+function apachesolr_nodeaccess_apachesolr_update_index(&$document, $node, $namespace) {
+  static $account;
+
+  if (!isset($account)) {
+    // Load the anonymous user.
+    $account = drupal_anonymous_user();
+  }
+
+  if (!node_access('view', $node, $account)) {
+    // Get node access grants.
+    $result = db_query('SELECT * FROM {node_access} WHERE (nid = 0 OR nid = :nid) AND grant_view = 1', array(':nid' => $node->nid));
+    foreach($result as $grant){
+      $key = 'nodeaccess_' . apachesolr_site_hash() . '_' . $grant->realm;
+      $document->setMultiValue($key, $grant->gid);
+    }
+  }
+  else {
+    // Add the generic view grant if we are not using
+    // node access or the node is viewable by anonymous users.
+    $document->setMultiValue('nodeaccess_all', 0);
+  }
+}
+
+/**
+ * Creates a Solr query for a given user
+ *
+ * @param $account an account to get grants for and build a solr query
+ *
+ * @throws Exception
+ */
+function apachesolr_nodeaccess_build_subquery($account) {
+  if (!user_access('access content', $account)) {
+    throw new Exception('No access');
+  }
+  $node_access_query = apachesolr_drupal_query();
+  if (empty($node_access_query)) {
+    throw new Exception('No query object in apachesolr_nodeaccess');
+  }
+  if (user_access('administer nodes', $account)) {
+    // Access all content from the current site, or public content.
+    $node_access_query->add_filter('nodeaccess_all', 0);
+    $node_access_query->add_filter('hash', apachesolr_site_hash());
+  }
+  else {
+    // Get node access grants.
+    $grants = node_access_grants('view', $account);
+    foreach ($grants as $realm => $gids) {
+      foreach ($gids as $gid) {
+        $node_access_query->add_filter('nodeaccess_' . apachesolr_site_hash() . '_' . $realm, $gid);
+      }
+    }
+    $node_access_query->add_filter('nodeaccess_all', 0);
+  }
+  return $node_access_query;
+}
+
+/**
+ * Implements hook_apachesolr_modify_query().
+ */
+function apachesolr_nodeaccess_apachesolr_modify_query(&$query, &$params, $caller = 'apachesolr_search') {
+  if ($caller == 'apachesolr_views_query') {
+    return;
+  }
+  global $user;
+  try {
+    $subquery = apachesolr_nodeaccess_build_subquery($user);
+  }
+  catch (Exception $e) {
+    $query = NULL;
+    watchdog("apachesolr_nodeaccess", 'User %name (UID:!uid) cannot search: @message', array('%name' => $user->name, '!uid' => $user->uid, '@message' => $e->getMessage()));
+    return;
+  }
+
+  if (!empty($subquery)) {
+    $query->add_subquery($subquery, 'OR');
+  }
+}
+
+/**
+ * Implements hook_node_insert().
+ * hook_node*() is called before hook_node_access_records() in node_save().
+ */
+function apachesolr_nodeaccess_node_insert($node){
+  $node->apachesolr_nodeaccess_ignore = 1;
+}
+
+/**
+ * Implements hook_node_update().
+ */
+function apachesolr_nodeaccess_node_update($node){
+  $node->apachesolr_nodeaccess_ignore = 1;
+}
+
+/**
+ * Implements hook_node_access_records().
+ *
+ * Listen to this hook to find out when a node needs to be re-indexed
+ * for its node access grants.
+ */
+function apachesolr_nodeaccess_node_access_records($node) {
+  // node_access_needs_rebuild() will usually be TRUE during a
+  // full rebuild.
+  if (empty($node->apachesolr_nodeaccess_ignore) && !node_access_needs_rebuild()) {
+    // Only one node is being changed - mark for re-indexing.
+    apachesolr_mark_node($node->nid);
+  }
+}
+
+/**
+ * Implements hook_form_alter().
+ */
+function apachesolr_nodeaccess_form_alter(&$form, $form_state, $form_id) {
+  if ($form_id == 'node_configure_rebuild_confirm') {
+    $form['#submit'][] = 'apachesolr_nodeaccess_rebuild_nodeaccess';
+  }
+}
+
+/**
+ * Force Solr to do a total re-index when node access rules change.
+ *
+ * This is unfortunate because not every node is going to be affected, but
+ * there is little we can do.
+ */
+function apachesolr_nodeaccess_rebuild_nodeaccess(&$form, $form_state) {
+  drupal_set_message(t('Solr search index will be rebuilt.'));
+  node_access_needs_rebuild(TRUE);
+  apachesolr_clear_last_index();
+}
+
+function apachesolr_nodeaccess_enable() {
+  drupal_set_message(t('Your content <a href="@url">must be re-indexed</a> before Apache Solr node access will be functional on searches.', array('@url' => url('admin/settings/apachesolr/index'))), 'warning');
+}
diff --git apachesolr_nodeaccess/tests/apachesolr_nodeaccess.test apachesolr_nodeaccess/tests/apachesolr_nodeaccess.test
new file mode 100644
index 0000000..faf832e
--- /dev/null
+++ apachesolr_nodeaccess/tests/apachesolr_nodeaccess.test
@@ -0,0 +1,121 @@
+<?php
+// $Id$
+
+class DrupalApacheSolrNodeAccess extends DrupalWebTestCase {
+  function getInfo() {
+    return array(
+      'name' => 'Node Access',
+      'description' => 'Test Access Control',
+      'group' => 'ApacheSolr'
+    );
+  }
+
+  function setUp() {
+    parent::setUp('nodeaccess', 'apachesolr', 'apachesolr_search', 'apachesolr_nodeaccess');
+
+     // Create a basic user, which is subject to moderation.
+    $permissions = array(
+      'access content',
+      'create page content',
+      'edit own page content',
+      'create story content',
+      'edit own story content',
+    );
+    $this->basic_user = $this->drupalCreateUser($permissions);
+  }
+
+  function testIndexing() {
+    $basic_user = $this->basic_user;
+    // Login as basic user to perform initial content creation.
+    $this->drupalLogin($basic_user);
+
+    //Create 2 nodes
+    $edit = array();
+    $edit['title'] = $this->randomName(32);
+    $edit['body']  = $this->randomName(32);
+    $role_restricted_node = $this->drupalCreateNode($edit);
+
+    $edit = array();
+    $edit['title'] = $this->randomName(32);
+    $edit['body']  = $this->randomName(32);
+    $author_restricted_node = $this->drupalCreateNode($edit);
+
+    $this->drupalLogout();
+
+    $roles = array_keys($basic_user->roles);
+    // The assigned role will be the last in the array.
+    $assigned_role = end($roles);
+    $role_grant = array(
+        'gid' => $assigned_role,
+        'realm' => 'nodeaccess_rid',
+        'grant_view' => '1',
+        'grant_update' => '0',
+        'grant_delete' => '0',
+    );
+    node_access_write_grants($role_restricted_node, array($role_grant), 'nodeaccess_rid');
+
+    $author_grant = array(
+        'gid' => $basic_user->uid,
+        'realm' => 'nodeaccess_author',
+        'grant_view' => '1',
+        'grant_update' => '0',
+        'grant_delete' => '0',
+    );
+
+    node_access_write_grants($author_restricted_node, array($author_grant), 'nodeaccess_author');
+
+    $include_path = get_include_path();
+    set_include_path(DRUPAL_ROOT . '/' . drupal_get_path('module', 'apachesolr') .'/SolrPhpClient/');
+    include_once('Apache/Solr/Service.php');
+    set_include_path($include_path);
+
+    $document = new Apache_Solr_Document();
+    apachesolr_nodeaccess_apachesolr_update_index($document, $role_restricted_node, 'apachesolr_search');
+    $field = 'nodeaccess_' . apachesolr_site_hash() . '_nodeaccess_rid';
+    $this->assertEqual($document->{$field}[0], $assigned_role, 'Solr Document being indexed is restricted by the proper role');
+
+    $document = new Apache_Solr_Document();
+    apachesolr_nodeaccess_apachesolr_update_index($document, $author_restricted_node, 'apachesolr_search');
+    $field = 'nodeaccess_' . apachesolr_site_hash() . '_nodeaccess_author';
+    $this->assertEqual($document->{$field}[0], $basic_user->uid, 'Solr Document being indexed is restricted by the proper author');
+  }
+
+  function testQuery() {
+    $basic_user = $this->basic_user;
+    // Login as basic user
+    $this->drupalLogin($basic_user);
+
+    include_once drupal_get_path('module', 'apachesolr') .'/Solr_Base_Query.php';
+    $query = apachesolr_current_query();
+    $params = array();
+
+    $subquery = apachesolr_nodeaccess_build_subquery($basic_user);
+
+    $roles = array_keys($basic_user->roles);
+    $assigned_role = end($roles);
+
+    $expected_criterion = array(
+      'nodeaccess_all' => 0,
+      'nodeaccess_' . apachesolr_site_hash() . '_all' => 0,
+      'nodeaccess_' . apachesolr_site_hash() . '_nodeaccess_rid' => array(2, $assigned_role),
+      'nodeaccess_' . apachesolr_site_hash() . '_nodeaccess_uid' => $basic_user->uid,
+      'nodeaccess_' . apachesolr_site_hash() . '_nodeaccess_author' => $basic_user->uid,
+    );
+
+    $fields = $subquery->get_filters();
+
+    foreach ($fields as $field) {
+      if (is_array($expected_criterion[$field['#name']])) {
+        $this->assertTrue(in_array($field['#value'], $expected_criterion[$field['#name']]), t('Expected node access grant @name == @value found', array('@name' => $field['#name'], '@value' => $field['#value'])));
+        //This is sorta a bug
+        $found_criterion[$field['#name']] = $expected_criterion[$field['#name']];
+      }
+      else {
+        $this->assertEqual($field['#value'], $expected_criterion[$field['#name']], t('Expected node access grant @name == @value found', array('@name' => $field['#name'], '@value' => $field['#value'])));
+        $found_criterion[$field['#name']] = $expected_criterion[$field['#name']];
+      }
+    }
+
+    $this->assertEqual($expected_criterion, $found_criterion, 'All Criteria was accounted for in fields. If not accounted for, Unaccounted Criteria [' . var_export(array_diff($expected_criterion, $found_criterion), 1) . ']');
+  }
+}
diff --git apachesolr_search.module apachesolr_search.module
old mode 100644
new mode 100755
index 7647144..5d066ae
--- apachesolr_search.module
+++ apachesolr_search.module
@@ -152,24 +152,6 @@ function apachesolr_search_conditions() {
   return $conditions;
 }
 
-function apachesolr_search_theme_search_results($search_result, $type){
-  if (isset($search_result) && is_array($search_result) && count($search_result)) {
-    if (module_hook($type, 'search_page')) {
-      $content = module_invoke($type, 'search_page', $search_result);
-    }
-    else {
-      $content = theme('search_results', array('results' => $search_result, 'type' => $type));
-    }
-  }
-  else if ($search_result) {
-    $content = theme('search_results_listing', array('title' => t('Search results'), 'content' => $search_result));
-  }
-  else {
-    $content = theme('search_results_listing', array('title' => t('Your search yielded no results'), 'content' => theme('apachesolr_search_noresults')));
-  }
-
-  return $content;
-}
 /**
  * Implements hook_apachesolr_document_handlers().
  *
@@ -368,7 +350,7 @@ function apachesolr_search_run($keys, $filterstring, $solrsort, $base_path = '',
 // TODO: Why does this take the $query object?
 function apachesolr_search_basic_params($query = NULL) {
   $params = array(
-    'fl' => 'id,nid,title,comment_count,type,created,changed,score,path,url,uid,name',
+    'fl' => 'id,entity_id,entity,bundle,bundle_name,nid,title,comment_count,type,created,changed,score,path,url,uid,name',
     'rows' => variable_get('apachesolr_rows', 10),
     'facet' => 'true',
     'facet.mincount' => 1,
@@ -549,10 +531,10 @@ function apachesolr_search_process_response($response, $query) {
 
       // Find the nicest available snippet.
       if (isset($response->highlighting->{$doc->id}->$hl_fl)) {
-        $snippet = theme('apachesolr_search_snippets', array('doc' => $doc, 'snippets' => $response->highlighting->{$doc->id}->$hl_fl));
+        $snippet = theme('apachesolr_search_snippets__'. $doc->entity . '__' . $doc->bundle, array('doc' => $doc, 'snippets' => $response->highlighting->{$doc->id}->$hl_fl));
       }
       elseif (isset($doc->teaser)) {
-        $snippet = theme('apachesolr_search_snippets', array('doc' => $doc, 'snippets' => array(truncate_utf8($doc->teaser, 256, TRUE))));
+        $snippet = theme('apachesolr_search_snippets__'. $doc->entity . '__' . $doc->bundle, array('doc' => $doc, 'snippets' => array(truncate_utf8($doc->teaser, 256, TRUE))));
       }
       else {
         $snippet = '';
@@ -561,30 +543,50 @@ function apachesolr_search_process_response($response, $query) {
       if (!isset($doc->body)) {
         $doc->body = $snippet;
       }
-      $doc->created = strtotime($doc->created);
-      $doc->changed = strtotime($doc->changed);
+
+      // Normalize common dates so that we can use Drupal's normal date and
+      // time handling.
+      if (isset($doc->created)) {
+        $doc->created = strtotime($doc->created);
+      }
+      if (isset($doc->changed)) {
+        $doc->changed = strtotime($doc->changed);
+      }
+
       $extra = array();
-      $extra['comments'] = format_plural($doc->comment_count, '1 comment', '@count comments');
+
       // Allow modules to alter each document and its extra information.
       drupal_alter('apachesolr_search_result', $doc, $extra);
+
       $fields = array();
       foreach ($doc->getFieldNames() as $field_name) {
         $fields[$field_name] = $doc->getField($field_name);
       }
-      $results[] = array(
+
+      $result = array(
+        // link is a required field, so handle it centrally.
         'link' => url($doc->path, array('absolute' => TRUE)),
-        'type' => apachesolr_search_get_type($doc->type),
         // template_preprocess_search_result() runs check_plain() on the title
         // again.  Decode to correct the display.
         'title' => htmlspecialchars_decode($doc->title, ENT_QUOTES),
-        'user' => theme('username', array('account' => $doc)),
-        'date' => $doc->created,
-        'node' => $doc,
-        'extra' => $extra,
+        // These values are not required by the search module but are provided
+        // to give entity callbacks and themers more flexibility.
         'score' => $doc->score,
         'snippet' => $snippet,
         'fields' => $fields,
+        'entity_type' => $doc->entity,
+        'bundle' => $doc->bundle,
       );
+
+      // Call entity-type-specific callbacks for extra handling.
+      $function = apachesolr_entity_get_callback($doc->entity, 'result callback');
+      if (function_exists($function)) {
+        $function($doc, $result, $extra);
+      }
+
+      $result['extra'] = $extra;
+
+      $results[] = $result;
     }
 
     // Hook to allow modifications of the retrieved results
@@ -596,6 +598,76 @@ function apachesolr_search_process_response($response, $query) {
   return $results;
 }
 
+/**
+ * Implements hook_entity_info_alter().
+ */
+function apachesolr_search_entity_info_alter(&$entity_info) {
+
+  // First set defaults so that we needn't worry about NULL keys.
+  foreach (array_keys($entity_info) as $type) {
+    $entity_info[$type] += array('apachesolr' => array());
+    $entity_info[$type]['apachesolr'] += array(
+      'result callback' => '',
+    );
+  }
+
+  // Now set those values that we know.  Other modules can do so
+  // for their own entities if they want.
+  $entity_info['node']['apachesolr']['result callback'] = 'apachesolr_search_node_result';
+}
+
+/**
+ * Callback function for node search results.
+ *
+ * @param Apache_Solr_Document $doc
+ *   The result document from Apache Solr.
+ * @param array $result
+ *   The result array for this record to which to add.
+ */
+function apachesolr_search_node_result(Apache_Solr_Document $doc, &$result, &$extra) {
+  $result += array(
+    'type' => apachesolr_search_get_type($doc->type),
+    'user' => theme('username', array('account' => $doc)),
+    'date' => $doc->created,
+    'node' => $doc,
+  );
+
+  if (isset($doc->comment_count)) {
+    $extra['comments'] = format_plural($doc->comment_count, '1 comment', '@count comments');
+  }
+}
+
+/**
+ * Template preprocess for apachesolr search results.
+ *
+ * We need to add additional entity/bundle-based templates
+ */
+function apachesolr_search_preprocess_search_result(&$variables) {
+  // If this search result is coming from our module, we want to improve the
+  // template potential to make life easier for themers.
+  if ($variables['module'] == 'apachesolr_search') {
+    $result = $variables['result'];
+    $variables['theme_hook_suggestions'][] = 'search_result__' . $variables['module'] . '__' . $result['entity_type'] . '__' . $result['bundle'];
+  }
+}
+
+function apachesolr_search_preprocess_search_results(&$variables) {
+  // If this is a solr search, expose more data to themes to play with.
+  if ($variables['module'] == 'apachesolr_search') {
+    $variables['response'] = apachesolr_static_response_cache();
+    $variables['query'] = apachesolr_current_query();
+
+    $total = $variables['response']->response->numFound;
+    $params = $variables['query']->params;
+
+    $variables['description'] = t('Showing items @start through @end of @total.', array(
+      '@start' => $params['start'] + 1,
+      '@end' => $params['start'] + $params['rows'] - 1,
+      '@total' => $total,
+    ));
+  }
+}
+
 function apachesolr_search_date_range($query, $facet_field) {
   foreach ($query->get_filters($facet_field) as $filter) {
     // If we had an ISO date library we could use ISO dates
@@ -684,12 +756,12 @@ function apachesolr_search_apachesolr_facets() {
   }
 
   // Get field facets.
-  $fields = apachesolr_node_fields();
+  $fields = apachesolr_entity_fields('node');
   foreach ($fields as $index_key => $field_info) {
     $facets[$index_key] = array(
         'info' => t('@module_name Field: Filter by @field_dname (@field_name)', array('@module_name' => $field_info['module_name'], '@field_name' => $field_info['field']['field_name'], '@field_dname' => $field_info['display_name'])),
         'facet_field' => $index_key,
-        'content_types' => $field_info['content_types'],
+        'content_types' => $field_info['bundles'],
     );
   }
 
@@ -755,7 +827,7 @@ function apachesolr_search_block_view($delta = ''){
       case 'created':
         return apachesolr_date_facet_block($response, $query, 'apachesolr_search', $delta, t('Filter by post date'));
       default:
-        if ($fields = apachesolr_node_fields()) {
+        if ($fields = apachesolr_entity_fields('node')) {
           if (isset($fields[$delta])) {
             // The $delta is the index key.
             $field_info = $fields[$delta];
@@ -1322,7 +1394,7 @@ function theme_apachesolr_breadcrumb_field($vars) {
     }
 
     //$mappings = apachesolr_cck_fields();
-    $mappings = apachesolr_node_fields();
+    $mappings = apachesolr_entity_fields('node');
     if (isset($mappings[$match]['display_callback'])) {
       $function = $mappings[$match]['display_callback'];
       if (function_exists($function)) {
diff --git contrib/apachesolr_nodeaccess/apachesolr_nodeaccess.info contrib/apachesolr_nodeaccess/apachesolr_nodeaccess.info
deleted file mode 100644
index 4c211af..0000000
--- contrib/apachesolr_nodeaccess/apachesolr_nodeaccess.info
+++ /dev/null
@@ -1,8 +0,0 @@
-; $Id: apachesolr_nodeaccess.info,v 1.1.2.4 2009/01/27 20:12:52 pwolanin Exp $
-name = Apache Solr node access
-description = Integrates the node access system with Apache Solr search
-dependencies[] = apachesolr
-package = Apache Solr
-core = 7.x
-
-files[] = apachesolr_nodeaccess.module
diff --git contrib/apachesolr_nodeaccess/apachesolr_nodeaccess.module contrib/apachesolr_nodeaccess/apachesolr_nodeaccess.module
deleted file mode 100644
index ffe18d9..0000000
--- contrib/apachesolr_nodeaccess/apachesolr_nodeaccess.module
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-// $Id$
-
-/**
- * Implements apachesolr_update_index
- */
-function apachesolr_nodeaccess_apachesolr_update_index(&$document, $node, $namespace) {
-  static $account;
-
-  if (!isset($account)) {
-    // Load the anonymous user.
-    $account = drupal_anonymous_user();
-  }
-
-  if (!node_access('view', $node, $account)) {
-    // Get node access grants.
-    $result = db_query('SELECT * FROM {node_access} WHERE (nid = 0 OR nid = :nid) AND grant_view = 1', array(':nid' => $node->nid));
-    foreach($result as $grant){
-      $key = 'nodeaccess_' . apachesolr_site_hash() . '_' . $grant->realm;
-      $document->setMultiValue($key, $grant->gid);
-    }
-  }
-  else {
-    // Add the generic view grant if we are not using
-    // node access or the node is viewable by anonymous users.
-    $document->setMultiValue('nodeaccess_all', 0);
-  }
-}
-
-/**
- * Creates a Solr query for a given user
- *
- * @param $account an account to get grants for and build a solr query
- *
- * @throws Exception
- */
-function apachesolr_nodeaccess_build_subquery($account) {
-  if (!user_access('access content', $account)) {
-    throw new Exception('No access');
-  }
-  $node_access_query = apachesolr_drupal_query();
-  if (empty($node_access_query)) {
-    throw new Exception('No query object in apachesolr_nodeaccess');
-  }
-  if (user_access('administer nodes', $account)) {
-    // Access all content from the current site, or public content.
-    $node_access_query->add_filter('nodeaccess_all', 0);
-    $node_access_query->add_filter('hash', apachesolr_site_hash());
-  }
-  else {
-    // Get node access grants.
-    $grants = node_access_grants('view', $account);
-    foreach ($grants as $realm => $gids) {
-      foreach ($gids as $gid) {
-        $node_access_query->add_filter('nodeaccess_' . apachesolr_site_hash() . '_' . $realm, $gid);
-      }
-    }
-    $node_access_query->add_filter('nodeaccess_all', 0);
-  }
-  return $node_access_query;
-}
-
-/**
- * Implements hook_apachesolr_modify_query().
- */
-function apachesolr_nodeaccess_apachesolr_modify_query(&$query, &$params, $caller = 'apachesolr_search') {
-  if ($caller == 'apachesolr_views_query') {
-    return;
-  }
-  global $user;
-  try {
-    $subquery = apachesolr_nodeaccess_build_subquery($user);
-  }
-  catch (Exception $e) {
-    $query = NULL;
-    watchdog("apachesolr_nodeaccess", 'User %name (UID:!uid) cannot search: @message', array('%name' => $user->name, '!uid' => $user->uid, '@message' => $e->getMessage()));
-    return;
-  }
-
-  if (!empty($subquery)) {
-    $query->add_subquery($subquery, 'OR');
-  }
-}
-
-/**
- * Implements hook_node_insert().
- * hook_node*() is called before hook_node_access_records() in node_save().
- */
-function apachesolr_nodeaccess_node_insert($node){
-  $node->apachesolr_nodeaccess_ignore = 1;
-}
-
-/**
- * Implements hook_node_update().
- */
-function apachesolr_nodeaccess_node_update($node){
-  $node->apachesolr_nodeaccess_ignore = 1;
-}
-
-/**
- * Implements hook_node_access_records().
- *
- * Listen to this hook to find out when a node needs to be re-indexed
- * for its node access grants.
- */
-function apachesolr_nodeaccess_node_access_records($node) {
-  // node_access_needs_rebuild() will usually be TRUE during a
-  // full rebuild.
-  if (empty($node->apachesolr_nodeaccess_ignore) && !node_access_needs_rebuild()) {
-    // Only one node is being changed - mark for re-indexing.
-    apachesolr_mark_node($node->nid);
-  }
-}
-
-/**
- * Implements hook_form_alter().
- */
-function apachesolr_nodeaccess_form_alter(&$form, $form_state, $form_id) {
-  if ($form_id == 'node_configure_rebuild_confirm') {
-    $form['#submit'][] = 'apachesolr_nodeaccess_rebuild_nodeaccess';
-  }
-}
-
-/**
- * Force Solr to do a total re-index when node access rules change.
- *
- * This is unfortunate because not every node is going to be affected, but
- * there is little we can do.
- */
-function apachesolr_nodeaccess_rebuild_nodeaccess(&$form, $form_state) {
-  drupal_set_message(t('Solr search index will be rebuilt.'));
-  node_access_needs_rebuild(TRUE);
-  apachesolr_clear_last_index();
-}
-
-function apachesolr_nodeaccess_enable() {
-  drupal_set_message(t('Your content <a href="@url">must be re-indexed</a> before Apache Solr node access will be functional on searches.', array('@url' => url('admin/settings/apachesolr/index'))), 'warning');
-}
diff --git contrib/apachesolr_nodeaccess/tests/apachesolr_nodeaccess.test contrib/apachesolr_nodeaccess/tests/apachesolr_nodeaccess.test
deleted file mode 100644
index faf832e..0000000
--- contrib/apachesolr_nodeaccess/tests/apachesolr_nodeaccess.test
+++ /dev/null
@@ -1,121 +0,0 @@
-<?php
-// $Id$
-
-class DrupalApacheSolrNodeAccess extends DrupalWebTestCase {
-  function getInfo() {
-    return array(
-      'name' => 'Node Access',
-      'description' => 'Test Access Control',
-      'group' => 'ApacheSolr'
-    );
-  }
-
-  function setUp() {
-    parent::setUp('nodeaccess', 'apachesolr', 'apachesolr_search', 'apachesolr_nodeaccess');
-
-     // Create a basic user, which is subject to moderation.
-    $permissions = array(
-      'access content',
-      'create page content',
-      'edit own page content',
-      'create story content',
-      'edit own story content',
-    );
-    $this->basic_user = $this->drupalCreateUser($permissions);
-  }
-
-  function testIndexing() {
-    $basic_user = $this->basic_user;
-    // Login as basic user to perform initial content creation.
-    $this->drupalLogin($basic_user);
-
-    //Create 2 nodes
-    $edit = array();
-    $edit['title'] = $this->randomName(32);
-    $edit['body']  = $this->randomName(32);
-    $role_restricted_node = $this->drupalCreateNode($edit);
-
-    $edit = array();
-    $edit['title'] = $this->randomName(32);
-    $edit['body']  = $this->randomName(32);
-    $author_restricted_node = $this->drupalCreateNode($edit);
-
-    $this->drupalLogout();
-
-    $roles = array_keys($basic_user->roles);
-    // The assigned role will be the last in the array.
-    $assigned_role = end($roles);
-    $role_grant = array(
-        'gid' => $assigned_role,
-        'realm' => 'nodeaccess_rid',
-        'grant_view' => '1',
-        'grant_update' => '0',
-        'grant_delete' => '0',
-    );
-    node_access_write_grants($role_restricted_node, array($role_grant), 'nodeaccess_rid');
-
-    $author_grant = array(
-        'gid' => $basic_user->uid,
-        'realm' => 'nodeaccess_author',
-        'grant_view' => '1',
-        'grant_update' => '0',
-        'grant_delete' => '0',
-    );
-
-    node_access_write_grants($author_restricted_node, array($author_grant), 'nodeaccess_author');
-
-    $include_path = get_include_path();
-    set_include_path(DRUPAL_ROOT . '/' . drupal_get_path('module', 'apachesolr') .'/SolrPhpClient/');
-    include_once('Apache/Solr/Service.php');
-    set_include_path($include_path);
-
-    $document = new Apache_Solr_Document();
-    apachesolr_nodeaccess_apachesolr_update_index($document, $role_restricted_node, 'apachesolr_search');
-    $field = 'nodeaccess_' . apachesolr_site_hash() . '_nodeaccess_rid';
-    $this->assertEqual($document->{$field}[0], $assigned_role, 'Solr Document being indexed is restricted by the proper role');
-
-    $document = new Apache_Solr_Document();
-    apachesolr_nodeaccess_apachesolr_update_index($document, $author_restricted_node, 'apachesolr_search');
-    $field = 'nodeaccess_' . apachesolr_site_hash() . '_nodeaccess_author';
-    $this->assertEqual($document->{$field}[0], $basic_user->uid, 'Solr Document being indexed is restricted by the proper author');
-  }
-
-  function testQuery() {
-    $basic_user = $this->basic_user;
-    // Login as basic user
-    $this->drupalLogin($basic_user);
-
-    include_once drupal_get_path('module', 'apachesolr') .'/Solr_Base_Query.php';
-    $query = apachesolr_current_query();
-    $params = array();
-
-    $subquery = apachesolr_nodeaccess_build_subquery($basic_user);
-
-    $roles = array_keys($basic_user->roles);
-    $assigned_role = end($roles);
-
-    $expected_criterion = array(
-      'nodeaccess_all' => 0,
-      'nodeaccess_' . apachesolr_site_hash() . '_all' => 0,
-      'nodeaccess_' . apachesolr_site_hash() . '_nodeaccess_rid' => array(2, $assigned_role),
-      'nodeaccess_' . apachesolr_site_hash() . '_nodeaccess_uid' => $basic_user->uid,
-      'nodeaccess_' . apachesolr_site_hash() . '_nodeaccess_author' => $basic_user->uid,
-    );
-
-    $fields = $subquery->get_filters();
-
-    foreach ($fields as $field) {
-      if (is_array($expected_criterion[$field['#name']])) {
-        $this->assertTrue(in_array($field['#value'], $expected_criterion[$field['#name']]), t('Expected node access grant @name == @value found', array('@name' => $field['#name'], '@value' => $field['#value'])));
-        //This is sorta a bug
-        $found_criterion[$field['#name']] = $expected_criterion[$field['#name']];
-      }
-      else {
-        $this->assertEqual($field['#value'], $expected_criterion[$field['#name']], t('Expected node access grant @name == @value found', array('@name' => $field['#name'], '@value' => $field['#value'])));
-        $found_criterion[$field['#name']] = $expected_criterion[$field['#name']];
-      }
-    }
-
-    $this->assertEqual($expected_criterion, $found_criterion, 'All Criteria was accounted for in fields. If not accounted for, Unaccounted Criteria [' . var_export(array_diff($expected_criterion, $found_criterion), 1) . ']');
-  }
-}
diff --git schema.xml schema.xml
index 46750f2..119e78b 100644
--- schema.xml
+++ schema.xml
@@ -11,7 +11,7 @@
  http://wiki.apache.org/solr/SchemaXml
 -->
 
-<schema name="drupal-1.9.6" version="1.2">
+<schema name="drupal-7.1.rc1" version="1.2">
     <!-- attribute "name" is the name of this schema and is only used for display purposes.
          Applications should change this to reflect the nature of the search collection.
          version="1.2" is Solr's version number for the schema syntax and semantics.  It should
@@ -291,47 +291,58 @@
        fields or fields that need an index-time boost need norms.
    -->
 
-<!-- The document id is derived from a site-spcific key (hash) and the node ID like:
+<!-- The document id is derived from a site-spcific key (hash) and the entity type and ID like:
      $document->id = $hash . '/node/' . $node->nid; -->
 
    <field name="id" type="string" indexed="true" stored="true" required="true" />
+   <field name="entity_id"  type="tlong" indexed="true" stored="true" required="true" />
+   <!-- entity is 'node', 'file', 'user', or some other Drupal object type -->
+   <field name="entity" type="string" indexed="true" stored="true" required="true" />
+   <!-- bundle is a node type, or as appropriate for other entity types -->
+   <field name="bundle" type="string" indexed="true" stored="true"/>
+   <field name="bundle_name" type="string" indexed="true" stored="true"/>
+   <!-- legacy: type is a node type, or can be used flexibly for other entity types -->
+   <field name="type" type="string" indexed="true" stored="true"/>
+   <field name="type_name" type="string" indexed="true" stored="true"/>
+   <!-- Copy the bundle to the type so Drupal 6 sites get expected fields in multisite search -->
+   <copyField source="bundle" dest="type"/>
+   <copyField source="bundle_name" dest="type_name"/>
 
-<!-- These are the fields that correspond to a Drupal node. The beauty of having
-     Lucene store title, body, type, etc., is that we retrieve them with the search
-     result set and don't need to go to the database with a node_load. -->
 
    <field name="site" type="string" indexed="true" stored="true"/>
    <field name="hash" type="string" indexed="true" stored="true"/>
    <field name="url" type="string" indexed="true" stored="true"/>
+   <!-- title is the default field for a human-readable string for this entity -->
    <field name="title" type="text" indexed="true" stored="true" termVectors="true" omitNorms="true"/>
    <field name="sort_title" type="sortString" indexed="true" stored="false"/>
+   <!-- body is the default field for full text search - dump crap here -->
    <field name="body" type="text" indexed="true" stored="true" termVectors="true"/>
    <field name="teaser" type="text" indexed="false" stored="true"/>
-   <!-- entity is 'node', 'file', 'user', or some other Drupal object type -->
-   <field name="entity" type="string" indexed="true" stored="true"/>
-   <!-- type is a node type, or can be used flexibly for other entity types -->
-   <field name="type" type="string" indexed="true" stored="true"/>
-   <field name="type_name" type="string" indexed="true" stored="true"/>
+
    <field name="path" type="string" indexed="true" stored="true"/>
    <field name="path_alias" type="text" indexed="true" stored="true" termVectors="true"/>
-   <field name="uid"  type="integer" indexed="true" stored="true"/>
+
+ <!-- These are the fields that correspond to a Drupal node. The beauty of having
+     Lucene store title, body, type, etc., is that we retrieve them with the search
+     result set and don't need to go to the database with a node_load. -->
+   <field name="uid"  type="long" indexed="true" stored="true"/>
    <field name="name" type="text" indexed="true" stored="true" termVectors="true"/>
    <field name="sname" type="string" indexed="true" stored="false"/>
    <field name="sort_name" type="sortString" indexed="true" stored="false"/>
    <field name="created" type="date" indexed="true" stored="true"/>
    <field name="changed" type="date" indexed="true" stored="true"/>
    <field name="last_comment_or_change" type="date" indexed="true" stored="true"/>
-   <field name="nid"  type="integer" indexed="true" stored="true"/>
+   <field name="nid"  type="long" indexed="true" stored="true"/>
    <field name="status" type="boolean" indexed="true" stored="true"/>
    <field name="promote" type="boolean" indexed="true" stored="true"/>
    <field name="moderate" type="boolean" indexed="true" stored="true"/>
    <field name="sticky" type="boolean" indexed="true" stored="true"/>
-   <field name="tnid"  type="integer" indexed="true" stored="true"/>
+   <field name="tnid"  type="long" indexed="true" stored="true"/>
    <field name="translate" type="boolean" indexed="true" stored="true"/>
    <field name="language" type="string" indexed="true" stored="true"/>
    <field name="comment_count" type="integer" indexed="true" stored="true"/>
-   <field name="tid"  type="integer" indexed="true" stored="true" multiValued="true"/>
-   <field name="vid"  type="integer" indexed="true" stored="true" multiValued="true"/>
+   <field name="tid"  type="long" indexed="true" stored="true" multiValued="true"/>
+   <field name="vid"  type="long" indexed="true" stored="true" multiValued="true"/>
    <field name="taxonomy_names" type="text" indexed="true" stored="false" termVectors="true" multiValued="true" omitNorms="true"/>
    <!-- The string version of the title is used for sorting -->
    <copyField source="title" dest="sort_title"/>
@@ -340,15 +351,6 @@
    <copyField source="name" dest="sort_name"/>
    <!-- Copy terms to a single field that contains all taxonomy term names -->
    <copyField source="ts_vid_*" dest="taxonomy_names"/>
-  
-   <!-- A set of fields to contain text extracted from tag contents which we
-        can boost at query time. -->
-   <field name="tags_h1" type="text" indexed="true" stored="false" omitNorms="true"/>
-   <field name="tags_h2_h3" type="text" indexed="true" stored="false" omitNorms="true"/>
-   <field name="tags_h4_h5_h6" type="text" indexed="true" stored="false" omitNorms="true"/>
-   <field name="tags_a" type="text" indexed="true" stored="false" omitNorms="true"/>
-   <!-- Inline tags are typically u, b, i, em, strong -->
-   <field name="tags_inline" type="text" indexed="true" stored="false" omitNorms="true"/>
 
    <!-- Here, default is used to create a "timestamp" field indicating
         when each document was indexed.-->
@@ -371,8 +373,12 @@
         Longer patterns will be matched first.  if equal size patterns
         both match, the first appearing in the schema will be used.  -->
 
-   <dynamicField name="is_*"  type="integer" indexed="true"  stored="true" multiValued="false"/>
-   <dynamicField name="im_*"  type="integer" indexed="true"  stored="true" multiValued="true"/>
+   <!-- A set of fields to contain text extracted from HTML tag contents which we
+        can boost at query time. -->
+   <dynamicField name="tags_*" type="text" indexed="true" stored="false" omitNorms="true"/>
+
+   <dynamicField name="is_*"  type="long" indexed="true"  stored="true" multiValued="false"/>
+   <dynamicField name="im_*"  type="long" indexed="true"  stored="true" multiValued="true"/>
    <dynamicField name="sis_*" type="sint"    indexed="true"  stored="true" multiValued="false"/>
    <dynamicField name="sim_*" type="sint"    indexed="true"  stored="true" multiValued="true"/>
    <dynamicField name="sm_*"  type="string"    indexed="true"  stored="true" multiValued="true"/>
@@ -412,20 +418,7 @@
         Alternately, change the type="ignored" to some other type e.g. "text" if you want
         unknown fields indexed and/or stored by default -->
    <dynamicField name="*" type="ignored" multiValued="true" />
-   
-   
-   
-   <!-- BACKWARDS COMPATIBILITY -->
-   <!-- Here is where we store fields which are no longer used -->
-   
-   <!-- Fields previously used for sorting -->
-   <field name="stitle" type="string" indexed="true" stored="true"/>
-   <field name="title_sort" type="sortString" indexed="true" stored="false"/>
-
-   <field name="name_sort" type="sortString" indexed="true" stored="false"/>
-    
-    
-   <!-- /BACKWARDS COMPATIBILITY -->
+
  </fields>
 
  <!-- Field to use to determine and enforce document uniqueness.
