barriers / 阅读 / 详情

Elasticsearch性能优化

2023-08-24 09:22:19
共1条回复
可乐
* 回复内容中包含的链接未经审核,可能存在风险,暂不予完整展示!

注:文本整理自《ELKstack权威指南》

在 CRUD 章节,我们已经知道 ES 的数据写入是如何操作的了。喜欢自己动手的读者可能已经迫不及待的自己写了程序开始往 ES 里写数据做测试。这时候大家会发现:程序的运行速度非常一般,即使 ES 服务运行在本机,一秒钟大概也就能写入几百条数据。

这种速度显然不是 ES 的极限。事实上,每条数据经过一次完整的 HTTP POST 请求和 ES indexing 是一种极大的性能浪费,为此,ES 设计了批量提交方式。在数据读取方面,叫 mget 接口,在数据变更方面,叫 bulk 接口。mget 一般常用于搜索时 ES 节点之间批量获取中间结果集,对于 Elastic Stack 用户,更常见到的是 bulk 接口。

bulk 接口采用一种比较简朴的数据积累格式,示例如下:

格式是,每条 JSON 数据的上面,加一行描述性的元 JSON,指明下一行数据的操作类型,归属索引信息等。

采用这种格式,而不是一般的 JSON 数组格式,是因为接收到 bulk 请求的 ES 节点,就可以不需要做完整的 JSON 数组解析处理,直接按行处理简短的元 JSON,就可以确定下一行数据 JSON 转发给哪个数据节点了。这样,一个固定内存大小的 network buffer 空间,就可以反复使用,又节省了大量 JVM 的 GC。

事实上,产品级的 logstash、rsyslog、spark 都是默认采用 bulk 接口进行数据写入的。对于打算自己写程序的读者,建议采用 Perl 的 Search::Elasticsearch::Bulk 或者 Python 的 elasticsearch.helpers.* 库。

在配置 bulk 数据的时候,一般需要注意的就是请求体大小(bulk size)。

这里有一点细节上的矛盾,我们知道,HTTP 请求,是可以通过 HTTP 状态码 100 Continue 来持续发送数据的。但对于 ES 节点接收 HTTP 请求体的 Content-Length 来说,是按照整个大小来计算的。所以,首先,要确保 bulk 数据不要超过 http.max_content_length 设置。

那么,是不是尽量让 bulk size 接近这个数值呢?当然不是。

依然是请求体的问题,因为请求体需要全部加载到内存,而 JVM Heap 一共就那么多(按 31GB 算),过大的请求体,会挤占其他线程池的空间,反而导致写入性能的下降。

再考虑网卡流量,磁盘转速的问题,所以一般来说,建议 bulk 请求体的大小,在 15MB 左右,通过实际测试继续向上探索最合适的设置。

注意:这里说的 15MB 是请求体的字节数,而不是程序里里设置的 bulk size。bulk size 一般指数据的条目数。不要忘了,bulk 请求体中,每条数据还会额外带上一行元 JSON。

以 logstash 默认的 bulk_size => 5000 为例,假设单条数据平均大小 200B ,一次 bulk 请求体的大小就是 1.5MB。那么我们可以尝试 bulk_size => 50000 ;而如果单条数据平均大小是 20KB,一次 bulk 大小就是 100MB,显然超标了,需要尝试下调至 bulk_size => 500 。

gateway 是 ES 设计用来长期存储索引数据的接口。一般来说,大家都是用本地磁盘来存储索引数据,即 gateway.type 为 local 。

数据恢复中,有很多策略调整我们已经在之前分片控制小节讲过。除开分片级别的控制以外,gateway 级别也还有一些可优化的地方:

注意:gateway 中说的节点,仅包括主节点和数据节点,纯粹的 client 节点是不算在内的。如果你有更明确的选择,也可以按需求写:

虽然 ES 对 gateway 使用 NFS,iscsi 等共享存储的方式极力反对,但是对于较大量级的索引的副本数据,ES 从 1.5 版本开始,还是提供了一种节约成本又不特别影响性能的方式:影子副本(shadow replica)。

首先,需要在集群各节点的 elasticsearch.yml 中开启选项:

同时,确保各节点使用相同的路径挂载了共享存储,且目录权限为 Elasticsearch 进程用户可读可写。

然后,创建索引:

针对 shadow replicas ,ES 节点不会做实际的索引操作,而是单纯的每次 flush 时,把 segment 内容 fsync 到共享存储磁盘上。然后 refresh 让其他节点能够搜索该 segment 内容。

如果你已经决定把数据放到共享存储上了,采用 shadow replicas 还是有一些好处的:

但是请注意:主分片节点还是要承担一个副本的写入过程,并不像 Lucene 的 FileReplicator 那样通过复制文件完成,所以达不到完全节省 CPU 的效果。

shadow replicas 只是一个在某些特定环境下有用的方式。在资源允许的情况下,还是应该使用 local gateway。而另外采用 snapshot 接口来完成数据长期备份到 HDFS 或其他共享存储的需要。

我们都知道,ES 中的 master 跟一般 MySQL、Hadoop 的 master 是不一样的。它即不是写入流量的唯一入口,也不是所有数据的元信息的存放地点。所以,一般来说,ES 的 master 节点负载很轻,集群性能是可以近似认为随着 data 节点的扩展线性提升的。

但是,上面这句话并不是完全正确的。

ES 中有一件事情是只有 master 节点能管理的,这就是集群状态(cluster state)。

集群状态中包括以下信息:

这些信息在集群的任意节点上都存放着,你也可以通过 /_cluster/state 接口直接读取到其内容。注意这最后一项信息,之前我们已经讲过 ES 怎么通过简单地取余知道一条数据放在哪个分片里,加上现在集群状态里又记载了分片在哪个节点上,那么,整个集群里,任意节点都可以知道一条数据在哪个节点上存储了。所以,数据读写才可以发送给集群里任意节点。

至于修改,则只能由 master 节点完成!显然,集群状态里大部分内容是极少变动的,唯独有一样除外——索引的映射。因为 ES 的 schema-less 特性,我们可以任意写入 JSON 数据,所以索引中随时可能增加新的字段。这个时候,负责容纳这条数据的主分片所在的节点,会暂停写入操作,将字段的映射结果传递给 master 节点;master 节点合并这段修改到集群状态里,发送新版本的集群状态到集群的所有节点上。然后写入操作才会继续。一般来说,这个操作是在一二十毫秒内就可以完成,影响也不大。

但是也有一些情况会是例外。

在较大规模的 Elastic Stack 应用场景中,这是比较常见的一个情况。因为 Elastic Stack 建议采用日期时间作为索引的划分方式,所以定时(一般是每天),会统一产生一批新的索引。而前面已经讲过,ES 的集群状态每次更新都是阻塞式的发布到全部节点上以后,节点才能继续后续处理。

这就意味着,如果在集群负载较高的时候,批量新建新索引,可能会有一个显著的阻塞时间,无法写入任何数据。要等到全部节点同步完成集群状态以后,数据写入才能恢复。

不巧的是,中国使用的是北京时间,UTC +0800。也就是说,默认的 Elastic Stack 新建索引时间是在早上 8 点。这个时间点一般日志写入量已经上涨到一定水平了(当然,晚上 0 点的量其实也不低)。

对此,可以通过定时任务,每天在最低谷的早上三四点,提前通过 POST mapping 的方式,创建好之后几天的索引。就可以避免这个问题了。

如果你的日志是比较严重的非结构化数据,这个问题在 2.0 版本后会变得更加严重。 Elasticsearch 从 2.0 版本开始,对 mapping 更新做了重构。为了防止字段类型冲突和减少 master 定期下发全量 cluster state 导致的大流量压力,新的实现和旧实现的区别在:

也就是说,一旦你日志中字段数量较多,在新创建索引的一段时间内,可能长达几十分钟一直被反复锁死!

