Как реализовать автоматическое использование с помощью нового API AnalyzerInfixSuggester от Lucene?

Я нахожусь в руке на Lucene, и я хочу реализовать автоматическое предложение, точно так же, как google, когда я вводил символ типа «G», он дал бы мне список, вы можете попробовать себя.

У меня есть поиск по всей сети. Никто этого не сделал, и это дает нам некоторые новые инструменты в пакете.

Но мне нужен пример, чтобы рассказать мне, как это сделать

Кто-нибудь может помочь?

Я дам вам довольно полный пример, показывающий, как использовать AnalyzingInfixSuggester . В этом примере мы притворимся, что мы Amazon, и мы хотим автозаполнять поле поиска продукта. Мы воспользуемся преимуществами системы предложений Lucene, чтобы реализовать следующее:

  1. Ранжированные результаты: Мы сначала предложим наиболее популярные продукты.
  2. Ограниченные регионом результаты: мы будем предлагать только продукты, которые мы продаем в стране клиента.
  3. Фотографии продукта. Мы будем хранить URL-адреса продуктов в индексе предложения, чтобы мы могли отображать их в результатах поиска, не требуя дополнительного поиска базы данных.

Сначала я определю простой class для хранения информации о продукте в Product.java:

 import java.util.Set; class Product implements java.io.Serializable { String name; String image; String[] regions; int numberSold; public Product(String name, String image, String[] regions, int numberSold) { this.name = name; this.image = image; this.regions = regions; this.numberSold = numberSold; } } 

Чтобы индексировать записи с помощью метода build AnalyzingInfixSuggester вам необходимо передать ему объект, реализующий интерфейс org.apache.lucene.search.suggest.InputIterator . InputIterator предоставляет доступ к ключу , контекстам , полезной нагрузке и весу для каждой записи.

Ключ – это текст, который вы хотите найти, и автозаполнение. В нашем примере это будет название продукта.

Контексты представляют собой набор дополнительных произвольных данных, которые можно использовать для фильтрации записей. В нашем примере контексты представляют собой набор ISO-кодов для стран, в которые мы отправим конкретный продукт.

Полезная нагрузка – это дополнительные произвольные данные, которые вы хотите сохранить в индексе для записи. В этом примере мы фактически сериализуем каждый экземпляр Product и сохраняем полученные байты в качестве полезной нагрузки. Затем, когда мы позже выполняем поиск, мы можем десериализовать полезную нагрузку и информацию о доступе в экземпляре продукта, таком как URL изображения.

Вес используется для заказа предложений; результаты с более высоким весом возвращаются в первую очередь. Мы будем использовать количество продаж для данного продукта в качестве его веса.

