def update(self, index, iterable, commit=True):
        """
        Updates the `index` with any objects in `iterable` by adding/updating
        the database as needed.

        Required arguments:
            `index` -- The `SearchIndex` to process
            `iterable` -- An iterable of model instances to index
        Optional arguments:
            `commit` -- ignored

        For each object in `iterable`, a document is created containing all
        of the terms extracted from `index.full_prepare(obj)` with field prefixes,
        and 'as-is' as needed.  Also, if the field type is 'text' it will be
        stemmed and stored with the 'Z' prefix as well.

        eg. `content:Testing` ==> `testing, Ztest, ZXCONTENTtest, XCONTENTtest`

        Each document also contains an extra term in the format:

        `XCONTENTTYPE<app_name>.<model_name>`

        As well as a unique identifier in the the format:

        `Q<app_name>.<model_name>.<pk>`

        eg.: foo.bar (pk=1) ==> `Qfoo.bar.1`, `XCONTENTTYPEfoo.bar`

        This is useful for querying for a specific document corresponding to
        a model instance.

        The document also contains a pickled version of the object itself and
        the document ID in the document data field.

        Finally, we also store field values to be used for sorting data.  We
        store these in the document value slots (position zero is reserver
        for the document ID).  All values are stored as unicode strings with
        conversion of float, int, double, values being done by Xapian itself
        through the use of the :method:xapian.sortable_serialise method.
        """
        database = self._database(writable=True)

        try:
            term_generator = xapian.TermGenerator()
            term_generator.set_database(database)
            term_generator.set_stemmer(xapian.Stem(self.language))
            try:
                term_generator.set_stemming_strategy(self.stemming_strategy)
            except AttributeError:  
                # Versions before Xapian 1.2.11 do not support stemming strategies for TermGenerator
                pass
            if self.include_spelling is True:
                term_generator.set_flags(xapian.TermGenerator.FLAG_SPELLING)

            def _add_text(termpos, text, weight, prefix=''):
                """
                indexes text appending 2 extra terms
                to identify beginning and ending of the text.
                """
                term_generator.set_termpos(termpos)

                start_term = '%s^' % prefix
                end_term = '%s$' % prefix
                # add begin
                document.add_posting(start_term, termpos, weight)
                # add text
                term_generator.index_text(text, weight, prefix)
                termpos = term_generator.get_termpos()
                # add ending
                termpos += 1
                document.add_posting(end_term, termpos, weight)

                # increase termpos
                term_generator.set_termpos(termpos)
                term_generator.increase_termpos(TERMPOS_DISTANCE)

                return term_generator.get_termpos()

            def _add_literal_text(termpos, text, weight, prefix=''):
                """
                Adds sentence to the document with positional information
                but without processing.

                The sentence is bounded by "^" "$" to allow exact matches.
                """
                text = '^ %s $' % text
                for word in text.split():
                    term = '%s%s' % (prefix, word)
                    document.add_posting(term, termpos, weight)
                    termpos += 1
                termpos += TERMPOS_DISTANCE
                return termpos

            def add_text(termpos, prefix, text, weight):
                """
                Adds text to the document with positional information
                and processing (e.g. stemming).
                """
                termpos = _add_text(termpos, text, weight, prefix=prefix)
                termpos = _add_text(termpos, text, weight, prefix='')
                termpos = _add_literal_text(termpos, text, weight, prefix=prefix)
                termpos = _add_literal_text(termpos, text, weight, prefix='')
                return termpos

            def _get_ngram_lengths(value):
                values = value.split()
                for item in values:
                    for ngram_length in six.moves.range(NGRAM_MIN_LENGTH, NGRAM_MAX_LENGTH + 1):
                        yield item, ngram_length

            for obj in iterable:
                document = xapian.Document()
                term_generator.set_document(document)

                def ngram_terms(value):
                    for item, length in _get_ngram_lengths(value):
                        item_length = len(item)
                        for start in six.moves.range(0, item_length - length + 1):
                            for size in six.moves.range(length, length + 1):
                                end = start + size
                                if end > item_length:
                                    continue
                                yield _to_xapian_term(item[start:end])

                def edge_ngram_terms(value):
                    for item, length in _get_ngram_lengths(value):
                        yield _to_xapian_term(item[0:length])

                def add_edge_ngram_to_document(prefix, value, weight):
                    """
                    Splits the term in ngrams and adds each ngram to the index.
                    The minimum and maximum size of the ngram is respectively
                    NGRAM_MIN_LENGTH and NGRAM_MAX_LENGTH.
                    """
                    for term in edge_ngram_terms(value):
                        document.add_term(term, weight)
                        document.add_term(prefix + term, weight)

                def add_ngram_to_document(prefix, value, weight):
                    """
                    Splits the term in ngrams and adds each ngram to the index.
                    The minimum and maximum size of the ngram is respectively
                    NGRAM_MIN_LENGTH and NGRAM_MAX_LENGTH.
                    """
                    for term in ngram_terms(value):
                        document.add_term(term, weight)
                        document.add_term(prefix + term, weight)

                def add_non_text_to_document(prefix, term, weight):
                    """
                    Adds term to the document without positional information
                    and without processing.

                    If the term is alone, also adds it as "^<term>$"
                    to allow exact matches on single terms.
                    """
                    document.add_term(term, weight)
                    document.add_term(prefix + term, weight)

                def add_datetime_to_document(termpos, prefix, term, weight):
                    """
                    Adds a datetime to document with positional order
                    to allow exact matches on it.
                    """
                    date, time = term.split()
                    document.add_posting(date, termpos, weight)
                    termpos += 1
                    document.add_posting(time, termpos, weight)
                    termpos += 1
                    document.add_posting(prefix + date, termpos, weight)
                    termpos += 1
                    document.add_posting(prefix + time, termpos, weight)
                    termpos += TERMPOS_DISTANCE + 1
                    return termpos

                data = index.full_prepare(obj)
                weights = index.get_field_weights()

                termpos = term_generator.get_termpos()  # identifies the current position in the document.
                for field in self.schema:
                    if field['field_name'] not in list(data.keys()):
                        # not supported fields are ignored.
                        continue

                    if field['field_name'] in weights:
                        weight = int(weights[field['field_name']])
                    else:
                        weight = 1

                    value = data[field['field_name']]

                    if field['field_name'] in (ID, DJANGO_ID, DJANGO_CT):
                        # Private fields are indexed in a different way:
                        # `django_id` is an int and `django_ct` is text;
                        # besides, they are indexed by their (unstemmed) value.
                        if field['field_name'] == DJANGO_ID:
                            value = int(value)
                        value = _term_to_xapian_value(value, field['type'])

                        document.add_term(TERM_PREFIXES[field['field_name']] + value, weight)
                        document.add_value(field['column'], value)
                        continue
                    else:
                        prefix = TERM_PREFIXES['field'] + field['field_name'].upper()

                        # if not multi_valued, we add as a document value
                        # for sorting and facets
                        if field['multi_valued'] == 'false':
                            document.add_value(field['column'], _term_to_xapian_value(value, field['type']))
                        else:
                            for t in value:
                                # add the exact match of each value
                                term = _to_xapian_term(t)
                                termpos = add_text(termpos, prefix, term, weight)
                            continue

                        term = _to_xapian_term(value)
                        if term == '':
                            continue
                        # from here on the term is a string;
                        # we now decide how it is indexed

                        if field['type'] == 'text':
                            # text is indexed with positional information
                            termpos = add_text(termpos, prefix, term, weight)
                        elif field['type'] == 'datetime':
                            termpos = add_datetime_to_document(termpos, prefix, term, weight)
                        elif field['type'] == 'ngram':
                            add_ngram_to_document(prefix, value, weight)
                        elif field['type'] == 'edge_ngram':
                            add_edge_ngram_to_document(prefix, value, weight)
                        else:
                            # all other terms are added without positional information
                            add_non_text_to_document(prefix, term, weight)

                # store data without indexing it
                document.set_data(pickle.dumps(
                    (obj._meta.app_label, obj._meta.model_name, obj.pk, data),
                    pickle.HIGHEST_PROTOCOL
                ))

                # add the id of the document
                document_id = TERM_PREFIXES[ID] + get_identifier(obj)
                document.add_term(document_id)

                # finally, replace or add the document to the database
                database.replace_document(document_id, document)

        except UnicodeDecodeError:
            sys.stderr.write('Chunk failed.\n')
            pass

        finally:
            database.close()
