У вас здесь пара вариантов. Список немного отличается от массива, когда дело доходит до перетасовки.
Как вы можете видеть ниже, массив быстрее, чем список, а примитивный массив быстрее, чем массив объектов.
List<Integer> Shuffle: 43133ns
Integer[] Shuffle: 31884ns
int[] Shuffle: 25377ns
Ниже приведены три различные реализации тасования. Вы должны использовать только Collections.shuffle, если вы имеете дело с коллекцией. Нет необходимости обертывать массив в коллекцию, чтобы отсортировать его.
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
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");
}
};
}
}
}
Я создал базу знаний среднего размера (возможно, 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 или аналогичных ситуациях.
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, но хотел бы видеть тот.
Одно соображение, что необходимо иметь в виду, состоит в том, какие поисковые ограничения Вы имеете в дополнение к полнотекстовому ограничению. При выполнении ограничений, которые не может обеспечить lucene, то Вы почти наверняка захотите использовать FTS. Одна из хороших вещей приблизительно в 2008 - то, что они улучшили интеграцию FTS со стандартными запросами SQL-сервера, таким образом, производительность должна быть лучше со смешанной базой данных и ограничениями FT, чем это было в 2005.
мы используем и возможности полнотекстового поиска, но по-моему это зависит от самих данных и Ваших потребностей.
мы масштабируемся с веб-серверами, и поэтому мне нравится lucene, потому что у меня нет так большой нагрузки на SQL-сервер.
для запуска в пустом указателе и желании иметь полное-textsearch я предпочел бы решение SQL-сервера, потому что я думаю, что это действительно быстро для получения результатов, если Вы хотите lucene, необходимо реализовать больше в запуске (и также получить некоторое ноу-хау).
Это могло бы помочь: http://blog.stackoverflow.com/2008/11/sql-2008-full-text-search-problems/
не использовал SQL Server 2008 лично, хотя на основе той записи в блоге, похоже, что функциональность полнотекстового поиска медленнее, чем это было в 2005.