这是另一种常见的滥用。在使用 Elastic Stack 处理访问日志时,为了查询更方便,可能会采用 logstash-filter-kv 插件,将访问日志中的每个 URL 参数,都切分成单独的字段。比如一个 "/index.do?uid=1234567890&action=payload" 的 URL 会被转换成如下 JSON:

但是,因为集群状态是存在所有节点的内存里的,一旦 URL 参数过多,ES 节点的内存就被大量用于存储字段映射内容。这是一个极大的浪费。如果碰上 URL 参数的键内容本身一直在变动,直接撑爆 ES 内存都是有可能的!

以上是真实发生的事件,开发人员莫名的选择将一个 UUID 结果作为 key 放在 URL 参数里。直接导致 ES 集群 master 节点全部 OOM。

如果你在 ES 日志中一直看到有新的 updating mapping [logstash-2015.06.01] 字样出现的话,请郑重考虑一下自己是不是用的上如此细分的字段列表吧。

好,三秒钟过去,如果你确定一定以及肯定还要这么做,下面是一个变通的解决办法。

用 nested object 来存放 URL 参数的方法稍微复杂,但还可以接受。单从 JSON 数据层面看,新方式的数据结构如下:

没错,看起来就是一个数组。但是 JSON 数组在 ES 里是有两种处理方式的。

如果直接写入数组,ES 在实际索引过程中,会把所有内容都平铺开,变成 Arrays of Inner Objects 。整条数据实际类似这样的结构:

这种方式最大的问题是,当你采用 urlargs.key:"uid" AND urlargs.value:"0987654321" 语句意图搜索一个 uid=0987654321 的请求时,实际是整个 URL 参数中任意一处 value 为 0987654321 的,都会命中。

要想达到正确搜索的目的,需要在写入数据之前,指定 urlargs 字段的映射类型为 nested object。命令如下:

这样,数据实际是类似这样的结构:

当然,nested object 节省字段映射的优势对应的是它在使用的复杂。Query 和 Aggs 都必须使用专门的 nested query 和 nested aggs 才能正确读取到它。

nested query 语法如下:

nested aggs 语法如下:

ES 内针对不同阶段,设计有不同的缓存。以此提升数据检索时的响应性能。主要包括节点层面的 filter cache 和分片层面的 request cache。下面分别讲述。

ES 的 query DSL 在 2.0 版本之前分为 query 和 filter 两种,很多检索语法,是同时存在 query 和 filter 里的。比如最常用的 term、prefix、range 等。怎么选择是使用 query 还是 filter 成为很多用户头疼的难题。于是从 2.0 版本开始,ES 干脆合并了 filter 统一归为 query。但是具体的检索语法本身,依然有 query 和 filter 上下文的区别。ES 依靠这个上下文判断,来自动决定是否启用 filter cache。

query 跟 filter 上下文的区别,简单来说:

所以,选择也就出来了:

不过我们要怎么写,才能让 ES 正确判断呢?看下面这个请求:

在这个请求中,

需要注意的是,filter cache 是节点层面的缓存设置,每个节点上所有数据在响应请求时,是共用一个缓存空间的。当空间用满,按照 LRU 策略淘汰掉最冷的数据。

可以用 indices.cache.filter.size 配置来设置这个缓存空间的大小,默认是 JVM 堆的 10%,也可以设置一个绝对值。注意这是一个静态值,必须在 elasticsearch.yml 中提前配置。

ES 还有另一个分片层面的缓存,叫 shard request cache。5.0 之前的版本中,request cache 的用途并不大,因为 query cache 要起作用,还有几个先决条件:

以 Elastic Stack 场景来说,Kibana 里几乎所有的请求,都是有 @timestamp 作为过滤条件的,而且大多数是以 最近 N 小时/分钟 这样的选项,也就是说,页面每次刷新,发出的请求 JSON 里的时间过滤部分都是在变动的。query cache 在处理 Kibana 发出的请求时,完全无用。

而 5.0 版本的一大特性,叫 instant aggregation。解决了这个先决条件的一大阻碍。

在之前的版本,Elasticsearch 接收到请求之后,直接把请求原样转发给各分片,由各分片所在的节点自行完成请求的解析,进行实际的搜索操作。所以缓存的键是原始 JSON 串。

而 5.0 的重构后,接收到请求的节点先把请求的解析做完,发送到各节点的是统一拆分修改好的请求,这样就不再担心 JSON 串多个空格啥的了。

其次,上面说的『拆分修改』是怎么回事呢?

比如,我们在 Kibana 里搜索一个最近 7 天( @timestamp:["now-7d" TO "now"] )的数据,ES 就可以根据按天索引的判断,知道从 6 天前到昨天这 5 个索引是肯定全覆盖的。那么这个横跨 7 天的 date range query 就变成了 5 个 match_all query 加 2 个短时间的 date_range query。

现在你的仪表盘过 5 分钟自动刷新一次,再提交上来一次最近 7 天的请求,中间这 5 个 match_all 就完全一样了,直接从 request cache 返回即可,需要重新请求的,只有两头真正在变动的 date_range 了。

注1: match_all 不用遍历倒排索引,比直接查询 @timestamp:* 要快很多。

注2:判断覆盖修改为 match_all 并不是真的按照索引名称,而是 ES 从 2.x 开始提供的 field_stats 接口可以直接获取到 @timestamp 在本索引内的 max/min 值。当然从概念上如此理解也是可以接受的。

响应结果如下:

和 filter cache 一样,request cache 的大小也是以节点级别控制的,配置项名为 indices.requests.cache.size ,其默认值为 1% 。

字段数据(fielddata),在 Lucene 中又叫 uninverted index。我们都知道,搜索引擎会使用倒排索引(inverted index)来映射单词到文档的 ID 号。而同时,为了提供对文档内容的聚合,Lucene 还可以在运行时将每个字段的单词以字典序排成另一个 uninverted index,可以大大加速计算性能。

作为一个加速性能的方式,fielddata 当然是被全部加载在内存的时候最为有效。这也是 ES 默认的运行设置。但是,内存是有限的,所以 ES 同时也需要提供对 fielddata 内存的限额方式:

Elasticsearch 在 total,fielddata,request 三个层面上都设计有 circuit breaker 以保护进程不至于发生 OOM 事件。在 fielddata 层面,其设置为:

但是相比较集群庞大的数据量,内存本身是远远不够的。为了解决这个问题,ES 引入了另一个特性,可以对精确索引的字段,指定 fielddata 的存储方式。这个配置项叫: doc_values 。

所谓 doc_values ,其实就是在 ES 将数据写入索引的时候,提前生成好 fielddata 内容,并记录到磁盘上。因为 fielddata 数据是顺序读写的,所以即使在磁盘上,通过文件系统层的缓存,也可以获得相当不错的性能。

注意:因为 doc_values 是在数据写入时即生成内容,所以,它只能应用在精准索引的字段上,因为索引进程没法知道后续会有什么分词器生成的结果。

由于在 Elastic Stack 场景中, doc_values 的使用极其频繁,到 Elasticsearch 5.0 以后,这两者的区别被彻底强化成两个不同字段类型: text 和 keyword 。

等同于过去的:

等同于过去的:

也就是说,以后的用户,已经不太需要在意 fielddata 的问题了。不过依然有少数情况,你会需要对分词字段做聚合统计的话,你可以在自己接受范围内,开启这个特性:

你可以看到在上面加了一段 fielddata_frequency_filter 配置,这个配置是 segment 级别的。上面示例的意思是:只有这个 segment 里的文档数量超过 500 个,而且含有该字段的文档数量占该 segment 里的文档数量比例超过 10% 时,才加载这个 segment 的 fielddata。

下面是一个可能有用的对分词字段做聚合的示例:

这个示例可以对经过了 logstash-filter-punct 插件处理的数据,获取每种 punct 类型日志的关键词和对应的代表性日志原文。其效果类似 Splunk 的事件模式功能:

[图片上传失败...(image-b0b69f-1511752650964)]

