索引是Solr搜索功能的核心,理解索引原理和优化策略对构建高性能搜索应用至关重要。
索引基本概念
什么是索引?
**索引(Indexing)**是将内容添加到Solr索引中使其可搜索的过程:
- 数据转换:将原始文档转换为可搜索的数据结构
- 倒排索引:创建从词条到文档的映射关系
- 优化存储:以高效的方式存储和组织数据
索引的核心组件
1 2 3 4 5 6 7 8 9 10 11 12
| Solr索引结构 ├── 文档(Documents) │ ├── 字段1(Field1) │ ├── 字段2(Field2) │ └── ... ├── 倒排索引(Inverted Index) │ ├── 词条→文档ID列表 │ ├── 词频统计 │ └── 位置信息 └── 存储结构(Stored Fields) ├── 原始字段值 └── 压缩数据
|
文档和字段结构
文档组成
Solr索引由文档(Documents)组成,每个文档包含多个字段(Fields):
1 2 3 4 5 6 7 8
| { "id": "doc_001", "title": "Apache Solr教程", "content": "Solr是强大的搜索引擎...", "author": "技术专家", "category": ["技术", "教程"], "publish_date": "2024-07-25T10:00:00Z" }
|
字段处理流程
1. 字段分析
1 2 3 4 5 6 7
| 原始文本: "Apache Solr是开源搜索平台" ↓ 分词器处理 分词结果: ["Apache", "Solr", "是", "开源", "搜索", "平台"] ↓ 过滤器处理 标准化: ["apache", "solr", "开源", "搜索", "平台"] ↓ 索引构建 倒排索引: apache→[doc1], solr→[doc1], 开源→[doc1] ...
|
2. 字段类型处理
不同字段类型的处理方式:
1 2 3 4 5 6 7 8 9 10 11
| <field name="id" type="string" indexed="true" stored="true"/>
<field name="content" type="text_general" indexed="true" stored="true"/>
<field name="price" type="pfloat" indexed="true" stored="true"/>
<field name="date" type="pdate" indexed="true" stored="true"/>
|
索引方法
1. Solr Cell和Apache Tika
处理二进制和结构化文件:
1 2 3 4 5 6 7
| curl "http://localhost:8983/solr/documents/update/extract?literal.id=pdf1&commit=true" \ -F "myfile=@document.pdf"
curl "http://localhost:8983/solr/documents/update/extract?literal.id=doc1&commit=true" \ -F "myfile=@presentation.pptx"
|
支持的文件格式:
- 办公文档:Word、Excel、PowerPoint
- PDF文档:各种版本的PDF文件
- 图像文件:提取元数据信息
- 邮件格式:MSG、EML等格式
2. XML/JSON文件上传
通过HTTP请求发送结构化数据:
JSON格式索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| curl -X POST -H 'Content-Type: application/json' \ 'http://localhost:8983/solr/mycollection/update?commit=true' -d ' [ { "id": "1", "title": "Solr入门教程", "content": "这是一篇关于Solr的入门教程", "category": "技术" }, { "id": "2", "title": "Elasticsearch对比", "content": "Solr与Elasticsearch的详细对比分析", "category": "分析" } ]'
|
XML格式索引
1 2 3 4 5 6 7 8 9 10
| curl -X POST -H 'Content-Type: text/xml' \ 'http://localhost:8983/solr/mycollection/update?commit=true' -d ' <add> <doc> <field name="id">3</field> <field name="title">高级搜索技巧</field> <field name="content">深入介绍Solr的高级搜索功能</field> <field name="category">进阶</field> </doc> </add>'
|
3. Java客户端API
最适合Java应用集成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.common.SolrInputDocument;
SolrClient client = new HttpSolrClient.Builder("http://localhost:8983/solr/mycollection").build();
SolrInputDocument doc = new SolrInputDocument(); doc.addField("id", "java_doc_1"); doc.addField("title", "Java客户端示例"); doc.addField("content", "使用SolrJ进行文档索引"); doc.addField("category", "开发");
client.add(doc); client.commit();
Collection<SolrInputDocument> docs = new ArrayList<>(); for (int i = 0; i < 1000; i++) { SolrInputDocument batchDoc = new SolrInputDocument(); batchDoc.addField("id", "batch_" + i); batchDoc.addField("title", "批量文档 " + i); docs.add(batchDoc); } client.add(docs); client.commit();
|
索引优化策略
1. 批量索引优化
批次大小优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| int batchSize = 1000; Collection<SolrInputDocument> batch = new ArrayList<>(batchSize);
for (Document doc : documents) { batch.add(createSolrDoc(doc)); if (batch.size() >= batchSize) { client.add(batch); batch.clear(); if (processedCount % (batchSize * 10) == 0) { client.commit(); } } }
if (!batch.isEmpty()) { client.add(batch); } client.commit();
|
提交策略优化
1 2 3 4 5 6 7 8 9 10
| <autoCommit> <maxTime>15000</maxTime> <maxDocs>1000</maxDocs> <openSearcher>false</openSearcher> </autoCommit>
<autoSoftCommit> <maxTime>1000</maxTime> </autoSoftCommit>
|
2. 内存和资源优化
JVM设置
1 2 3 4 5 6
| SOLR_JAVA_MEM="-Xms4g -Xmx4g" SOLR_OPTS="$SOLR_OPTS -XX:+UseG1GC" SOLR_OPTS="$SOLR_OPTS -XX:+PerfDisableSharedMem" SOLR_OPTS="$SOLR_OPTS -XX:+ParallelRefProcEnabled" SOLR_OPTS="$SOLR_OPTS -XX:MaxGCPauseMillis=250"
|
缓存配置
1 2 3 4 5 6 7
| <query> <filterCache size="512" initialSize="512" autowarmCount="128"/> <queryResultCache size="512" initialSize="512" autowarmCount="32"/> <documentCache size="512" initialSize="512" autowarmCount="0"/> <fieldValueCache size="512" initialSize="128" autowarmCount="128"/> </query>
|
3. 字段级别优化
选择性索引
1 2 3 4 5 6 7
| <field name="searchable_title" type="text_general" indexed="true" stored="false"/> <field name="searchable_content" type="text_general" indexed="true" stored="false"/>
<field name="display_title" type="string" indexed="false" stored="true"/> <field name="display_summary" type="string" indexed="false" stored="true"/>
|
复制字段优化
1 2 3 4 5 6 7 8
| <field name="text" type="text_general" indexed="true" stored="false" multiValued="true"/>
<copyField source="title" dest="text"/> <copyField source="content" dest="text"/> <copyField source="author" dest="text"/> <copyField source="tags" dest="text"/>
|
索引维护
1. 索引更新
文档更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| curl -X POST -H 'Content-Type: application/json' \ 'http://localhost:8983/solr/mycollection/update?commit=true' -d ' [ { "id": "doc1", "title": "更新后的标题", "content": "更新后的内容" } ]'
curl -X POST -H 'Content-Type: application/json' \ 'http://localhost:8983/solr/mycollection/update?commit=true' -d ' [ { "id": "doc1", "price": {"set": 99.99}, "tags": {"add": "新标签"} } ]'
|
文档删除
1 2 3 4 5 6 7 8 9 10 11 12 13
| curl -X POST -H 'Content-Type: application/json' \ 'http://localhost:8983/solr/mycollection/update?commit=true' -d ' { "delete": {"id": "doc1"} }'
curl -X POST -H 'Content-Type: application/json' \ 'http://localhost:8983/solr/mycollection/update?commit=true' -d ' { "delete": {"query": "category:obsolete"} }'
|
2. 索引优化
段合并优化
1 2 3 4 5
| curl "http://localhost:8983/solr/mycollection/update?optimize=true&maxSegments=1"
curl "http://localhost:8983/solr/mycollection/update?commit=true&expungeDeletes=true"
|
索引统计监控
1 2 3 4 5
| curl "http://localhost:8983/solr/admin/luke?numTerms=0"
curl "http://localhost:8983/solr/admin/cores?action=STATUS"
|
索引工具和实用程序
1. Post工具
Solr内置的索引工具:
1 2 3 4 5 6 7 8 9 10 11
| bin/solr post -c mycollection /path/to/documents/
bin/solr post -c mycollection -filetypes pdf,doc,docx /path/to/docs/
bin/solr post -c mycollection -recursive /path/to/docs/
bin/solr post -c mycollection -url http://example.com/data.json
|
2. 数据导入处理器(DIH)
配置文件驱动的数据导入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <dataConfig> <dataSource driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/db" user="dbuser" password="dbpwd"/> <document> <entity name="product" query="SELECT id, name, description, price FROM products"> <field column="id" name="id"/> <field column="name" name="title"/> <field column="description" name="content"/> <field column="price" name="price"/> </entity> </document> </dataConfig>
|
执行数据导入:
1 2 3 4 5 6 7 8
| curl "http://localhost:8983/solr/mycollection/dataimport?command=full-import"
curl "http://localhost:8983/solr/mycollection/dataimport?command=delta-import"
curl "http://localhost:8983/solr/mycollection/dataimport?command=status"
|
性能监控
1. 索引性能指标
关键指标监控:
1 2 3 4 5 6 7 8
| curl "http://localhost:8983/solr/admin/cores?action=STATUS" | jq '.status.mycollection.index'
curl "http://localhost:8983/solr/mycollection/admin/segments"
curl "http://localhost:8983/solr/admin/metrics?group=core&prefix=UPDATE"
|
2. 性能调优技巧
索引时间优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| client.setRequestWriter(new BinaryRequestWriter());
ExecutorService executor = Executors.newFixedThreadPool(4); for (List<SolrInputDocument> batch : batches) { executor.submit(() -> { try { client.add(batch); } catch (Exception e) { log.error("索引失败", e); } }); }
|
内存使用优化
1 2 3 4 5
| <field name="large_content" type="text_general" indexed="true" stored="false"/>
<field name="compressed_content" type="text_general" indexed="true" stored="true" compressed="true"/>
|
故障排除
1. 常见索引问题
内存不足
1 2 3
|
SOLR_JAVA_MEM="-Xms8g -Xmx8g"
|
索引锁定
1 2 3
|
find /var/solr/data/mycollection -name "write.lock" -delete
|
提交失败
1 2 3
|
curl "http://localhost:8983/solr/mycollection/update?commit=true&waitSearcher=false"
|
2. 调试工具
索引分析
1 2 3 4 5
| curl "http://localhost:8983/solr/mycollection/analysis/field?analysis.fieldname=content&analysis.fieldvalue=测试文本"
curl "http://localhost:8983/solr/admin/luke?core=mycollection&show=schema"
|
总结
Solr索引的关键要点:
- 理解原理:掌握文档、字段和倒排索引的概念
- 选择方法:根据数据类型选择合适的索引方法
- 优化性能:通过批处理、缓存和资源配置提升性能
- 维护管理:定期监控和维护索引状态
通过深入理解这些概念,您将能够构建高效、可靠的Solr索引系统。
下一步学习