Полнотекстовый поиск (FTS) SQL Server 2008 года по сравнению с Lucene.NET

У вас здесь пара вариантов. Список немного отличается от массива, когда дело доходит до перетасовки.

Как вы можете видеть ниже, массив быстрее, чем список, а примитивный массив быстрее, чем массив объектов.

Длительность выборки

List<Integer> Shuffle: 43133ns
    Integer[] Shuffle: 31884ns
        int[] Shuffle: 25377ns

Ниже приведены три различные реализации тасования. Вы должны использовать только Collections.shuffle, если вы имеете дело с коллекцией. Нет необходимости обертывать массив в коллекцию, чтобы отсортировать его.

ShuffleUtil Class

import java.lang.reflect.Array;
import java.util.*;

public class ShuffleUtil<T> {
    private static final int[] EMPTY_INT_ARRAY = new int[0];
    private static final int SHUFFLE_THRESHOLD = 5;

    private static Random rand;

Основной метод

    public static void main(String[] args) {
        List<Integer> list = null;
        Integer[] arr = null;
        int[] iarr = null;

        long start = 0;
        int cycles = 1000;
        int n = 1000;

        // Shuffle List<Integer>
        start = System.nanoTime();
        list = range(n);
        for (int i = 0; i < cycles; i++) {
            ShuffleUtil.shuffle(list);
        }
        System.out.printf("%22s: %dns%n", "List<Integer> Shuffle", (System.nanoTime() - start) / cycles);

        // Shuffle Integer[]
        start = System.nanoTime();
        arr = toArray(list);
        for (int i = 0; i < cycles; i++) {
            ShuffleUtil.shuffle(arr);
        }
        System.out.printf("%22s: %dns%n", "Integer[] Shuffle", (System.nanoTime() - start) / cycles);

        // Shuffle int[]
        start = System.nanoTime();
        iarr = toPrimitive(arr);
        for (int i = 0; i < cycles; i++) {
            ShuffleUtil.shuffle(iarr);
        }
        System.out.printf("%22s: %dns%n", "int[] Shuffle", (System.nanoTime() - start) / cycles);
    }

Перетасовка общего списка

    // ================================================================
    // Shuffle List<T> (java.lang.Collections)
    // ================================================================
    @SuppressWarnings("unchecked")
    public static <T> void shuffle(List<T> list) {
        if (rand == null) {
            rand = new Random();
        }
        int size = list.size();
        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
            for (int i = size; i > 1; i--) {
                swap(list, i - 1, rand.nextInt(i));
            }
        } else {
            Object arr[] = list.toArray();

            for (int i = size; i > 1; i--) {
                swap(arr, i - 1, rand.nextInt(i));
            }

            ListIterator<T> it = list.listIterator();
            int i = 0;

            while (it.hasNext()) {
                it.next();
                it.set((T) arr[i++]);
            }
        }
    }

    public static <T> void swap(List<T> list, int i, int j) {
        final List<T> l = list;
        l.set(i, l.set(j, l.get(i)));
    }

    public static <T> List<T> shuffled(List<T> list) {
        List<T> copy = copyList(list);
        shuffle(copy);
        return copy;
    }