如果经过之前章节的一系列优化之后,数据确实超过了集群能承载的能力,除了拆分集群以外,最后就只剩下一个办法了:清除废旧索引。

为了更加方便的做清除数据,合并 segment,备份恢复等管理任务,Elasticsearch 在提供相关 API 的同时,另外准备了一个命令行工具,叫 curator 。curator 是 Python 程序,可以直接通过 pypi 库安装:

注意,是 elasticsearch-curator 不是 curator。PyPi 原先就有另一个项目叫这个名字

和 Elastic Stack 里其他组件一样,curator 也是被 Elastic.co 收购的原开源社区周边。收编之后同样进行了一次重构,命令行参数从单字母风格改成了长单词风格。新版本的 curator 命令可用参数如下:

Options 包括:

--host TEXT Elasticsearch host.

--url_prefix TEXT Elasticsearch http url prefix.

--port INTEGER Elasticsearch port.

--use_ssl Connect to Elasticsearch through SSL.

--http_auth TEXT Use Basic Authentication ex: user:pass

--timeout INTEGER Connection timeout in seconds.

--master-only Only operate on elected master node.

--dry-run Do not perform any changes.

--debug Debug mode

--loglevel TEXT Log level

--logfile TEXT log file

--logformat TEXT Log output format [default|logstash].

--version Show the version and exit.

--help Show this message and exit.

Commands 包括:

alias Index Aliasing

allocation Index Allocation

bloom Disable bloom filter cache

close Close indices

delete Delete indices or snapshots

open Open indices

optimize Optimize Indices

replicas Replica Count Per-shard

show Show indices or snapshots

snapshot Take snapshots of indices (Backup)

针对具体的 Command,还可以继续使用 --help 查看该子命令的帮助。比如查看 close 子命令的帮助,输入 curator close --help ,结果如下:

在使用 1.4.0 以上版本的 Elasticsearch 前提下,curator 曾经主要的一个子命令 bloom 已经不再需要使用。所以,目前最常用的三个子命令,分别是 close , delete 和 optimize ,示例如下:

这一顿任务,结果是:

logstash-mweibo-nginx-yyyy.mm.dd 索引保存最近 5 天, logstash-mweibo-client-yyyy.mm.dd 保存最近 10 天, logstash-mweibo-yyyy.mm.dd 索引保存最近 30 天;且所有七天前的 logstash-* 索引都暂时关闭不用;最后对所有非当日日志做 segment 合并优化。

profiler 是 Elasticsearch 5.0 的一个新接口。通过这个功能,可以看到一个搜索聚合请求,是如何拆分成底层的 Lucene 请求,并且显示每部分的耗时情况。

启用 profiler 的方式很简单,直接在请求里加一行即可:

可以看到其中对 query 和 aggs 部分的返回是不太一样的。

query 部分包括 collectors、rewrite 和 query 部分。对复杂 query,profiler 会拆分 query 成多个基础的 TermQuery,然后每个 TermQuery 再显示各自的分阶段耗时如下:

我们可以很明显的看到聚合统计在初始化阶段、收集阶段、构建阶段、汇总阶段分别花了多少时间,遍历了多少数据。

注意其中 reduce 阶段还没实现完毕,所有都是 0。因为目前 profiler 只能在 shard 级别上做统计。

collect 阶段的耗时,有助于我们调整对应 aggs 的 collect_mode 参数选择。目前 Elasticsearch 支持 breadth_first 和 depth_first 两种方式。

initialise 阶段的耗时,有助于我们调整对应 aggs 的 execution_hint 参数选择。目前 Elasticsearch 支持 map 、 global_ordinals_low_cardinality 、 global_ordinals 和 global_ordinals_hash 四种选择。在计算离散度比较大的字段统计值时,适当调整该参数,有益于节省内存和提高计算速度。

对高离散度字段值统计性能很关注的读者,可以关注 https://g****.com/elastic/elasticsearch/pull/21626 这条记录的进展。

(本文完)

文本整理自《ELKstack权威指南》

相关推荐

Lucene该怎么读

卢僧
2023-08-17 05:17:337

Lucene 的存储结构概述

lucene的检索算法属于索引检索,即用空间来换取时间,对需要检索的文件、字符流进行全文索引,在检索的时候对索引进行快速的检索,得到检索位置,这个位置记录检索词出现的文件路径或者某个关键词。 lucene 在存储它的全文索引结构时,是有层次结构的,这涉及到5个层次:索引(Index);段(Segment);文档(Document);域(Field);词(Term),他们的关系如下图所示:(lucene 索引存储结构概念图) 下图是Lucene生成的索引的一个实例,右边是对这5个层次的描述: Lucene的索引结构是有层次结构的,主要分以下几个层次: Lucene的索引结构中,即保存了正向信息,也保存了反向信息。 所谓正向信息: 所谓反向信息: 段(Segment) 的控制策略 在建立索引的时候对性能影响最大的地方就是在将索引写入文件的时候, 所以在具体应用的时候就需要对此加以控制: Lucene默认情况是每加入10份文档(Document)就从内存往index文件写入并生成一个段(Segment) ,然后每10个段(Segment)就合并成一个段(Segment). 这些控制的变量如下: MaxMergeDocs用于控制一个segment文件中最多包含的Document数.比如限制为100的话,即使当前有10个segment也不会合并,因为合并后的segment将包含1000个文档,超过了限制。 MinMergeDocs用于确定一个当内存中文档达到多少的时候才写入文件,该项对segment的数量和大小不会有什么影响,它仅仅影响内存的使用,进一步影响写索引的效率。
2023-08-17 05:17:471

1,什么是Lucene,Lucene能干什么

1、什么是lucene Lucene是一个全文搜索框架,而不是应用产品。因此它并不像http://www.baidu.com/ 或者google Desktop那么拿来就能用,它只是提供了一种工具让你能实现这些产品。 2、lucene能做什么 要回答这个问题,先要了解lucene的本质。实际上lucene的功能很单一,说到底,就是你给它若干个字符串,然后它为你提供一个全文搜索服务,告诉你你要搜索的关键词出现在哪里。知道了这个本质,你就可以发挥想象做任何符合这个条件的事情了。你可以把站内新闻都索引了,做个资料库;你可以把一个数据库表的若干个字段索引起来,那就不用再担心因为“%like%”而锁表了;你也可以写个自己的搜索引擎……
2023-08-17 05:17:541

Lucene、Elasticsearch、Solr区别

Lucene: java写的单机搜索引擎Solr和Elasticsearch都是流行的搜索引擎,都是基于Java,但它们有一些区别。Solr是基于Lucene的搜索服务器,而Elasticsearch是一个分布式搜索和分析引擎。Solr更适合传统的企业搜索场景,而Elasticsearch更适合实时搜索和分析场景。Elasticsearch还具有更好的可扩展性和更好的文档处理能力。还有新的搜索引擎,基于c++开发的小唐代码搜索引擎,基于rust开发的github代码搜索引擎。
2023-08-17 05:18:022

lucene,solr有什么区别

Lucene是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎.Solr是一个高性能,采用Java5开发,基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能管理界面,是一款非常优秀的全文搜索引擎。它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Solr Get操作提出查找请求,并得到XML格式的返回结果;Solr和Lucene的本质区别有以下三点:搜索服务器,企业级和管理。Lucene本质上是搜索库,不是独立的应用程序,而Solr是。Lucene专注于搜索底层的建设,而Solr专注于企业应用。Lucene不负责支撑搜索服务所必须的管理,而Solr负责。所以说,一句话概括Solr: Solr是Lucene面向企业搜索应用的扩展
2023-08-17 05:18:101

请问Lucene开源工具具有何种用途?它是如何实现对相关文档实现排名打分的?

你的问题跟我要问的一字不差啊!
2023-08-17 05:18:192

Lucene可以对MYSQL进行全文检索吗

