Lucene总结(二):使用Lucene创建索引总结

上一篇讲到了Lucene的检索原理以及简单介绍如何创建索引。

这一篇从Lucene的添加、删除、更新、文档域加权来对构建索引进行总结。

准备所需jar包和数据

新建了一个maven工程,pom.xml如下:

<dependencies>
        <!-- lucene核心包 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>5.3.1</version>
        </dependency>
        <!-- lucene查询解析包 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queryparser</artifactId>
            <version>5.3.1</version>
        </dependency>
        <!-- lucene解析器包 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>5.3.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

在工程中新建一个junit测试类IndexTest1.java,在类中准备一下用来测试的数据,如下:

//用来测试的数据
private String ids[] = {"1", "2", "3"}; 
private String dates[] = {"yesterday", "today", "tomorrow"};
private String descs[] = {
    "It was a rainy day yesterday",
    "It's cloudy today",
    "Tomorrow is sunny."};

可以将上面三个数组不同位置上对应的字符串看成一个文档,如对数组位置为0的,这个文档就是,id域为“1”,date域为”yesterday”,desc域就是”It was a rainy day yesterday”。因此就会有三个文档,下面对文档进行分析。

添加文档

添加文档其实就是创建索引,首先使用上一篇讲到的创建索引的方法,首先创建一个写索引,然后通过这个对象去添加文档,每个文档就是一个Lucene的Document,于是可以在继续在IndexTest1.java中添加:

public class IndexingTest1 {

    private Directory dir; //存放索引的位置

    //用来测试的数据
    private String ids[] = {"1", "2", "3"}; 
    private String dates[] = {"yesterday", "today", "tomorrow"};
    private String descs[] = {
        "It was a rainy day yesterday",
        "It's cloudy today",
        "Tomorrow is sunny."};


    //生成索引
    @Test
    public void index() throws Exception{
        IndexWriter writer = getWriter();
        for(int i = 0; i < ids.length; i++){
            Document document = new Document();
            document.add(new StringField("id", ids[i], Field.Store.YES));
            document.add(new StringField("date", dates[i], Field.Store.YES));
            document.add(new TextField("desc", descs[i], Field.Store.YES));
            writer.addDocument(document);
        }
        writer.close(); //close了才真正写到文档中
    }

    //获取IndexWriter实例
    public IndexWriter getWriter() throws Exception{
        dir = FSDirectory.open(Paths.get("D:\\resource"));
        Analyzer analyzer = new StandardAnalyzer();//标准分词器,会自动去掉空格啊,is a the等单词
        IndexWriterConfig  config = new IndexWriterConfig(analyzer);//将标准分词器配到写索引的配置中
        IndexWriter writer = new IndexWriter(dir,config);//实例化写索引对象
        return writer;
    }
}

从上面的代码可以看出,每个数组元素都是一个filed域。文档添加好了域之后,就添加到写索引的实例writer中写入。也就是先创建一个文件,再在文件中添加信息,在使用写索引写入索引库中。
如图,就有了这样的索引文件的产生:
这里写图片描述

读取文档

读取文档的话需要IndexReader对象,初始化的时候要传入读取文档所在的路径,也就是之前的D:\resource。

public void testIndexReader() throws Exception {
    dir = FSDirectory.open(Paths.get("D:\\resource"));
    IndexReader reader = DirectoryReader.open(dir);
    System.out.println("最大文档数:" + reader.maxDoc());
    System.out.println("实际文档数:" + reader.numDocs());
    reader.close();
}

删除文档

删除文档有两种方式。一种是在合并前删除,另一种是在合并后删除

  1. 合并前删除指的是并没有真正删除这个文档,只是在这个文档上做一个标记而已;
  2. 合并后删除指的是真正删掉了这个文档了。

使用场景
如果一个项目比较大,并发访问的人数比较多,删除肯定会对性能有影响,这个时候就可以用合并前删除,先不删,只是标记一下这个文档属于已删除的文档,等到访问量比较小的时候,再统一删除。同样的,如果数据量不大,删除操作也不怎么影响性能,那么直接删除,也就是合并后删除。

