Что такое Люсен? ?
Lucene — это набор инструментов для полнотекстового поиска с открытым исходным кодом, выпущенный Apache Software Foundation, написанный старшим экспертом по полнотекстовому поиску Дугом Каттингом.Архитектура полнотекстовой поисковой системы, обеспечивает полное создание индекса и индекс запроса, а также механизм частичного анализа текста, цель Lucene — предоставить разработчикам программного обеспечения простой в использовании набор инструментов для облегчения реализации функций полнотекстового поиска в целевой системе или использовать На основе этого создается полноценная полнотекстовая поисковая система.Lucene — классический родоначальник в области полнотекстового поиска.Сейчас на этой основе создается множество поисковых систем, и идеи те же.
Lucene — это инструмент текстового поиска, который выполняет поиск по ключевым словам. Он может искать текстовое содержимое только внутри веб-сайта, а не между веб-сайтами.
Раз уж мы говорили о поиске внутри сайта, давайте поговорим о том, на чем основаны знакомые нам поисковые системы Baidu и Google...
Из картинки видно, чтоПоисковые системы, такие как baidu и google, на самом деле выполняют поиск с помощью поисковых роботов....
Почему мы используем Lucene?
При введении Lucene мы уже сказали: Lucene не является поисковой системой, это простоВнутри сайтапровеститекстпоиск. Тогда почему мы должны учиться у него? ? ?
Когда мы раньше писали систему налоговой службы, мы фактически ужеИспользовал SQL для поиска по сайту..
Поскольку SQL может выполнять функции, мы должны изучить Lucene, почему? ? ?
Давайте рассмотрим недостатки использования SQL для поиска:
- (1) SQL может выполнять поиск только по таблицам базы данных,Не удается выполнить прямой поиск текста на жестком диске
- (2)SQL не имеет рейтинга релевантности
- (3)Результаты поиска SQL без выделения ключевых слов
- (4)SQL требует поддержки базы данных, сама база данных требует больших накладных расходов на память, например: Oracle
- (5)Поиск SQL иногда замедляется, особенно когда БД не локальная, супер медленная, например: Oracle
Давайте посмотрим, как это выглядит при поиске Lucene в baidu по ключевым словам:
Как упоминалось выше, мы не можем этого сделать, если используем SQL. Итак, мы учимсяLucene, чтобы помочь нам искать данные на основе текстовых ключевых слов на сайте.!
Если нашему веб-сайту необходимо выполнять поиск по ключевым словам, мы можем использовать SQL или Lucene... тогда мыLucene и SQL одинаковы, оба закодированы на уровне персистентности.. .
1. Быстрый старт
Далее мы объясним, как использовать Lucene... Прежде чем объяснять API Lucene, давайте сначала поговорим о том, что Lucene хранит... Наш SQL использует память в базе данных, которая хранится на жестком диске.Файл DBF посередине. .. Так что же внутри нашего Lucene? ?
В Lucene хранитсяРяд бинарных сжатых файлов и некоторые управляющие файлы, которые расположены на жестком диске компьютера,Это содержимое вместе называется индексной библиотекой., библиотека индексов состоит из двух частей:
- (1)Оригинальная запись
- Исходный текст, хранящийся в индексной библиотеке, например: Я Чжун Фучэн.
- (2)Глоссарий
- После разделения каждого символа в исходной записи в соответствии с определенной стратегией разделения (например, токенизатором) он сохраняется в таблице для будущего поиска.
Это:Место, где Lucene хранит данные, обычно называется индексной библиотекой, а индексная библиотека делится на две части: исходная запись и словарь.....
1.1 Оригинальные записи и глоссарий
Когда мы хотим сохранить данные в репозитории индексов, первое, что мы сохраняем, — это сохранение данных в исходной записи. …
И поскольку, когда мы используем его для пользователя, пользовательИспользование ключевых слов для запроса наших конкретных записей. Поэтому нам нужно поставить нашуИсходные сохраненные данные разделены! будетРазделенные данные хранятся в словаре.
Словарь похож на индексную таблицу, которую мы изучаем в Oracle.При разделении будет задано соответствующее значение индекса.
Когда пользователи выполняют поиск по ключевым словам,Затем программа сначала проверит, существует ли ключевое слово в словаре, и если ключевое слово есть, она найдет исходную таблицу записей и вернет исходные записи, соответствующие условиям, пользователю для просмотра..
Давайте посмотрим на следующую схему для легкого понимания:
На этом этапе некоторые люди могут спросить: разделены ли данные исходной записью один за другим? ? Тогда не много ли ключевых слов в глоссарии? ? ?
На самом деле, когда мы сохраняем в исходной таблице записей, мы можем указать, какой алгоритм мы используем для разделения данных и сохранения их в словаре... НашИзображение представляет собой стандартный алгоритм сегментации слов Lucene, разбивающий китайские символы один за другим.. Мы можем использовать другие алгоритмы сегментации слов, разбиения два на два или другие алгоритмы.
1.2 Написание первой программы Lucene
Во-первых, давайте импортируем необходимые пакеты разработки для Lucene:
- lucene-core-3.0.2.jar [ядро Lucene]
- lucene-analyzers-3.0.2.jar [разделитель слов]
- lucene-highlighter-3.0.2.jar [Lucene выделит искомые слова и предложит пользователю]
- lucene-memory-3.0.2.jar [стратегия оптимизации библиотеки индексов]
Создайте объект User, объект User инкапсулирует данные....
/**
* Created by ozc on 2017/7/12.
*/
public class User {
private String id ;
private String userName;
private String sal;
public User() {
}
public User(String id, String userName, String sal) {
this.id = id;
this.userName = userName;
this.sal = sal;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getSal() {
return sal;
}
public void setSal(String sal) {
this.sal = sal;
}
}
Мы хотим использовать Lucene для запроса исходящих данных, прежде всего нам нужна библиотека индексов! тогдаСначала мы создаем библиотеку индексов и сохраняем наши данные в библиотеке индексов..
Шаги для создания библиотеки индексов:
- 1)Создание объектов JavaBean
- 2)Создать объект документа
- 3)Поместите все значения атрибутов объекта JavaBean в объект Document, имя атрибута может быть таким же или отличным от JavaBean
- 4)Создайте объект IndexWriter
- 5)Запишите объект Document в библиотеку индексов через объект IndexWriter.
- 6)Закройте объект IndexWriter.
@Test
public void createIndexDB() throws Exception {
//把数据填充到JavaBean对象中
User user = new User("1", "钟福成", "未来的程序员");
//创建Document对象【导入的是Lucene包下的Document对象】
Document document = new Document();
//将JavaBean对象所有的属性值,均放到Document对象中去,属性名可以和JavaBean相同或不同
/**
* 向Document对象加入一个字段
* 参数一:字段的关键字
* 参数二:字符的值
* 参数三:是否要存储到原始记录表中
* YES表示是
* NO表示否
* 参数四:是否需要将存储的数据拆分到词汇表中
* ANALYZED表示拆分
* NOT_ANALYZED表示不拆分
*
* */
document.add(new Field("id", user.getId(), Field.Store.YES, Field.Index.ANALYZED));
document.add(new Field("userName", user.getUserName(), Field.Store.YES, Field.Index.ANALYZED));
document.add(new Field("sal", user.getSal(), Field.Store.YES, Field.Index.ANALYZED));
//创建IndexWriter对象
//目录指定为E:/createIndexDB
Directory directory = FSDirectory.open(new File("E:/createIndexDB"));
//使用标准的分词算法对原始记录表进行拆分
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
//LIMITED默认是1W个
IndexWriter.MaxFieldLength maxFieldLength = IndexWriter.MaxFieldLength.LIMITED;
/**
* IndexWriter将我们的document对象写到硬盘中
*
* 参数一:Directory d,写到硬盘中的目录路径是什么
* 参数二:Analyzer a, 以何种算法来对document中的原始记录表数据进行拆分成词汇表
* 参数三:MaxFieldLength mfl 最多将文本拆分出多少个词汇
*
* */
IndexWriter indexWriter = new IndexWriter(directory, analyzer, maxFieldLength);
//将Document对象通过IndexWriter对象写入索引库中
indexWriter.addDocument(document);
//关闭IndexWriter对象
indexWriter.close();
}
После выполнения программы мы увидим нашу индексную библиотеку на жестком диске.
тогда мыСейчас неизвестно, хранятся ли записи в библиотеке индексов на самом деле, потому что мы ее не видим. Данные, хранящиеся в библиотеке индексов, помещаются в файл cfs, и мы не можем открыть файл cfs..
Итак, теперь мы используем ключевое слово для чтения данных индексной библиотеки. Посмотрите, успешно ли прочитаны данные.
Запросить содержимое в индексной библиотеке по ключевому слову:
- 1)Создайте объект IndexSearcher
- 2)Создайте объект QueryParser
- 3)Создайте объект запроса для инкапсуляции ключевых слов
- 4)Используйте объект IndexSearcher для запроса первых 100 записей, соответствующих условиям в библиотеке индексов. Если записей меньше 100, фактическая запись имеет преимущественную силу.
- 5)Получите подходящее удостоверение личности
- 6)Используйте объект IndexSearcher, чтобы запросить объект документа, соответствующий номеру в библиотеке индекса
- 7)Извлеките все свойства из объекта Document, инкапсулируйте их обратно в объект JavaBean и добавьте в коллекцию, чтобы сохранить для последующего использования.
@Test
public void findIndexDB() throws Exception {
/**
* 参数一: IndexSearcher(Directory path)查询以xxx目录的索引库
*
* */
Directory directory = FSDirectory.open(new File("E:/createIndexDB"));
//创建IndexSearcher对象
IndexSearcher indexSearcher = new IndexSearcher(directory);
//创建QueryParser对象
/**
* 参数一: Version matchVersion 版本号【和上面是一样的】
* 参数二:String f,【要查询的字段】
* 参数三:Analyzer a【使用的拆词算法】
* */
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
QueryParser queryParser = new QueryParser(Version.LUCENE_30, "userName", analyzer);
//给出要查询的关键字
String keyWords = "钟";
//创建Query对象来封装关键字
Query query = queryParser.parse(keyWords);
//用IndexSearcher对象去索引库中查询符合条件的前100条记录,不足100条记录的以实际为准
TopDocs topDocs = indexSearcher.search(query, 100);
//获取符合条件的编号
for (int i = 0; i < topDocs.scoreDocs.length; i++) {
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int no = scoreDoc.doc;
//用indexSearcher对象去索引库中查询编号对应的Document对象
Document document = indexSearcher.doc(no);
//将Document对象中的所有属性取出,再封装回JavaBean对象中去
String id = document.get("id");
String userName = document.get("userName");
String sal = document.get("sal");
User user = new User(id, userName, sal);
System.out.println(user);
}
Эффект:
1.3 Дальнейшее объяснение кода Lucene
Наша программа Lucene имеет примерно ту же идею:Объект JavaBean инкапсулируется в объект Document, а затем документ записывается в библиотеку индексов с помощью IndexWriter. Когда пользователям необходимо выполнить запрос, они используют IndexSearcher для чтения данных из библиотеки индексов, поиска соответствующего объекта Document, анализа содержимого внутри и затем инкапсулируют его в объект JavaBean для использования нами..
2. Оптимизируйте код Lucene
Давайте вернемся к коду, который мы написали в предыдущем кратком обзоре, и я возьму несколько репрезентативных:
Следующий код появляется при заполнении данных в библиотеке индексов и запросе данных из библиотеки индексов.дублирующийся код!
Directory directory = FSDirectory.open(new File("E:/createIndexDB"));
//使用标准的分词算法对原始记录表进行拆分
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
Следующий код на самом делеЧтобы инкапсулировать данные JavaBean в объект Document, мы можем инкапсулировать их посредством отражения..... Если мы не инкапсулируем, если у нас есть много JavaBeans, которые нужно добавить в объект Document, будет много похожего кода.
document.add(new Field("id", user.getId(), Field.Store.YES, Field.Index.ANALYZED));
document.add(new Field("userName", user.getUserName(), Field.Store.YES, Field.Index.ANALYZED));
document.add(new Field("sal", user.getSal(), Field.Store.YES, Field.Index.ANALYZED));
Следующий код извлекает данные из объекта Document и инкапсулирует их в JavaBean. Если в JavaBean много свойств, нам также нужно много раз писать аналогичный код....
//将Document对象中的所有属性取出,再封装回JavaBean对象中去
String id = document.get("id");
String userName = document.get("userName");
String sal = document.get("sal");
User user = new User(id, userName, sal);
2.1 Написать класс инструментов Lucene
При написании служебных классов стоит отметить:
- Когда мы получаем свойства объекта, мы можем инкапсулировать метод получения свойств
- Получите метод get, вы можете вызвать его, чтобы получить соответствующее значение
- При манипулировании свойствами объекта мы хотим использовать доступ методом грубой силы
- Если есть три переменных свойства, значения и объекта, мы не забываем использовать компонент BeanUtils.
import org.apache.commons.beanutils.BeanUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* Created by ozc on 2017/7/12.
*/
/**
* 使用单例事例模式
* */
public class LuceneUtils {
private static Directory directory;
private static Analyzer analyzer;
private static IndexWriter.MaxFieldLength maxFieldLength;
private LuceneUtils() {}
static{
try {
directory = FSDirectory.open(new File("E:/createIndexDB"));
analyzer = new StandardAnalyzer(Version.LUCENE_30);
maxFieldLength = IndexWriter.MaxFieldLength.LIMITED;
} catch (Exception e) {
e.printStackTrace();
}
}
public static Directory getDirectory() {
return directory;
}
public static Analyzer getAnalyzer() {
return analyzer;
}
public static IndexWriter.MaxFieldLength getMaxFieldLength() {
return maxFieldLength;
}
/**
* @param object 传入的JavaBean类型
* @return 返回Document对象
*/
public static Document javaBean2Document(Object object) {
try {
Document document = new Document();
//得到JavaBean的字节码文件对象
Class<?> aClass = object.getClass();
//通过字节码文件对象得到对应的属性【全部的属性,不能仅仅调用getFields()】
Field[] fields = aClass.getDeclaredFields();
//得到每个属性的名字
for (Field field : fields) {
String name = field.getName();
//得到属性的值【也就是调用getter方法获取对应的值】
String method = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
//得到对应的值【就是得到具体的方法,然后调用就行了。因为是get方法,没有参数】
Method aClassMethod = aClass.getDeclaredMethod(method, null);
String value = aClassMethod.invoke(object).toString();
System.out.println(value);
//把数据封装到Document对象中。
document.add(new org.apache.lucene.document.Field(name, value, org.apache.lucene.document.Field.Store.YES, org.apache.lucene.document.Field.Index.ANALYZED));
}
return document;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @param aClass 要解析的对象类型,要用户传入进来
* @param document 将Document对象传入进来
* @return 返回一个JavaBean
*/
public static Object Document2JavaBean(Document document, Class aClass) {
try {
//创建该JavaBean对象
Object obj = aClass.newInstance();
//得到该JavaBean所有的成员变量
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
//设置允许暴力访问
field.setAccessible(true);
String name = field.getName();
String value = document.get(name);
//使用BeanUtils把数据封装到Bean中
BeanUtils.setProperty(obj, name, value);
}
return obj;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Test
public void test() {
User user = new User();
LuceneUtils.javaBean2Document(user);
}
}
2.2 Использование LuceneUtils для преобразования программы
@Test
public void createIndexDB() throws Exception {
//把数据填充到JavaBean对象中
User user = new User("2", "钟福成2", "未来的程序员2");
Document document = LuceneUtils.javaBean2Document(user);
/**
* IndexWriter将我们的document对象写到硬盘中
*
* 参数一:Directory d,写到硬盘中的目录路径是什么
* 参数二:Analyzer a, 以何种算法来对document中的原始记录表数据进行拆分成词汇表
* 参数三:MaxFieldLength mfl 最多将文本拆分出多少个词汇
*
* */
IndexWriter indexWriter = new IndexWriter(LuceneUtils.getDirectory(), LuceneUtils.getAnalyzer(), LuceneUtils.getMaxFieldLength());
//将Document对象通过IndexWriter对象写入索引库中
indexWriter.addDocument(document);
//关闭IndexWriter对象
indexWriter.close();
}
@Test
public void findIndexDB() throws Exception {
//创建IndexSearcher对象
IndexSearcher indexSearcher = new IndexSearcher(LuceneUtils.getDirectory());
//创建QueryParser对象
QueryParser queryParser = new QueryParser(Version.LUCENE_30, "userName", LuceneUtils.getAnalyzer());
//给出要查询的关键字
String keyWords = "钟";
//创建Query对象来封装关键字
Query query = queryParser.parse(keyWords);
//用IndexSearcher对象去索引库中查询符合条件的前100条记录,不足100条记录的以实际为准
TopDocs topDocs = indexSearcher.search(query, 100);
//获取符合条件的编号
for (int i = 0; i < topDocs.scoreDocs.length; i++) {
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int no = scoreDoc.doc;
//用indexSearcher对象去索引库中查询编号对应的Document对象
Document document = indexSearcher.doc(no);
//将Document对象中的所有属性取出,再封装回JavaBean对象中去
User user = (User) LuceneUtils.Document2JavaBean(document, User.class);
System.out.println(user);
}
}
3. Оптимизация библиотеки индексов
Мы уже можем создать библиотеку индексов и прочитать данные объекта из библиотеки индексов. На самом деле, есть еще места, где индексную библиотеку можно оптимизировать...
3.1 Объединение файлов
Когда мы добавляем данные в библиотеку индексов,Каждый раз, когда вы добавляете его, он автоматически создает для нас файл cfs....
Это на самом деле не хорошо, потому что если количество данных велико, наш жесткий диск будет иметь много файлов CFS ..... на самом делеБиблиотека индексов поможет нам автоматически объединить файлы, по умолчанию 10.
Если мы хотим изменить значение по умолчанию, мы можем изменить его с помощью следующего кода:
//索引库优化
indexWriter.optimize();
//设置合并因子为3,每当有3个cfs文件,就合并
indexWriter.setMergeFactor(3);
3.2 Настройка библиотеки индексов памяти
Наша текущая программа работает непосредственно с файлами, поэтому накладные расходы на ввод-вывод на самом деле относительно велики. И это относительно медленно... мы можем использовать индексную библиотеку в памяти, чтобы повысить эффективность чтения и записи...
Для библиотеки индексирования в памяти это быстро, потому что мы работаем непосредственно с памятью... Но что,Мы хотим сохранить индексную библиотеку памяти в индексной библиотеке жесткого диска. Когда мы читаем данные, мы должны сначала синхронизировать данные индексной библиотеки жесткого диска с индексной библиотекой памяти.
Article article = new Article(1,"培训","传智是一家Java培训机构");
Document document = LuceneUtil.javabean2document(article);
Directory fsDirectory = FSDirectory.open(new File("E:/indexDBDBDBDBDBDBDBDB"));
Directory ramDirectory = new RAMDirectory(fsDirectory);
IndexWriter fsIndexWriter = new IndexWriter(fsDirectory,LuceneUtil.getAnalyzer(),true,LuceneUtil.getMaxFieldLength());
IndexWriter ramIndexWriter = new IndexWriter(ramDirectory,LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
ramIndexWriter.addDocument(document);
ramIndexWriter.close();
fsIndexWriter.addIndexesNoOptimize(ramDirectory);
fsIndexWriter.close();
4. Токенизатор
Мы уже говорили, что при хранении данных в библиотеке индексов мы будем использовать определенные алгоритмы для хранения данных исходной таблицы записей в словаре... тогдаСумму этих алгоритмов мы можем назвать токенизатором.
Токенизатор: ** Алгоритм используется для разделения символов в текстах на китайском и английском языках для формирования словарного запаса, который можно искать после того, как пользователи введут ключевые слова**
Что касается того, почему мы должны использовать токенизатор, мы также ясно сказали: поскольку пользователи не могут полностью записывать наши исходные данные записи, при поиске они запрашивают исходную таблицу записей с помощью ключевых слов.. .. в этот момент мы используемтокенизатор для наилучшего сопоставления соответствующих данных
4.1 Процесс токенизации
-
步一:按分词器拆分出词汇
-
步二:去除停用词和禁用词
-
步三:如果有英文,把英文字母转为小写,即搜索不分大小写
4.2 API токенизатора
Когда мы выбираем алгоритм сегментации, мы обнаружим, что очень, очень много API Tokenizer, мы можем использовать следующий код, чтобы увидеть, еслиКак токенизатор разделяет данные:
private static void testAnalyzer(Analyzer analyzer, String text) throws Exception {
System.out.println("当前使用的分词器:" + analyzer.getClass());
TokenStream tokenStream = analyzer.tokenStream("content",new StringReader(text));
tokenStream.addAttribute(TermAttribute.class);
while (tokenStream.incrementToken()) {
TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);
System.out.println(termAttribute.term());
}
}
После эксперимента мы можем выбрать подходящий алгоритм сегментации слов...
4.3 Токенизатор IKAnalyzer
Это сторонний токенизатор, если мы хотим его использовать, нам нужно импортировать соответствующий jar-пакет.
- IKAnalyzer3.2.0Stable.jar
- Шаг 2: Скопируйте файлы IKAnalyzer.cfg.xml, stopword.dic и xxx.dic в каталог src MyEclipse, а затем настройте его.При настройке первая строка должна быть пустой.
Чем хорош этот сторонний токенизатор? ? ? ? онКитайский предпочтительный токенизатор...то есть: он разделен по китайским словам!
5. Обработайте результаты поиска
5.1 Выделите результаты поиска
Когда мы используем SQL, искомые данные не выделяются... и мы используемЛуче, мы можем установить ключевое слово, чтобы выделить поисковый контент... Это будет уделять больше внимания пользовательскому опыту!
String keywords = "钟福成";
List<Article> articleList = new ArrayList<Article>();
QueryParser queryParser = new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
Query query = queryParser.parse(keywords);
IndexSearcher indexSearcher = new IndexSearcher(LuceneUtil.getDirectory());
TopDocs topDocs = indexSearcher.search(query,1000000);
//设置关键字高亮
Formatter formatter = new SimpleHTMLFormatter("<font color='red'>","</font>");
Scorer scorer = new QueryScorer(query);
Highlighter highlighter = new Highlighter(formatter,scorer);
for(int i=0;i<topDocs.scoreDocs.length;i++){
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int no = scoreDoc.doc;
Document document = indexSearcher.doc(no);
//设置内容高亮
String highlighterContent = highlighter.getBestFragment(LuceneUtil.getAnalyzer(),"content",document.get("content"));
document.getField("content").setValue(highlighterContent);
Article article = (Article) LuceneUtil.document2javabean(document,Article.class);
articleList.add(article);
}
for(Article article : articleList){
System.out.println(article);
}
}
5.2 Сводка результатов поиска
Если содержимое нашего поиска слишком велико, и мы хотим показать только часть содержимого, мы можем обобщить его...
Стоит отметить: сводки результатов поиска необходимо использовать с настройкой выделения.
String keywords = "钟福成";
List<Article> articleList = new ArrayList<Article>();
QueryParser queryParser = new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
Query query = queryParser.parse(keywords);
IndexSearcher indexSearcher = new IndexSearcher(LuceneUtil.getDirectory());
TopDocs topDocs = indexSearcher.search(query,1000000);
Formatter formatter = new SimpleHTMLFormatter("<font color='red'>","</font>");
Scorer scorer = new QueryScorer(query);
Highlighter highlighter = new Highlighter(formatter,scorer);
//设置摘要
Fragmenter fragmenter = new SimpleFragmenter(4);
highlighter.setTextFragmenter(fragmenter);
for(int i=0;i<topDocs.scoreDocs.length;i++){
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int no = scoreDoc.doc;
Document document = indexSearcher.doc(no);
String highlighterContent = highlighter.getBestFragment(LuceneUtil.getAnalyzer(),"content",document.get("content"));
document.getField("content").setValue(highlighterContent);
Article article = (Article) LuceneUtil.document2javabean(document,Article.class);
articleList.add(article);
}
for(Article article : articleList){
System.out.println(article);
}
}
5.3 Сортировка результатов поиска
Мы, конечно, используем множество поисковых систем, используя разные поисковые системы для поиска одного и того же контента. Их домашняя страница также будет ранжироваться по-другому... вот почему они используют внутреннюю сортировку результатов поиска....
Есть много видов ранжирования, которые влияют на веб-страницы:
-
head/meta/【keywords关键字】
-
网页的标签整洁
-
网页执行速度
-
采用div+css
-
等等等等
В Lucene мы можем установить показатель релевантности для ранжирования различных результатов:
IndexWriter indexWriter = new IndexWriter(LuceneUtil.getDirectory(),LuceneUtil.getAnalyzer(),LuceneUtil.getMaxFieldLength());
//为结果设置得分
document.setBoost(20F);
indexWriter.addDocument(document);
indexWriter.close();
Конечно, мы также можем сортировать по одному полю:
//true表示降序
Sort sort = new Sort(new SortField("id",SortField.INT,true));
TopDocs topDocs = indexSearcher.search(query,null,1000000,sort);
Также возможна сортировка по нескольким полям: при сортировке по нескольким полямТолько когда результаты сортировки по первому полю совпадают, сортировка по второму полю имеет эффект.Рекомендуется числовая сортировка.
Sort sort = new Sort(new SortField("count",SortField.INT,true),new SortField("id",SortField.INT,true));
TopDocs topDocs = indexSearcher.search(query,null,1000000,sort);
5.4 Условный поиск
В нашем примере мы используем ключевое слово для поиска содержимого поля. Синтаксис аналогичен следующему:
QueryParser queryParser = new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalyzer());
На самом деле, мы также можем использовать ключевые слова для поиска по нескольким полям, то есть поиск по нескольким условиям.Что мы часто используем на практике, так это поиск с несколькими условиями, который может использовать нас для сопоставления соответствующих данных в максимально возможной степени.!
QueryParser queryParser = new MultiFieldQueryParser(LuceneUtil.getVersion(),new String[]{"content","title"},LuceneUtil.getAnalyzer());
6. Резюме
- Lucene — предок механизма полнотекстового индексирования., последние Solr и Elasticsearch основаны на Lucene (позже будет статья об Elasticsearch, так что следите за обновлениями~)
- Lucene хранит сериюБинарный архив и некоторые управляющие файлы, которые в совокупности называютсяБиблиотека индексов, библиотека индексов разделена на две части:
- оригинальная запись
- Глоссарий
- Узнайте, как оптимизировать библиотеку индексов: 1. Объединить файлы. 2. Настроить библиотеку индексов в памяти.
- В Lucene есть много видов токенизаторов, выберите тот, который подходит вам для сегментации слов.
- Результаты запроса можно выделить, обобщить и отсортировать.
Это верхушка айсберга для Lucene,Как правило, сейчас можно использовать Solr и Elasticsearch., но если вы хотите узнать больше о Lucene, вы можете прочитать другую информацию~
Если в статье есть какие-либо ошибки, пожалуйста, поправьте меня, и мы сможем общаться друг с другом. Учащиеся, привыкшие читать технические статьи в WeChat и желающие получить больше ресурсов по Java, могутОбратите внимание на публичный аккаунт WeChat: Java3y