java的开源的免费全文检索工具Lucene Lucene不是一个完整的全文索引应用,而是是一个用Java写的全文索引引擎工具包,它可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能。 Lucene的作者:Lucene的贡献者Doug Cutting是一位资深全文索...
2023-08-17 05:18:292

lucene中对不同的域使用不同的分析器

  在lucene使用过程中 如果要对同一IndexWriter中不同Document 不同Field中使用不同的 *** yzer 我们该如何实现呢?   通过对《lucene in action》的阅读 发现是可以解决这一问题的 lucene可以正对整个IndexWriter对象或者每一个document对象或者特定Field使用不同的分析器   Analyzer *** yzer = new StandardAnalyzer();   IndexWriter writer = new IndexWriter(direcotry *** yzer true); //   Document doc = new Document();   doc add(new Field( title this is title Field Store PRESS Field Index TOKENIZED Field TermVector WITH_POSITIONS_OFFSETS));   doc add(new Field( content this is content Field Store PRESS Field Index TOKENIZED Field TermVector WITH_POSITIONS_OFFSETS));   writer addDocument(doc); //这是大部分情况下使用的一个方法   其实还有另外一个方法 原型如下   lucene自带文档写道   addDocument(Document doc Analyzer *** yzer) Adds a document to this index using the provided *** yzer instead of the value of getAnalyzer()   所以我们还可以写成这样   writer addDocument(doc *** yzer); // 这里的 *** yzer是指另外一个你指定的 *** yzer 不同于上面的StandardAnalyzer   那么如何针对特定Field使用不同分析器呢 lucene包里面有个PerFieldAnalyzerWrapper类 解决了这一问题 这是lucene的文档里面的一段话   lucene自带文档写道   Example usage:   PerFieldAnalyzerWrapper aWrapper = new PerFieldAnalyzerWrapper(new StandardAnalyzer());   aWrapper addAnalyzer( firstname new KeywordAnalyzer()); aWrapper addAnalyzer( lastname new KeywordAnalyzer());   In this example StandardAnalyzer will be used for all fields except firstname and lastname for which KeywordAnalyzer will be used   A PerFieldAnalyzerWrapper can be used like any other *** yzer for both indexing and query parsing PreFieldAnalyzerWrapper类的构造函数中需要一个默认的分析器作为参数 为了给不同的Field指定不同的 *** yzer 就需要调用该类的addAnalyzer()方法 上面的E文相信大家都能看懂的 就不需要我来翻译了 我的英语很差 着急啊 呵呵   也就是说大家以前初始化分析器的时候用这一句:   Analyzer *** yzer = new StandardAnalyzer();   现在可以改用   PerFieldAnalyzerWrapper *** yzer = new PerFieldAnalyzerWrapper(new StandardAnalyzer());   然后如果需要特定域的分析器就调用addAnalyzer方法    *** yzer addAnalyzer( fieldname new KeywordAnalyzer()); lishixinzhi/Article/program/Java/hx/201311/25894
2023-08-17 05:18:561

请问一下Lucene对文档内容建立索引后是否将文档存储?

Lucene搜索时都是搜索的索引库,并不搜索原文档。在索引时,Lucene首先将文档内容进行分词,然后做成倒排索引,搜索是搜索该倒排索引。建立索引时,可以针对每个字段(域)进行不同的索引设置,可设置是否分词?是否存储?以及使用到的分词器。此处设置的是否存储是指该字段(域)是否作为一个整体保留(不分词)。例如:文档一:”巴西世界杯很好看!“在索引时,如果是分词索引,则:巴西/世界杯/很/好看如果搜索世界杯,则文档一就会被搜索出来,在索引中保存的是巴西/世界杯/很/好看这样的分词。如果索引时除了分词之外还存储该字段(域),则:巴西/世界杯/很/好看/巴西世界杯很好看可以看出,索引中将文档一的所有内容作为一个分词,搜索时必须输入整个字段内容才会搜索到就想到这么多了,希望你能明白。
2023-08-17 05:19:051

海量数据环境下,Lucene 的索引性能如何优化?

很多人会抱怨 Lucene 在数据量增加到一定规模的时候,性能会出现明显下降,对于并发用户访问的支持能力也比较弱。其实在工程师所遇到的绝大多数环境下 Lucene 的性能问题,往往是因为系统没有经过良好的调优。而非简单的 Lucene 设计缺陷所造成。 当前使用 Lucene 的知名网站包括,Stack Exchange,旗下全球最大的事实性问答网站 StackOverFlow.com . 基于Lucene 文档 “How to make indexing faster”,我们可以看到如下经验可能可以应用于 Lucene 优化。 确定的确需要进行索引性能调优很多场景之下,性能问题其实表现为整体数据架构设计的问题,而不仅仅是通过索引所可以解决的。在决定进行索引性能调优之前,可能需要首先判断,是否数据架构上出现了情况。 确定在使用最新版本的LuceneLucene也是在不断发展之中。新版本的Lucene通常性能都会有些改善。 使用更快的硬件,例如,改善IO系统性能通常硬件性能的改善对于系统整体性能提升是立竿见影的。例如,通过SSD硬盘(Solid-State Disk,固态硬盘)取代通常的 SATA 或者 SAS 硬盘,将可以获得明显的系统性能提升。 在建立索引过程中,使用单例的 Writer基于内存执行 Flush 而不是基于 document count在Lucene 2.3 及其以上系统中,IndexWriter可以基于内存执行Flush操作。调用 writer.setRAMBufferSizeMB() 可以设置Buffer大小。 尽量多使用内存内存越多,Lucene应对海量数据的时候性能明显加强。 关闭复合文件格式(Compound file format)调用setUseCompoundFile(false),可以关闭。建立复合文件,将可能使得索引建立时间被拉长,有可能达到7%-33%。而关闭复合文件格式,将可能大大增加文件数量,而由于减少了文件合并操作,索引性能被明显增强。 重用文档与字段实例这是在 Lucene 2.3 之后才有的一个新技术。在之前如果要修改某个记录,需要删除掉索引中的文档,然后重新添加。而新的方法通过 setValue 实现。这将有助于更有效的减少GC开销而改善性能。 在存储字段数据以及执行 term vectors 的时候,使用同样的字段顺序添加文档这样将有助于保证合并操作的性能。 在打开 IndexWriter 的时候,设置 autoCommit = false同传统的数据库操作一样,批量提交事务性能总是比每个操作一个事务的性能能好很多。 同样,对于实时性要求不是很强的系统。通过标记,并定时进行索引和优化,也将比随时进行索引操作性能能改善很多。 不要使用太多的小字段,如果字段过多,尝试将字段合并到一个更大的字段中,以便于查询和索引适当增加 mergeFactor,但是不要增加的太多。关闭所有不需要的特性使用更快的 Analyzer特别是对于中文分词而言,分词器对于性能的影响更加明显。 加快文档的构造速度通常,从数据库,文件系统,或者网络爬行过程中,都可能因为上游程序处理的性能而影响 Lucene 文档建立的速度。 除非真的需要改善索引性能,通常不要特别进行优化对于一个实例的 IndexWriter 可以使用多线程或者并发技术使用Java Profiler分析 Lucene 和调用程序的性能,并由此改善性能Index into separate indices then merge.If you have a very large amount of content to index then you can break your content into N "silos", index each silo on a separate machine, then use the writer.addIndexesNoOptimize to merge them all into one final index.
2023-08-17 05:19:131

lucene中分词和索引的区别

ucene中分词和索引的区别如下:1、分词器,对文本资源进行切分,将字符文本串按照一定的规则切分为一个个可以进行索引的最小单位(关键词),以便检索时使用。2、索引文件结构索引库是一组索引文件的集合。索引文件的检索:索引表规模相对较小,文档集合规模较大。进行检索时,先从检索索引表开始,然后找到相对应的文档。如果查询中仅包含一个关键词,则在索引表中找到该关键词,并取出它所对应的文档就可以了。如果查询中包含多个关键词,则需要将各个关键字检索出的文档记录进行合并。索引文件的维护:维护索引常使用三个操作:插入、删除和更新文档。但是更新操作需要较高的代价,因为文档修改后(即使是很小的修改),也可以造成文档中的很多的关键词的位置发生了变化,这时需要频繁的读取和修改记录,这种代价是相当高的。因此,一般不进行更新操作,而是使用“先删除,后创建”的方式代替更新操作。代码如下:
2023-08-17 05:19:201