Перетасовка общего массива

    // ================================================================
    // Shuffle T[]
    // ================================================================
    public static <T> void shuffle(T[] arr) {
        if (rand == null) {
            rand = new Random();
        }

        for (int i = arr.length - 1; i > 0; i--) {
            swap(arr, i, rand.nextInt(i + 1));
        }
    }

    public static <T> void swap(T[] arr, int i, int j) {
        T tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static <T> T[] shuffled(T[] arr) {
        T[] copy = Arrays.copyOf(arr, arr.length);
        shuffle(copy);
        return copy;
    }

Перемешивание примитивного массива

    // ================================================================
    // Shuffle int[]
    // ================================================================
    public static <T> void shuffle(int[] arr) {
        if (rand == null) {
            rand = new Random();
        }

        for (int i = arr.length - 1; i > 0; i--) {
            swap(arr, i, rand.nextInt(i + 1));
        }
    }

    public static <T> void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static int[] shuffled(int[] arr) {
        int[] copy = Arrays.copyOf(arr, arr.length);
        shuffle(copy);
        return copy;
    }

Утилиты

Простые методы утилиты для копирования и преобразования массивов в списки и наоборот.

    // ================================================================
    // Utility methods
    // ================================================================
    protected static <T> List<T> copyList(List<T> list) {
        List<T> copy = new ArrayList<T>(list.size());
        for (T item : list) {
            copy.add(item);
        }
        return copy;
    }

    protected static int[] toPrimitive(Integer[] array) {
        if (array == null) {
            return null;
        } else if (array.length == 0) {
            return EMPTY_INT_ARRAY;
        }
        final int[] result = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            result[i] = array[i].intValue();
        }
        return result;
    }

    protected static Integer[] toArray(List<Integer> list) {
        return toArray(list, Integer.class);
    }

    protected static <T> T[] toArray(List<T> list, Class<T> clazz) {
        @SuppressWarnings("unchecked")
        final T[] arr = list.toArray((T[]) Array.newInstance(clazz, list.size()));
        return arr;
    }

Range Class

Генерирует диапазон значений, аналогичный функции range Python.

    // ================================================================
    // Range class for generating a range of values.
    // ================================================================
    protected static List<Integer> range(int n) {
        return toList(new Range(n), new ArrayList<Integer>());
    }

    protected static <T> List<T> toList(Iterable<T> iterable) {
        return toList(iterable, new ArrayList<T>());
    }

    protected static <T> List<T> toList(Iterable<T> iterable, List<T> destination) {
        addAll(destination, iterable.iterator());

        return destination;
    }

    protected static <T> void addAll(Collection<T> collection, Iterator<T> iterator) {
        while (iterator.hasNext()) {
            collection.add(iterator.next());
        }
    }

    private static class Range implements Iterable<Integer> {
        private int start;
        private int stop;
        private int step;

        private Range(int n) {
            this(0, n, 1);
        }

        private Range(int start, int stop) {
            this(start, stop, 1);
        }

        private Range(int start, int stop, int step) {
            this.start = start;
            this.stop = stop;
            this.step = step;
        }

        @Override
        public Iterator<Integer> iterator() {
            final int min = start;
            final int max = stop / step;

            return new Iterator<Integer>() {
                private int current = min;

                @Override
                public boolean hasNext() {
                    return current < max;
                }

                @Override
                public Integer next() {
                    if (hasNext()) {
                        return current++ * step;
                    } else {
                        throw new NoSuchElementException("Range reached the end");
                    }
                }

                @Override
                public void remove() {
                    throw new UnsupportedOperationException("Can't remove values from a Range");
                }
            };
        }
    }
}
41
задан ajma 1 February 2009 в 07:12
поделиться

5 ответов

Я создал базу знаний среднего размера (возможно, 2 ГБ индексируемого текста) сверху FTS 2005 SQL Server в 2006 и теперь переместил его в iFTS 2008. Обе ситуации работали хорошо на меня, но перемещение с 2005 до 2008 было на самом деле улучшением для меня.

Моя ситуация не была похожа на StackOverflow в том смысле, что я индексировал данные, которые были только обновлены ночью, однако я пытался присоединиться, результаты поиска от нескольких операторов CONTAINSTABLE въезжают задним ходом друг другу и к реляционным таблицам.

В FTS 2005, это означало, что каждый CONTAINSTABLE должен будет выполнить свой поиск на индексе, возвратиться, полные результаты и затем иметь механизм DB соединяют те результаты с реляционными таблицами (это было все очевидно для меня, но он происходил и был дорог к запросам). iFTS 2008 улучшил эту ситуацию, потому что интеграция базы данных позволяет нескольким результатам CONTAINSTABLE становиться частью плана запросов, который сделал много из поисков более эффективным.