Вот содержимое ProductIterator.java:

 import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.UnsupportedEncodingException; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.apache.lucene.search.suggest.InputIterator; import org.apache.lucene.util.BytesRef; class ProductIterator implements InputIterator { private Iterator productIterator; private Product currentProduct; ProductIterator(Iterator productIterator) { this.productIterator = productIterator; } public boolean hasContexts() { return true; } public boolean hasPayloads() { return true; } public Comparator getComparator() { return null; } // This method needs to return the key for the record; this is the // text we'll be autocompleting against. public BytesRef next() { if (productIterator.hasNext()) { currentProduct = productIterator.next(); try { return new BytesRef(currentProduct.name.getBytes("UTF8")); } catch (UnsupportedEncodingException e) { throw new Error("Couldn't convert to UTF-8"); } } else { return null; } } // This method returns the payload for the record, which is // additional data that can be associated with a record and // returned when we do suggestion lookups. In this example the // payload is a serialized Java object representing our product. public BytesRef payload() { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bos); out.writeObject(currentProduct); out.close(); return new BytesRef(bos.toByteArray()); } catch (IOException e) { throw new Error("Well that's unfortunate."); } } // This method returns the contexts for the record, which we can // use to restrict suggestions. In this example we use the // regions in which a product is sold. public Set contexts() { try { Set regions = new HashSet(); for (String region : currentProduct.regions) { regions.add(new BytesRef(region.getBytes("UTF8"))); } return regions; } catch (UnsupportedEncodingException e) { throw new Error("Couldn't convert to UTF-8"); } } // This method helps us order our suggestions. In this example we // use the number of products of this type that we've sold. public long weight() { return currentProduct.numberSold; } } 

В нашей программе драйверов мы сделаем следующее:

  1. Создайте индексный каталог в ОЗУ.
  2. Создайте StandardTokenizer .
  3. Создайте AnalyzingInfixSuggester используя каталог RAM и токенизатор.
  4. Индексируйте ряд продуктов, используя ProductIterator .
  5. Распечатайте результаты некоторых выборочных поисков.

Вот программа драйвера, SuggestProducts.java:

 import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.search.suggest.analyzing.AnalyzingInfixSuggester; import org.apache.lucene.search.suggest.Lookup; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.Version; public class SuggestProducts { // Get suggestions given a prefix and a region. private static void lookup(AnalyzingInfixSuggester suggester, String name, String region) { try { List results; HashSet contexts = new HashSet(); contexts.add(new BytesRef(region.getBytes("UTF8"))); // Do the actual lookup. We ask for the top 2 results. results = suggester.lookup(name, contexts, 2, true, false); System.out.println("-- \"" + name + "\" (" + region + "):"); for (Lookup.LookupResult result : results) { System.out.println(result.key); Product p = getProduct(result); if (p != null) { System.out.println(" image: " + p.image); System.out.println(" # sold: " + p.numberSold); } } } catch (IOException e) { System.err.println("Error"); } } // Deserialize a Product from a LookupResult payload. private static Product getProduct(Lookup.LookupResult result) { try { BytesRef payload = result.payload; if (payload != null) { ByteArrayInputStream bis = new ByteArrayInputStream(payload.bytes); ObjectInputStream in = new ObjectInputStream(bis); Product p = (Product) in.readObject(); return p; } else { return null; } } catch (IOException|ClassNotFoundException e) { throw new Error("Could not decode payload :("); } } public static void main(String[] args) { try { RAMDirectory index_dir = new RAMDirectory(); StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_48); AnalyzingInfixSuggester suggester = new AnalyzingInfixSuggester( Version.LUCENE_48, index_dir, analyzer); // Create our list of products. ArrayList products = new ArrayList(); products.add( new Product( "Electric Guitar", "http://sofru.miximages.com/java/electric-guitar.jpg", new String[]{"US", "CA"}, 100)); products.add( new Product( "Electric Train", "http://sofru.miximages.com/java/train.jpg", new String[]{"US", "CA"}, 100)); products.add( new Product( "Acoustic Guitar", "http://sofru.miximages.com/java/acoustic-guitar.jpg", new String[]{"US", "ZA"}, 80)); products.add( new Product( "Guarana Soda", "http://sofru.miximages.com/java/soda.jpg", new String[]{"ZA", "IE"}, 130)); // Index the products with the suggester. suggester.build(new ProductIterator(products.iterator())); // Do some example lookups. lookup(suggester, "Gu", "US"); lookup(suggester, "Gu", "ZA"); lookup(suggester, "Gui", "CA"); lookup(suggester, "Electric guit", "US"); } catch (IOException e) { System.err.println("Error!"); } } } 

И вот вывод из программы драйвера:

 -- "Gu" (US): Electric Guitar image: http://images.example/electric-guitar.jpg # sold: 100 Acoustic Guitar image: http://images.example/acoustic-guitar.jpg # sold: 80 -- "Gu" (ZA): Guarana Soda image: http://images.example/soda.jpg # sold: 130 Acoustic Guitar image: http://images.example/acoustic-guitar.jpg # sold: 80 -- "Gui" (CA): Electric Guitar image: http://images.example/electric-guitar.jpg # sold: 100 -- "Electric guit" (US): Electric Guitar image: http://images.example/electric-guitar.jpg # sold: 100 

аппендикс

Есть способ избежать написания полного InputIterator , который может оказаться проще. Вы можете написать заглушку InputIterator которая возвращает null из своих next , payload и contexts методов. Передайте экземпляр этого метода методу AnalyzingInfixSuggester :

 suggester.build(new ProductIterator(new ArrayList().iterator())); 

Затем для каждого элемента, который вы хотите проиндексировать, вызовите метод add AnalyzingInfixSuggester add :

 suggester.add(text, contexts, weight, payload) 

После того, как вы проиндексировали все, вызовите refresh :

 suggester.refresh(); 

Если вы индексируете большие объемы данных, можно значительно ускорить индексирование с помощью этого метода с несколькими streamами: вызывать build , затем использовать несколько streamов для add элементов, а затем, наконец, вызвать refresh .

[Отредактировано 2015-04-23, чтобы продемонстрировать десериализацию информации из полезной нагрузки LookupResult .]

Interesting Posts

Android AsyncTask для длительных операций

Взлом для запуска нескольких iMacros случайным образом

R подавляет запуск сообщений от зависимости

Как установить значки и описание типов файлов, связанных с Notepad ++?

Проблема с PictureBox

Маршрутизация трафика на определенные веб-сайты через Ethernet, отдых через Wi-Fi в Mac OS X 10.6?

android.app.Application нельзя использовать для android.app.Activity

Возможно ли создать FORMAT внешний жесткий диск, который был зашифрован с помощью Storagecrypt?

Получение растрового изображения из векторного рисунка

Что должно быть в моем .gitignore для проекта Android Studio?

Как предотвратить автоматическое опорожнение удаленных элементов при выходе из Outlook 2010?

Как настроить кнопку Добавить в jqGrid?

Как опубликовать представление / преобразование коллекции в Meteor?

Как написать xml с пространством имен и префиксом с XElement?

Статус HTTP 404 – запрашиваемый ресурс (/ имя_проекта /) недоступен

Давайте будем гением компьютера.