怎么用java的lucene对数据库进行检索

lucene是一个公用的全文索引组件,它的目标是把各种各样格式的数据转化成lucene特有的索引文件格式,这样才能通过lucene的高速检索机制进行全文检索。你的数据来源可以是关系数据库,可以是word、execl、txt文档,可以是html网页,对于这些数据源,你必须将它们内部的数据读取出来,并封装成lucene的document实例,之后让lucene帮你构建索引。举个例子:你的有一个用户数据库,里面存储了几十万的用户信息,你现在要对这个数据库进行全文索引,那么你要做的事情是:1.写一段传统的JDBC程序,讲每条的用户信息从数据库读取出来2.针对每条用户记录,建立一个lucene documentDocument doc = new Document();并根据你的需要,将用户信息的各个字段对应luncene document中的field 进行添加,如:doc.add(new Field("NAME","USERNAME", Field.Store.YES,Field.Index.UN_TOKENIZED));然后将该条doc加入到索引中, 如: luceneWriter.addDocument(doc);这样就建立了lucene的索引库3.编写对索引库的搜索程序(看lucene文档),通过对lucene的索引库的查找,你可以快速找到对应记录的ID4.通过ID到数据库中查找相关记录上面阐述了lucene的大体用法,不知道是不是说的很清楚。
2023-08-17 05:19:521

lucene按匹配度排序是怎么做到的

cene的搜索结果默认按相关度排序,这个相关度排序是基于内部的Score和DocID,Score又基于关键词的内部评分和做索引时的boost。默认Score高的排前面,如果Score一样,再按索引顺序,先索引的排前面。那么有人问了,如果我要先索引的排后面怎么办呢?隐士研究了源码后发现这是相当简单的事情。以下代码基于Lucene 2.0。看Sort的默认构造函数,相关度就是SortField.FIELD_SCORE和SortField.FIELD_DOC的组合。java 代码/**
2023-08-17 05:20:022

小型系统有必要用到lucene吗

没必要。如果数据在千万级以下,完全可以通过索引、建分区表等方式提升性能。使用lucene对性能提升不大,反而会使系统更加臃肿。当然,如果这个小型系统存储的全是文本文档,那就另当别论了。
2023-08-17 05:20:101

lucene 怎么和 动态参数排序

Lucene的默认排序是按照Document的得分进行排序的。当检索结果集中的两个Document的具有相同的得分时,默认按照Document的ID对结果进行排序。 下面研究几种设置/改变检索结果排序的方法。 1、改变Document的boost(激励因子) 改变boost的大小,会导致Document的得分的改变,从而按照Lucene默认的对检索结果集的排序方式,改变检索结果中Document的排序的提前或者靠后。在计算得分的时候,使用到了boost的值,默认boost的值为1.0,也就说默认情况下Document的得分与boost的无关的。一旦改变了默认的boost的值,也就从Document的得分与boost无关,变为相关了:boost值越大,Document的得分越高。 2、改变Field的boost(激励因子) 改变Field的boost值,和改变Document的boost值是一样的。因为Document的boost是通过添加到Docuemnt中Field体现的,所以改变Field的boost值,可以改变Document的boost值。 3、使用Sort排序工具实现排序 Lucene在查询的时候,可以通过以一个Sort作为参数构造一个检索器IndexSearcher,在构造Sort的时候,指定排序规则。 调用sort进行排序的方法是IndexSearcher.search,例如: IndexSearcher.search(query,sort); 关于Sort类,在其内部定义了6种构造方法: public Sort() // public Sort(SortField field) //通过构造某个域(field)的SortField对象根据一个域进行排序 public Sort(SortField[] fields) //通过构造一组域(field)的SortField对象组实现根据多个域排序 public Sort(String field) //根据某个域(field)的名称构造Sort进行排序 public Sort(String field, boolean reverse) //根据某个域(field)的名称构造SortField进行排序,reverse为true为升序 public Sort(String[] fields) //根据一组域(field)的名称构造一组Sort进行排序 4、直接使用SortField实现排序 关于SortField类,在其内部定义了7种构造方法: public SortField (String field, boolean reverse)//根据某个域(field)的名称构造SortField, reverse为false为升序 public SortField (String field, int type) public SortField (String field, int type, boolean reverse) public SortField (String field, Locale locale) public SortField (String field, Locale locale, boolean reverse) public SortField (String field, SortComparatorSource comparator) public SortField (String field, SortComparatorSource comparator, boolean reverse) type对应的值分别为: SortField. SCORE 按积分排序 SortField. DOC 按文档排序 SortField. AUTO 域的值为int、long、float都有效 SortField.STRING 域按STRING排序 SortField..FLOAT SortField.LONG SortField.DOUBLE SortField.SHORT SortField.CUSTOM 通过比较器排序 SortField.BYTE 5、自定义排序 Lucene中的自定义排序功能和Java集合中的自定义排序的实现方法差不多,都要实现一下比较接口. 在Java中只要实现Comparable接口就可以了.但是在Lucene中要实现SortComparatorSource接口和ScoreDocComparator接口.在了解具体实现方法之前先来看看这两个接口的定义吧
2023-08-17 05:20:171

lucene检索,必须完全包含我筛选的关键字,只包含其中一个字的要过滤掉,怎么设置 ?

这个要看你的搜索关键词是什么,采用的分词器是什么,比如你搜索的关键词是“搜索引擎”,如果采用的分词器的分词结果就包含“搜索引擎‘这个词,那么采用TermQuery就可以了;如果采用的分词器的分词结果不是“搜索引擎‘这个词,而是”搜索“和”引擎“这两个词,那么要采用PhraseQuery,setSlop(0),这样就可以搜索出同时包含”搜索“和”引擎“这两个词并且这两个词紧挨着的所有文章了。
2023-08-17 05:20:361

lucene 创建索引 document。add 报错

报什么异常,能贴出来么?
2023-08-17 05:20:443

lucene复合模糊查询如何实现?

String queryString = "site:1 AND channel:1 AND title:*lucene*";QueryParsernew parser = new QueryParser(参数自己写,默认字段传null);parser.setAllowleading...(true);具体怎么写自己查API吧Query query = parser(参数自己写).parse(queryString);searcher.search(query,100);根据自己的印象写的,手头没有api,剩下的你自己写吧。
2023-08-17 05:20:511

lucene创建了索引,是不是已经等于缓存了所有数据了?

看来楼主是刚接触lucene。lucene在磁盘上建立的索引,就是数据内容的本身,索引一旦建立,就和数据库没有任何关系了。按楼主的说法就是:已经包含了全部的内容。lucene的数据是不是缓存到本地,这个问题要看自己的设置。在建立索引的时候,有两种方式,一个是在内存中建立索引,一个是在本地磁盘建立索引。第一种方式,当电脑重启之后就会消失。第二种方式是在本地磁盘建立了文件,可以被长期保留。
2023-08-17 05:20:591

如何获取Lucene索引文件中的所有关键词

获取Lucene中的主要的索引文件关键字方法:1.索引块文件这个文件包含了索引中的索引块信息,这个文件包含了每个索引块的名字以及大小等信息。2.域信息文件我们知道,索引中的文档由一个或者多个域组成,这个文件包含了每个索引块中的域的信息。3.索引项信息文件这是索引文件里面最核心的一个文件,它存储了所有的索引项的值以及相关信息,并且以索引项来排序。4.频率文件5.位置文件这个文件包含了索引项在每个文档中出现的位置信息,可以利用这些信息来参与对索引结果的排序。
2023-08-17 05:21:092

lucene 查询部分字段总是返回 null

应该可以帮到你:Document doc = new Document(); Field FieldPath = new Field("path",file.getCanonicalPath(), Field.Store.YES, Field.Index.NO);Field FieldBody = new Field("contents", txtReader, Field.Store.YES, Field.Index.ANALYZED,Field.TermVector.WITH_POSITIONS_OFFSETS); doc.add(FieldPath); doc.add(FieldBody); writer.addDocument(doc);注:IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR),analyzer, true, IndexWriter.MaxFieldLength.LIMITED);
2023-08-17 05:21:172

Lucene 3.4 中文分词,

3.4 修改了Tokenizer 的接口,见incrementToken() 方法,原来是没有的。不兼容之前的,所以需要修改一下。
2023-08-17 05:21:253

lucene通过文件内容查询文件路径出现重复记录,怎么解决

建索引代码: private Document[] fileContentConvertDoc() { File f = new File(fileLuceneConfig.getDocFilePath()); List<File> allowFiles = new LinkedList<File>(); allowFiles = getAllowFiles(f, allowFiles); Document[] documents = new Document[allowFiles.size()]; int i = 0; for (File tmp : allowFiles) { this.baseExtractor = AbstractExtractorFactory.getBaseExtractor(tmp .getName()); documents[i] = new Document(); // 文件名,不分词的索引,但存储 documents[i].add(new Field("fileName", tmp.getName(), Field.Store.YES, Field.Index.NOT_ANALYZED)); // 文件绝对路径,不索引,但存储 documents[i].add(new Field("filePath", tmp.getAbsolutePath(), Field.Store.YES, Field.Index.NO)); // 文件内容,分词索引,但不存储,根据路径来加载 try { documents[i].add(new Field("fileContent", baseExtractor .getContent(new FileInputStream(tmp)), Field.Store.NO, Field.Index.ANALYZED)); } catch (FileNotFoundException e) { log.debug(new StringBuffer("文件名为:").append(tmp.getName()).append("的文件没有找到,无法对该文件内容建立索引!")); } i++; } return documents; } public void indexDocs() { FSDirectory fsDirectory = null; try { fsDirectory = FSDirectory.open(new File(luceneConfig.getIndexDirPath())); RAMDirectory ramDirectory = new RAMDirectory(); IndexWriter fsWriter = new IndexWriter(fsDirectory, AnalyzerFactory.getAnalyzer(luceneConfig), true, MaxFieldLength.UNLIMITED); IndexWriter ramWriter = new IndexWriter(ramDirectory, AnalyzerFactory.getAnalyzer(luceneConfig), true, MaxFieldLength.UNLIMITED); Document[] documents = this.luceneConfig.getAbstractDocument().getDocuments();这里实际就是调用上面那个方法将每个目标目录下每个文件构建成单独的Document int i = 0; for (Document d : documents) { ramWriter.addDocument(d); if (i % 10 == 0) { fsWriter.addIndexesNoOptimize(new Directory[]{ramDirectory}); ramWriter.close(); ramWriter = new IndexWriter(ramDirectory, AnalyzerFactory.getAnalyzer(luceneConfig), MaxFieldLength.UNLIMITED); } fsWriter.optimize(); fsWriter.commit(); } fsWriter.close(); ramWriter.close(); } catch (IOException e) { e.printStackTrace(); } 搜索代码:通过fileContent内容找出对应的filePath public String[] searchDoc(SearchModel searchModel, String returnField) { try { Analyzer analyzer = AnalyzerFactory.getAnalyzer(luceneConfig); QueryParser parser = new QueryParser(Version.LUCENE_30,searchModel.getSearchField(),analyzer); Query query = parser.parse(searchModel.getSearchContent()); IndexSearcher seacrcher = new IndexSearcher(FSDirectory.open(new File(luceneConfig.getIndexDirPath())),true); TopDocs ts = seacrcher.search(query,null,100); int totalHits = ts.totalHits; ScoreDoc[] scoreDocs = ts.scoreDocs; String[] values = new String[scoreDocs.length]; for (int i = 0; i < scoreDocs.length; i++) { //根据命中的文档的内部编号获取该文档 Document hitDoc = seacrcher.doc(scoreDocs[i].doc); //获取该文档指定域的值 values[i] = hitDoc.getField(returnField).stringValue(); System.out.println(values[i]); } return values; }catch (FileNotFoundException e) { if (-1 < e.getMessage().indexOf("no segments* file found")) { log.error(new StringBuffer(luceneConfig.getIndexDirPath()).append("目录没有索引文件!")); } } catch (ParseException e) { e.printStackTrace(); } catch (CorruptIndexException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } public static void main(String[] args) { FileLuceneConfig fileLuceneConfig = new FileLuceneConfig("E:\Lucene\test\target"); fileLuceneConfig.setIndexDirPath("E:\Lucene\test\index\file");//这是索引存放目录 fileLuceneConfig.setAnalyzerType("SC"); SearchModel searchModel = new SearchModel("人民","fileContent"); LuceneSearcher luceneSearcher = new LuceneSearcher(fileLuceneConfig); luceneSearcher.searchDoc(searchModel,"filePath"); } 查询结果,有重复记录: E:Lucene est argetc.txt E:Lucene est arget.txt E:Lucene est arget.txt 这里,我们先不管分词器如何分词,我希望出来的结果应该是: E:Lucene est argetc.txt E:Lucene est arget.txt 不会出现两条E:Lucene est arget.txt记录,请高手指定,为什么这里会有重复,如何做才能得到不重复的记录呢?
2023-08-17 05:21:331

lucene索引附件,怎么获取附件的内容。

个人认为,第一种方法相对靠谱一点。毕竟你的目的是可以检索到附件。优化建议:提取摘要。索引全部附件不太可取,这对硬件的压力也很大。可以选择新增一个域,用来保存附件的摘要。从那行代码来看,附件应该都是文档类吧。lucene的Highlighter貌似有这个功能,也可以考虑用其它方式实现。摘要+附件名,附件检索的目的完全可以达到了。增加相关域,根据对附件的检索需求,可以使用tika读取更多的相关信息,比如:附件名、附件大小、作者、时间、附件摘要,等相关信息。加上这些内容,一般的需求都能满足了。
2023-08-17 05:21:401

关于Lucene怎么使用SpanQuery进行模糊搜索

SpanQuery是按照词在文章中的距离或者查询几个相邻词的查询。打个比方:如“中华人民共和国” 用“中国“做为关键字, 跨度为某个值,如5。跨度代表 中 和国之间的长度。。lucene的:SpanQuery包括以下几种: SpanTermQuery:词距查询的基础,结果和TermQuery相似,只不过是增加了查询结果中单词的距离信息。 SpanFirstQuery:在指定距离可以找到第一个单词的查询。 SpanNearQuery:查询的几个语句之间保持者一定的距离。 SpanOrQuery:同时查询几个词句查询。 SpanNotQuery:从一个词距查询结果中,去除一个词距查询。所以这种Query不能进行模糊搜索,要进行模糊查询,可以选择FuzzyQuery或者WildcardQuery。
2023-08-17 05:21:481

lucene 查出来的content为空,title 不为空,该怎么显示啊

1、您的document里面有该字段;2、您在addField内容这个字段的时候,需要把设置Field.Store.YES。
2023-08-17 05:22:201

Lucene:怎样判断一个文件是否已经被创建了索引

你用Lucene建立索引的时候IndexWriter writer = new IndexWriter(indexdir,new StandardAnalyzer(), true);第三个参数当为TRUE时是会删除同一个目录下的索引的,这是在初次创建索引时使用以后每次增量索引直接设置为FALSE即可,这样直接将后面新建立的索引添加到索引文件中,不会覆盖原来建立的索引。当删除索引时我们可以找到对应的索引ID,然后删除索引,将删除掉索引文件中的该条记录,同时在同目录下生成一个删除索引的记录问价,为-DEL文件,便于后面恢复删除的索引。以上解答希望你能理解,建个简单的索引试试就可以知道的
2023-08-17 05:22:291

lucene 不分词为什么搜不到东西

您去看看lucene的实现原理吧 没有分词无法建立索引库 自然搜不到
2023-08-17 05:22:383

在Lucene中删除索引,使用writer.optimize();//优化操作使删除生效,可是这一句老是有错,求大神指教。

IndexReader提供了两种方法:reader.DeleteDocument(int docNum)reader.DeleteDocuments(Term term)前者是根据文档的编号来删除该文档,docNum是该文档进入索引时Lucene的编号,是按照顺序编的;后者是删除满足某一个条件的多个文档。在执行了DeleteDocument或者DeleteDocuments方法后,系统会生成一个*.del的文件,该文件中记录了删除的文档,但并未从物理上删除这些文档。此时,这些文档是受保护的,当使用Document doc = reader.Document(i)来访问这些受保护的文档时,Lucene会报“Attempt to access a deleted document”异常。如果一次需要删除多个文档时,可以用两种方法来解决:1. 删除一个文档后,用IndexWriter的Optimize方法来优化索引,这样我们就可以继续删除另一个文档。2. 先扫描整个索引文件,记录下需要删除的文档在索引中的编号。
2023-08-17 05:22:471

lucene 怎么设置查询的关键字查询匹配度100%

这个要看你的搜索关键词是什么,采用的分词器是什么,比如你搜索的关键词是“搜索引擎”,如果采用的分词器的分词结果就包含“搜索引擎‘这个词,那么采用TermQuery就可以了;如果采用的分词器的分词结果不是“搜索引擎‘这个词,而是”搜索“和”引擎“这两个词,那么要采用PhraseQuery,setSlop(0),这样就可以搜索出同时包含”搜索“和”引擎“这两个词并且这两个词紧挨着的所有文章了。
2023-08-17 05:22:551

使用lucene建立索引时,出现write.lock,求高手修改,代码如下

我感觉应该是fileReader这个函数出错了,如果fileDir目录下有子目录,或者这个目录下有比较大的文件,获取内容就会失败,这样就不会执行ndexWriter.close();这句。程序中应该加一些异常判断和保护就可以了。
2023-08-17 05:23:031

lucene4.2 这样写怎么检索不出来内容

你如果用的是不可索引的Field,那么肯定查不出来,如果用StringField,你需要分词查,那也查不出来(StringField("a", "中华人民共和国", Field.Store.YES)你查询共和国是查不出来的)org.apache.lucene.document.StringField这个是可索引的,不分词的org.apache.lucene.document.TextField这个是可索引的,分词的
2023-08-17 05:23:111

Lucene需要索引的文本文件太大,怎么解决

就报错来看,还没有用到Lucene就出错了,意思是只到第一行就虚拟机内存溢出了,可以考虑把源文件进行切割,如把10M的文本切成5个1M的,建议你试一下给一个可以切分文件的程序,可把它作为预处理的一部分public static void splitToSmallFiles(File file, String outputpath) throws IOException {int filePointer = 0;int MAX_SIZE = 10240000;BufferedWriter writer = null;BufferedReader reader = new BufferedReader(new FileReader(file));StringBuffer buffer = new StringBuffer();String line = reader.readLine();while (line != null) {buffer.append(line).append("\r");if (buffer.toString().getBytes().length >= MAX_SIZE){writer = new BufferedWriter(new FileWriter(outputpath + "output" + filePointer + ".txt"));writer.write(buffer.toString());writer.close();filePointer++;buffer = new StringBuffer();}line = reader.readLine();}writer = new BufferedWriter(new FileWriter(outputpath + "output" + filePointer + ".txt"));writer.write(buffer.toString());writer.close();}
2023-08-17 05:23:191

lucene最大能支持多大数据量的查询,且速度很好

用solr或者es吧 升级版
2023-08-17 05:23:273

lucene这个单词怎么读

lu Sen
2023-08-17 05:23:464

lucene 得分一样怎么排序

Lucene的默认排序是按照Document的得分进行排序的。当检索结果集中的两个Document的具有相同的得分时,默认按照Document的ID对结果进行排序。下面研究几种设置/改变检索结果排序的方法。1、改变Document的boost(激励因子)改变boost的大小,会导致Document的得分的改变,从而按照Lucene默认的对检索结果集的排序方式,改变检索结果中Document的排序的提前或者靠后。在计算得分的时候,使用到了boost的值,默认boost的值为1.0,也就说默认情况下Document的得分与boost的无关的。一旦改变了默认的boost的值,也就从Document的得分与boost无关,变为相关了:boost值越大,Document的得分越高。2、改变Field的boost(激励因子)改变Field的boost值,和改变Document的boost值是一样的。因为Document的boost是通过添加到Docuemnt中Field体现的,所以改变Field的boost值,可以改变Document的boost值。3、使用Sort排序工具实现排序Lucene在查询的时候,可以通过以一个Sort作为参数构造一个检索器IndexSearcher,在构造Sort的时候,指定排序规则。调用sort进行排序的方法是IndexSearcher.search,例如:IndexSearcher.search(query,sort);关于Sort类,在其内部定义了6种构造方法:publicSort()//publicSort(SortFieldfield)//通过构造某个域(field)的SortField对象根据一个域进行排序publicSort(SortField[]fields)//通过构造一组域(field)的SortField对象组实现根据多个域排序publicSort(Stringfield)//根据某个域(field)的名称构造Sort进行排序publicSort(Stringfield,booleanreverse)//根据某个域(field)的名称构造SortField进行排序,reverse为true为升序publicSort(String[]fields)//根据一组域(field)的名称构造一组Sort进行排序4、直接使用SortField实现排序关于SortField类,在其内部定义了7种构造方法:publicSortField(Stringfield,booleanreverse)//根据某个域(field)的名称构造SortField,reverse为false为升序publicSortField(Stringfield,inttype)publicSortField(Stringfield,inttype,booleanreverse)publicSortField(Stringfield,Localelocale)publicSortField(Stringfield,Localelocale,booleanreverse)publicSortField(Stringfield,SortComparatorSourcecomparator)publicSortField(Stringfield,SortComparatorSourcecomparator,booleanreverse)type对应的值分别为:SortField.SCORE按积分排序SortField.DOC按文档排序SortField.AUTO域的值为int、long、float都有效SortField.STRING域按STRING排序SortField..FLOATSortField.LONGSortField.DOUBLESortField.SHORTSortField.CUSTOM通过比较器排序SortField.BYTE5、自定义排序Lucene中的自定义排序功能和Java集合中的自定义排序的实现方法差不多,都要实现一下比较接口.在Java中只要实现Comparable接口就可以了.但是在Lucene中要实现SortComparatorSource接口和ScoreDocComparator接口.在了解具体实现方法之前先来看看这两个接口的定义吧
2023-08-17 05:23:541

lucene搜索时同义词怎么处理

这个要看你的搜索关键词是什么,采用的分词器是什么,比如你搜索的关键词是“搜索引擎”,如果采用的分词器的分词结果就包含“搜索引擎‘这个词,那么采用TermQuery就可以了;如果采用的分词器的分词结果不是“搜索引擎‘这个词,而是”搜索“和”引擎“这两个词,那么要采用PhraseQuery,setSlop(0),这样就可以搜索出同时包含”搜索“和”引擎“这两个词并且这两个词紧挨着的所有文章了。
2023-08-17 05:24:011

如何搞定 lucene3.0 自定义排序

Lucene的默认排序是按照Document的得分进行排序的。当检索结果集中的两个Document的具有相同的得分时,默认按照Document的ID对结果进行排序。 下面研究几种设置/改变检索结果排序的方法。 1、改变Document的boost(激励因子) 改变boost的大小,会导致Document的得分的改变,从而按照Lucene默认的对检索结果集的排序方式,改变检索结果中Document的排序的提前或者靠后。在计算得分的时候,使用到了boost的值,默认boost的值为1.0,也就说默认情况下Document的得分与boost的无关的。一旦改变了默认的boost的值,也就从Document的得分与boost无关,变为相关了:boost值越大,Document的得分越高。 2、改变Field的boost(激励因子) 改变Field的boost值,和改变Document的boost值是一样的。因为Document的boost是通过添加到Docuemnt中Field体现的,所以改变Field的boost值,可以改变Document的boost值。 3、使用Sort排序工具实现排序 Lucene在查询的时候,可以通过以一个Sort作为参数构造一个检索器IndexSearcher,在构造Sort的时候,指定排序规则。 调用sort进行排序的方法是IndexSearcher.search,例如: IndexSearcher.search(query,sort); 关于Sort类,在其内部定义了6种构造方法: public Sort() // public Sort(SortField field) //通过构造某个域(field)的SortField对象根据一个域进行排序 public Sort(SortField[] fields) //通过构造一组域(field)的SortField对象组实现根据多个域排序 public Sort(String field) //根据某个域(field)的名称构造Sort进行排序 public Sort(String field, boolean reverse) //根据某个域(field)的名称构造SortField进行排序,reverse为true为升序 public Sort(String[] fields) //根据一组域(field)的名称构造一组Sort进行排序 4、直接使用SortField实现排序 关于SortField类,在其内部定义了7种构造方法: public SortField (String field, boolean reverse)//根据某个域(field)的名称构造SortField, reverse为false为升序 public SortField (String field, int type) public SortField (String field, int type, boolean reverse) public SortField (String field, Locale locale) public SortField (String field, Locale locale, boolean reverse) public SortField (String field, SortComparatorSource comparator) public SortField (String field, SortComparatorSource comparator, boolean reverse) type对应的值分别为: SortField. SCORE 按积分排序 SortField. DOC 按文档排序 SortField. AUTO 域的值为int、long、float都有效 SortField.STRING 域按STRING排序 SortField..FLOAT SortField.LONG SortField.DOUBLE SortField.SHORT SortField.CUSTOM 通过比较器排序 SortField.BYTE 5、自定义排序 Lucene中的自定义排序功能和Java集合中的自定义排序的实现方法差不多,都要实现一下比较接口. 在Java中只要实现Comparable接口就可以了.但是在Lucene中要实现SortComparatorSource接口和ScoreDocComparator接口.在了解具体实现方法之前先来看看这两个接口的定义吧
2023-08-17 05:24:081

Lucene可以对MYSQL进行全文检索吗

Lucene是可以的,它常见的用例就是在一个或者多个数据库表进行全文检索。虽然MySql有全文检索的功能,但是如果字段和数据量增加,MySql的性能会减低很快。
2023-08-17 05:24:161

lucene搜索问题

虽然这个问题过去很久了,但是给后来的人解释下----第三个 用表达式("content:Y*")来搜索是不是应该搜索出"Yello你好"而不是"hello你好"----那是因为 你给content设置了两个值啊,一个field1一个field2,分词名称都是content
2023-08-17 05:24:232

lucene构建索引是保存在本地 还是内存中

反正我项目是保存在本地,好像也可以保存在内存的
2023-08-17 05:24:422

Lucene doc 文件格式详解

本文及后面关于Lucene的文章所采用的lucene 版本为8.1.0. doc 文件主要用于保存term的倒排表信息,包括docId倒排链及term在docId的term freq信息等。倒排链是Lucene 进行全文检索的核心数据结构,请特别关注这个数据结构 请参考 Lucene tim文件格式详解 第三部分 文件头部分主要内容为标识此文件类型为 Lucene50PostingsWriterDoc , 源码部分在 Lucene50PostingsWriter 的123行,主要内容如下 开始本部分阅读时,请注意一个在第3部分得到的结果及含义, 现在开始分析该部分内容 下面为term的doc信息。 主要逻辑是: 对于term的doc freq = 1的term来说,doc文件不保存这个term的doc信息,而是在 tim 文件中保存,doc 文件只保存doc freq > 1的term。在范例中,只有nice的doc freq > 1, 故只保存nice的doc倒排链 关于其它term(term freq = 1)的编码方式,请参考 tim 文件相应的格式内容 footer区主要有以下内容
2023-08-17 05:24:491

如何使用lucene改造oracle数据库

Lucene一个常见的用例是在一个或者多个数据库表进行全文检索。 虽然MySql有全文检索的功能,但是如果字段和数据量增加,MySql的性能会减低很快。映射数据到Lucene用伪代码表示:String sql = “select id, firstname, lastname, phone, email fro...
2023-08-17 05:24:581

Lucene搜索的字典dic文件如何指定路径

IndexReader indexReader=IndexReader.open(FSDirectory.open(file))
2023-08-17 05:25:261

lucene高版本怎么查低版本的数据?比如用lucene6.5代去查原先lucene3.6代创建的索引信息。

首先,应该知道lucene检索的是索引文件,而索引文件则是依据于数据库创建而成的。那么问题来了,你想怎么去创建索引呢?一般来说,这个得看需求了,最主要是考虑对数据的实时性要求高不高、数据量大不大?额,就假设数据量比较大吧,毕竟数据量太小也没必要使用lucene。1、数据实时性要求不高。可定时增量更新索引,以天或几个小时为单位。2.数据实时性要求较高。可在数据入库时,立即进行索引更新操作。那么问题又来了数据量比较大的时候,更新一次索引是比较慢的。所以,还得继续考虑缓存策略问题,将新增数据保存在缓存中,选择合适的时间进行提交。
2023-08-17 05:25:341

lucene中如何检索两个字段值相等的数据

好像没有直接的方法,不过可以通过try catch的方法来判断,如: Boolean flag=false; try{ String contents=searcher.doc(docNum).get("content"); flag=true; } catch(Exception e){ flag=false; } 如果flag=ture说明content这个字段是存在的
2023-08-17 05:25:411

Lucene 内置的一元分词为什么不被使用,而是要使用中文分词

因为一元分词不适合进行中文检索。一元分词是按字拆分的,比如一句话“梦想很丰满”,使用一元分词拆分的结果是:“梦”,“想”,“很”,“丰”,“满”。如果查找“梦想”这个词,是找不到查询结果的。这并不符合我们的检索习惯,所以极少使用。
2023-08-17 05:25:491

lucene最大能支持多大数据量的查询,且速度很好

luncene?给你个测试结果,自己考虑测试一:250万记录,300M左右文本,生成索引380M左右,800线程下平均处理时间300ms。测试二:37000记录,索引数据库中的两个varchar字段,索引文件2.6M,800线程下平均处理时间1.5ms。
2023-08-17 05:25:561

使用lucene在索引不分词的情况下能不能用模糊查询,也就是想达到like的效果

可以的,模糊查询和分词没有直接关系的。如果不分词,那么一句话就是一个域,可以使用FuzzyQuery或QueryParser查询。在使用QueryParser的时候,如果第一个字符就想使用通配符,那么需要使用setAllowLeadingWildcard(true)来开启。最后,模糊查询效率较低,结合自己的需求使用吧。
2023-08-17 05:26:041

用lucene建立索引时,当第二次创建时,还在同一个目录下,那么之前的索引会被删除吗?

你用Lucene建立索引的时候IndexWriter writer = new IndexWriter(indexdir,new StandardAnalyzer(), true);第三个参数当为TRUE时是会删除同一个目录下的索引的,这是在初次创建索引时使用以后每次增量索引直接设置为FALSE即可,这样直接将后面新建立的索引添加到索引文件中,不会覆盖原来建立的索引。当删除索引时我们可以找到对应的索引ID,然后删除索引,将删除掉索引文件中的该条记录,同时在同目录下生成一个删除索引的记录问价,为-DEL文件,便于后面恢复删除的索引。以上解答希望你能理解,建个简单的索引试试就可以知道的
2023-08-17 05:26:123