Updates the `index` with any objects in `iterable` by adding/updating
        the database as needed.

        Required arguments:
            `index` -- The `SearchIndex` to process
            `iterable` -- An iterable of model instances to index
        Optional arguments:
            `commit` -- ignored

        For each object in `iterable`, a document is created containing all
        of the terms extracted from `index.full_prepare(obj)` with field prefixes,
        and 'as-is' as needed.  Also, if the field type is 'text' it will be
        stemmed and stored with the 'Z' prefix as well.

        eg. `content:Testing` ==> `testing, Ztest, ZXCONTENTtest, XCONTENTtest`

        Each document also contains an extra term in the format:

        `XCONTENTTYPE<app_name>.<model_name>`

        As well as a unique identifier in the the format:

        `Q<app_name>.<model_name>.<pk>`

        eg.: foo.bar (pk=1) ==> `Qfoo.bar.1`, `XCONTENTTYPEfoo.bar`

        This is useful for querying for a specific document corresponding to
        a model instance.

        The document also contains a pickled version of the object itself and
        the document ID in the document data field.

        Finally, we also store field values to be used for sorting data.  We
        store these in the document value slots (position zero is reserver
        for the document ID).  All values are stored as unicode strings with
        conversion of float, int, double, values being done by Xapian itself
        through the use of the :method:xapian.sortable_serialise method.