同样的在之前那个例子上添加如下代码:

//合并前删除
    @Test
    public void testDeleteBefore() throws Exception{
        IndexWriter writer = getWriter();
        System.out.println("删除前有" + writer.numDocs() + "个文档");
        writer.deleteDocuments(new Term("id", "1")); //删除id=1对应的文档
        writer.commit(); //提交删除,并没有真正删除
        System.out.println("删除后最大文档数:" + writer.maxDoc());
        System.out.println("删除后实际文档数:" + writer.numDocs());
        writer.close();
    }

    //合并后删除
    @Test
    public void testDeleteAfter() throws Exception {
        IndexWriter writer = getWriter();
        System.out.println("删除前有" + writer.numDocs() + "个文档");
        writer.deleteDocuments(new Term("id", "1")); //删除id=1对应的文档
        writer.forceMergeDeletes(); //强制合并(强制删除),没有索引了
        writer.commit(); //提交删除,真的删除了
        System.out.println("删除后最大文档数:" + writer.maxDoc());
        System.out.println("删除后实际文档数:" + writer.numDocs());
        writer.close();
    }

测试结果如下:
合并前删除测试:
这里写图片描述
合并后删除测试:
这里写图片描述
在这里,测试的时候要注意,完成合并前删除测试之后,将路径上的所有索引都删除,重新调用上面的index方法重新生成一下,再去测试合并后删除,因为之前删掉一个了,会影响后面的测试。

更新文档

更新文档,就是新建一个Document对象,然后按照前面设置的字段自己再设置个新的,然后更新原来的文档。
在上面的例子上添加:

//更新文档测试
    @Test
    public void updateTest() throws Exception{
        IndexWriter writer = getWriter();
        Document document = new Document();
        document.add(new StringField("id", ids[1], Field.Store.YES));
        document.add(new StringField("date", "today update", Field.Store.YES));
        document.add(new TextField("desc", "Today is a good day", Field.Store.NO));
        writer.updateDocument(new Term("id", ids[1]),document);
        writer.close();
        System.out.println(document.getField("desc"));
    }

结果如下:
这里写图片描述

文档域加权

这个其实有点可以理解,比如你想在一个博客上查一个单词,很多篇文档都会有这个单词,但是你希望标题含有这个单词的优先排在前面,或者希望某位作者写的文档放在前面一点,那么你就可以使用加权。

这里的代码我用了网上的一个例子,因为不想想文档具体的内容。就是有四个人写了四篇有关Java的文章,希望匹配将作者c写的放在最前面。因此新建了一个IndexTest2类。

//准备数据,五个人各写了一篇文章,希望先出来C的文章,因此给C加权
    private String ids[] = {"1", "2", "3", "4"};
    private String authors[] = {"A", "B", "C", "D"};
    private String positions[] = {"a", "b", "c", "d"};
    private String titles[] = {"Java is a good language.", "Java is a cross platform language", "Java powerful", "You should learn java"};
    private String contents[] = {
            "If possible, use the same JRE major version at both index and search time.",
            "When upgrading to a different JRE major version, consider re-indexing. ",
            "Different JRE major versions may implement different versions of Unicode.",
            "For example: with Java 1.4, `LetterTokenizer` will split around the character U+02C6."
    };