я думаю, что и 2005 и механизмы FTS 2008, а также Lucene.NET, имеют архитектурные компромиссы, которые собираются выровняться лучше или хуже к большому количеству обстоятельств проекта - я просто стал удачливым, что обновление работало в мою пользу. Я могу полностью видеть, почему iFTS 2008 не работал бы в той же конфигурации 2005 для высоко природа OLTP варианта использования как StackOverflow.com. Однако я не обесценил бы возможность, что 2008 iFTS мог быть изолирован от тяжелой загрузки транзакции вставки..., но она также кажется, что это могло быть столько же работы для выполнения этого сколько перемещение на Lucene.NET..., и прохладный фактор Lucene.NET трудно проигнорировать ;)

Так или иначе, для меня, простота и эффективность iFTS 2008 SQL в большинстве ситуаций, вероятно, вычеркивают 'прохладный' фактор Lucene (хотя это просто в использовании, я никогда не использовал ее в производственной системе, таким образом, я резервирую комментарий к этому). Я был бы интересен в знании, сколько еще эффективный Lucene (оказался? это реализовано теперь?) в StackOverflow или аналогичных ситуациях.

16
ответ дан ZeroBugBounce 4 August 2019 в 21:55
поделиться

SQL Server FTS будет легче справиться для небольшого развертывания. Так как FTS интегрируется с DB, дескрипторы RDBMS, обновляющие индекс автоматически. Довод "против" здесь - то, что у Вас нет очевидного решения для масштабирования за исключением тиражирования DB. Таким образом, если Вы не должны масштабироваться, SQL Server, FTS, вероятно, "более безопасен". С политической точки зрения большинство магазинов будет более довольным чистым решением для SQL Server.

На стороне Lucene, я одобрил бы SOLR по прямому Lucene. С любым решением необходимо сделать больше работы, сами обновляющей индекс, когда данные изменяются, а также отображающиеся данные сами к индексу SOLR/Lucene. Профессионалы - то, что можно легко масштабироваться путем добавления дополнительных индексов. Вы могли выполнить эти индексы на очень минимизированных серверах Linux, который устраняет некоторую стоимость лицензии. Если бы Вы следуете маршрутом Lucene/SOLR, я стремился бы помещать ВСЕ данные, в которых Вы нуждаетесь непосредственно в индекс, вместо того, чтобы отложить указатели на DB в индексе. Можно включать данные в индекс, который не доступен для поиска, так например, Вы, возможно, предварительно создали HTML или XML, сохраненный в индексе, и подаете его как результат поиска. С этим подходом мог снизиться Ваш DB, но Вы все еще можете подать результаты поиска в разъединенном режиме.

я никогда не видел сравнение производительности лицом к лицу SQL Server 2008 и Lucene, но хотел бы видеть тот.

19
ответ дан Lee Harold 4 August 2019 в 21:55
поделиться

Одно соображение, что необходимо иметь в виду, состоит в том, какие поисковые ограничения Вы имеете в дополнение к полнотекстовому ограничению. При выполнении ограничений, которые не может обеспечить lucene, то Вы почти наверняка захотите использовать FTS. Одна из хороших вещей приблизительно в 2008 - то, что они улучшили интеграцию FTS со стандартными запросами SQL-сервера, таким образом, производительность должна быть лучше со смешанной базой данных и ограничениями FT, чем это было в 2005.

0
ответ дан harmanjd 4 August 2019 в 21:55
поделиться

мы используем и возможности полнотекстового поиска, но по-моему это зависит от самих данных и Ваших потребностей.

мы масштабируемся с веб-серверами, и поэтому мне нравится lucene, потому что у меня нет так большой нагрузки на SQL-сервер.

для запуска в пустом указателе и желании иметь полное-textsearch я предпочел бы решение SQL-сервера, потому что я думаю, что это действительно быстро для получения результатов, если Вы хотите lucene, необходимо реализовать больше в запуске (и также получить некоторое ноу-хау).

4
ответ дан karlis 4 August 2019 в 21:55
поделиться

Это могло бы помочь: http://blog.stackoverflow.com/2008/11/sql-2008-full-text-search-problems/

не использовал SQL Server 2008 лично, хотя на основе той записи в блоге, похоже, что функциональность полнотекстового поиска медленнее, чем это было в 2005.

4
ответ дан Mun 4 August 2019 в 21:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: