索引
通过索引可以快速查找元素,例如:在代码库中,查找包含某个单词或某个方法的文件。插件开发者可以使用IDE已有的索引来构建和使用自己的索引。
有以下2种索引:
-
文件索引 :基于文件内容构建的索引。通过该索引可以直接搜索到符合指定条件的文件
-
Stud索引 :基于序列化Stub trees 构建。 Stub tree 是PSI tree 的子集,只包含PSI tree中外部可见的声明,以二进制格式存储。该索引可以搜索符合指定条件的PSI元素集。
提示
PSI tree: PSI树,例如在java类中,java类会被解构为一个一个的PsiElement(PSI元素),所有的PsiElement构建为一个PSI树,可以参考文档 PSI元素
提示
可以使用 Index Viewer
插件查看索引的内容和属性。
# Dumb mode
索引在后台进程中进行构建,在构建索引的过程中,DumbService
限制了 只能使用 文本编辑或版本控制等不需要使用索引的功能 ,如果调用了需要使用索引的功能,会抛出 IndexNotReadyException
异常。
通过DumbService 可以获取当前项目处于 dumb模式(该模式下不能访问索引)还是 smart模式(该模式下,索引构建完成,可以使用索引),也可以等待项目处于smart模式时再执行操作。
//判断项目处于什么模式下
// dumb模式(该模式下不能访问索引)
// smart模式(该模式下,索引构建完成,可以使用索引)
DumbService.getInstance(project).isDumb();
DumbService.isDumb(project);
//等待项目处于 smart模式 时,再执行业务操作
DumbService.getInstance(project).runWhenSmart(()->{//业务逻辑});
# Gists
有时候会碰到以下情况:
-
不需要使用文件索引,只需要计算文件内容的相关数据,并将数据缓存到硬盘上
-
不需要在索引构建期间执行计算(例如:它会拖慢索引的构建,或者只有一小部分文件曾经需要这些计算数据)
-
可以根据请求延迟重新计算数据,而不会造成明显的性能损失。
大部分情况下可以使用 文件索引 ,但是通过 gists的API 可以延迟计算,并缓存到硬盘上, 可以参考 VirtualFileGist
的文档。
示例:
-
VirtualFileGist :使用 ImageInfoIndex
-
计算图片的大小尺寸并显示到UI上。
-
PsiFileGist : 使用 JavaSimplePropertyGist
-
获取Java类的简单属性
# 提高索引性能
# 性能指标
在2020.2及以后的版本中,索引的性能指标以json格式存储在了沙盒中的logs文件夹中,从2021.1版本开始,以HTML格式存储了另外的一些指标,参考下图:
沙盒路径查看文档:插件开发项目配置
# 避免使用AST
如果可能,尽量使用词法分析器信息而不是解析树。 如果不可能,请使用不会占用大量内存的经量级AST(LighterAST) ,这样可以提升遍历速度。可以通过将传过来的 FileContent参数 转换为 PsiDependentFileContent 然后调用 getLighterAST() 来获取 LighterAST,使用 LighterASTNodeVisitor
来遍历自己需要用到的节点,
来实现轻量级 Stub 索引
If a custom language contains lazy-parseable elements that never or rarely contain any stubs, consider implementing StubBuilder.skipChildProcessingWhenBuildingStubs()
(preferably using Lexer/node text).
考虑使用 NanoXmlUtil
来索引 xml 文件
# 预创建Stubs
如果你使用的编程语言有大量的对所有用户都一样的组件库,你可以注册 PrebuiltStubsProvider
扩展 来预创建Stubs索引,避免每次安装都需要构建Stubs索引。
文件索引
文件索引基于Map/Reduce
的数据结构。每一个索引都有一个指定类型的key,一个指定类型的value.
示例:word索引中,key就是word自己。value是跟key关联的,包含了word的context的对象(code, string literal, 或 comment)
在索引中,如果获取索引中某key的value的 type 等于 Void ,则表示不存在跟key相关的数据。
当一个索引实现类对一个文件创建了索引,那么这个索引实现类会收到该文件的内容,并返回一个Map, Map包含了该文件的索引key,及跟key相关的value
访问索引的时候,传入key,就能获取到跟key相关的所有文件。
提示
某些情况,可以不使用索引,而使用 Gist
# 实现文件索引
是一个相对简单的索引示例,它存储了 GUI Designer
.form中使用的class的全限定命令
注册索引实现类,如下:
<!--在plugin.xml里注册索引实现类-->
<extensions defaultExtensionNs="com.intellij">
<fileBasedIndex implementation="com.intellij.util.indexing.FileBasedIndexExtension 的子类"></fileBasedIndex>
</extensions>
实现 com.intellij.util.indexing.FileBasedIndexExtension
分为以下几部分:
-
getIndexer() :返回 DataIndexer
-
,它负责根据文件内容构建索引。
-
getKeyDescriptor() :返回以二进制的格式存储key的 KeyDescriptor
,最常用的是 KeyDescriptor的子类 EnumeratorStringDescriptor
-
,它能提升存储效率。
-
getValueExternalizer() :返回以二进制格式存储value的 DataExternalizer
getInputFilter() :只过滤自己需要的文件。可以使用 DefaultFileTypeSpecificInputFilter
-
getName() :返回唯一的索引ID,推荐使用类的全限定命名,防止冲突,例如可以使用:com.example.myplugin.indexing.MyIndex
-
getVersion() :索引的版本。如果当前使用的索引版本和实现类的版本不一致,将会自动重新构建索引
如果获取到的value的type 等于 Void ,则表示不存在该文件。
通过继承 ScalarIndexExtension
可以实现简单的索引。如果索引的Value只有一个,可以继承 SingleEntryFileBasedIndexExtension
来实现
警告
为了保证相同的Value只存储一个,所有索引Value的实现类必须重写 equals() 和 hashCode() 方法。
通过 DataIndexer.map() 方法返回的数据必须只依赖用户输入的参数,不能依赖任何外部元素,否则,你的索引将不能实时更新
在开发的时候,debug索引时,可以把 intellij.idea.indices.debug/intellij.idea.indices.debug.extra.sanity 设置为true
# 访问文件索引
提示
注意:在项目处于 Dumb mode 时,不能访问索引
来访问文件索引,主要包括以下操作:
- getAllKeys() 和 processAllKeys() 方法可以获取到项目的文件所有的key。可以让 FileBasedIndexExtension.traceKeyHashToVirtualFileMapping() 方法返回 true ,来优化性能
提示
保证能返回最新项目中所有的key,也可能有最新项目中不包含的key(项目更新时,会更新索引,但不会删除老索引)。
-
getValues() :获取跟Key有关的所有值,但是不包含值所在的文件
-
getContainingFiles() :获取包括Key的所有文件
-
processValues() :可以遍历和访问跟Key有关的所有文件
警告
索引不支持嵌套访问,可能会引起死锁。应该先从索引A中获取到所有结果,然后再在索引B中使用索引A的结果。
# 标准索引
IntelliJ Platform 提供了常用的索引,如下:
# Word Index
通常使用 PsiSearchHelper
来访问
# File Name Index
可以快速的根据文件名称查找文件
# File Type Index
可以快速的根据文件类型查找文件
# 向原有的索引根中添加索引
,并在plugin.xml里注册,如下:
<extensions defaultExtensionNs="com.intellij">
<indexedRootsProvider implementation="com.intellij.util.indexing.IndexableSetContributor 实现类"></indexedRootsProvider>
</extensions>
原文链接:https://www.cnblogs.com/qwop/p/17384236.html
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:索引和PSI存根 (Indexing and PSI Stubs) - Python技术站