同样的生成索引,区别在于进行了加权操作。
public class IndexTest2 {

private Directory directory;

//准备数据,五个人各写了一篇文章,希望先出来C的文章,因此给C加权
private String ids[] = {"1", "2", "3", "4"};
private String authors[] = {"A", "B", "C", "D"};
private String positions[] = {"a", "b", "c", "d"};
private String titles[] = {"Java is a good language.", "Java is a cross platform language", "Java powerful", "You should learn java"};
private String contents[] = {
        "If possible, use the same JRE major version at both index and search time.",
        "When upgrading to a different JRE major version, consider re-indexing. ",
        "Different JRE major versions may implement different versions of Unicode.",
        "For example: with Java 1.4, `LetterTokenizer` will split around the character U+02C6."
};

@Test
public void index() throws Exception {
    IndexWriter indexWriter = getWriter();
    for (int i = 0; i < ids.length; i++) {
        Document document = new Document();
        document.add(new StringField("id", ids[i], Field.Store.YES));
        document.add(new StringField("author", authors[i], Field.Store.YES));
        document.add(new StringField("position", positions[i], Field.Store.YES));

        //这部分就是加权操作了,对title这个Field进行加权,因为等会要查这个Field
        TextField field = new TextField("title", titles[i], Field.Store.YES);
        //先判断这个人是不是c,如果是就加权
        if ("c".equals(positions[i])) {
            field.setBoost(1.5f); //加权操作,默认为1,1.5表示加权了,小于1就降权了
        }

        document.add(field);
        document.add(new TextField("content", contents[i], Field.Store.NO));
        indexWriter.addDocument(document); //添加文档
    }
    indexWriter.close();
}
//获取IndexWriter实例
public IndexWriter getWriter() throws Exception{
    directory = FSDirectory.open(Paths.get("D:\\masterSpring\\code\\chapter18\\src\\resource"));
    Analyzer analyzer = new StandardAnalyzer();
    IndexWriterConfig config = new IndexWriterConfig(analyzer);
    IndexWriter writer = new IndexWriter(directory,config);
    return writer;
}
//测试加权的等下写。
}

上面就是创建索引的过程。

`if ("c".equals(positions[i])) {
    field.setBoost(1.5f); 
}

这句话就是给作者是C的文档加权了,默认为1,大于1表示加权了,小于1就降权了
结果如下。
这里写图片描述
可以看见C排在了第一位,如果没有上面的那段加权代码,那么匹配出来的顺序是Lucene中自己的一个算法,可以认为是Lucene默认的顺序,具体是怎样的就不探讨了,我们可以自己根据需求自己设定一下权重。


希望对你有帮助,如有疑问或见解,欢迎提出,共同进步。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
GeoPandas是一个开源的Python库,旨在简化地理空间数据的处理和分析。它结合了Pandas和Shapely的能力,为Python用户提供了一个强大而灵活的工具来处理地理空间数据。以下是关于GeoPandas的详细介绍: 一、GeoPandas的基本概念 1. 定义 GeoPandas是建立在Pandas和Shapely之上的一个Python库,用于处理和分析地理空间数据。 它扩展了Pandas的DataFrame和Series数据结构,允许在其中存储和操作地理空间几何图形。 2. 核心数据结构 GeoDataFrame:GeoPandas的核心数据结构,是Pandas DataFrame的扩展。它包含一个或多个列,其中至少一列是几何列(geometry column),用于存储地理空间几何图形(如点、线、多边形等)。 GeoSeries:GeoPandas中的另一个重要数据结构,类似于Pandas的Series,但用于存储几何图形序列。 、GeoPandas的功能特性 1. 读取和写入多种地理空间数据格式 GeoPandas支持读取和写入多种常见的地理空间数据格式,包括Shapefile、GeoJSON、PostGIS、KML等。这使得用户可以轻松地从各种数据源中加载地理空间数据,并将处理后的数据保存为所需的格式。 2. 地理空间几何图形的创建、编辑和分析 GeoPandas允许用户创建、编辑和分析地理空间几何图形,包括点、线、多边形等。它提供了丰富的空间操作函数,如缓冲区分析、交集、并集、差集等,使得用户可以方便地进行地理空间数据分析。 3. 数据可视化 GeoPandas内置了数据可视化功能,可以绘制地理空间数据的地图。用户可以使用matplotlib等库来进一步定制地图的样式和布局。 4. 空间连接和空间索引 GeoPandas支持空间连接操作,可以将两个GeoDataFrame按照空间关系(如相交、包含等)进行连接。此外,它还支持空间索引,可以提高地理空间数据查询的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值