文档更新 #

一、更新概述 #

1.1 更新类型 #

Solr支持多种更新方式:

类型 说明
全量更新 覆盖整个文档
原子更新 更新部分字段
脚本更新 使用脚本更新
增量更新 数值增减操作

1.2 更新前提 #

  • 文档必须有唯一键(uniqueKey)
  • 字段必须存储(stored=true)
  • 部分更新需要启用DocValues

二、全量更新 #

2.1 覆盖更新 #

bash
# 原文档
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "book-001",
    "title": "Solr实战指南",
    "author": "张三",
    "price": 99.0
  }'

# 覆盖更新(会丢失author字段)
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "book-001",
    "title": "Solr实战指南(第二版)",
    "price": 128.0
  }'

2.2 优缺点 #

优点

  • 简单直接
  • 性能较好

缺点

  • 需要获取完整文档
  • 可能丢失字段
  • 并发更新有风险

三、原子更新 #

3.1 原子更新操作 #

操作 说明
set 设置字段值
add 添加值到多值字段
remove 从多值字段移除值
removeregex 正则移除值
inc 数值递增
setoradd 设置或添加

3.2 set操作 #

bash
# 设置字段值
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "book-001",
    "title": {"set": "Solr实战指南(第二版)"}
  }'

3.3 add操作 #

bash
# 添加标签
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "book-001",
    "tags": {"add": ["推荐", "畅销"]}
  }'

3.4 remove操作 #

bash
# 移除标签
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "book-001",
    "tags": {"remove": "推荐"}
  }'

3.5 inc操作 #

bash
# 数值递增
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "book-001",
    "views": {"inc": 1},
    "sales": {"inc": 10}
  }'

3.6 组合更新 #

bash
# 多个操作组合
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "book-001",
    "title": {"set": "Solr实战指南(第二版)"},
    "price": {"set": 128.0},
    "tags": {"add": "新版"},
    "views": {"inc": 1},
    "updated_at": {"set": "2026-03-27T10:00:00Z"}
  }'

3.7 批量原子更新 #

bash
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "id": "book-001",
      "views": {"inc": 1}
    },
    {
      "id": "book-002",
      "views": {"inc": 1}
    }
  ]'

四、原子更新要求 #

4.1 Schema配置 #

xml
<!-- 字段必须stored -->
<field name="title" type="text_general" indexed="true" stored="true"/>

<!-- 数值字段建议docValues -->
<field name="views" type="pint" indexed="true" stored="true" docValues="true"/>
<field name="price" type="pdouble" indexed="true" stored="true" docValues="true"/>

<!-- 多值字段 -->
<field name="tags" type="string" indexed="true" stored="true" multiValued="true"/>

4.2 solrconfig.xml配置 #

xml
<updateHandler class="solr.DirectUpdateHandler2">
  <updateLog>
    <str name="dir">${solr.ulog.dir:}</str>
  </updateLog>
</updateHandler>

五、脚本更新 #

5.1 基本语法 #

bash
curl -X POST "http://localhost:8983/solr/mycore/update" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "book-001",
    "script": {
      "source": "ctx._source.views += params.increment",
      "params": {
        "increment": 1
      }
    }
  }'

5.2 条件更新 #

bash
curl -X POST "http://localhost:8983/solr/mycore/update" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "book-001",
    "script": {
      "source": "if (ctx._source.price > params.threshold) { ctx._source.premium = true }",
      "params": {
        "threshold": 100
      }
    }
  }'

5.3 复杂脚本 #

bash
curl -X POST "http://localhost:8983/solr/mycore/update" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "book-001",
    "script": {
      "source": "ctx._source.tags.add(params.newTag); ctx._source.updated_at = params.now",
      "params": {
        "newTag": "热门",
        "now": "2026-03-27T10:00:00Z"
      }
    }
  }'

六、更新处理器 #

6.1 UpdateRequestProcessorChain #

xml
<updateRequestProcessorChain name="myChain">
  <processor class="solr.LogUpdateProcessorFactory"/>
  <processor class="solr.DistributedUpdateProcessorFactory"/>
  <processor class="solr.RunUpdateProcessorFactory"/>
</updateRequestProcessorChain>

6.2 自定义处理器 #

xml
<updateRequestProcessorChain name="customChain">
  <!-- 时间戳处理器 -->
  <processor class="solr.TimestampUpdateProcessorFactory">
    <str name="fieldName">updated_at</str>
  </processor>
  
  <!-- UUID处理器 -->
  <processor class="solr.UUIDUpdateProcessorFactory">
    <str name="fieldName">id</str>
  </processor>
  
  <processor class="solr.RunUpdateProcessorFactory"/>
</updateRequestProcessorChain>

6.3 使用处理器链 #

bash
curl -X POST "http://localhost:8983/solr/mycore/update?processor=customChain" \
  -H "Content-Type: application/json" \
  -d '{"title": "新文档"}'

七、乐观并发控制 #

7.1 使用_version_ #

bash
# 获取文档版本
curl "http://localhost:8983/solr/mycore/get?id=book-001"

# 响应包含_version_
{
  "doc": {
    "id": "book-001",
    "title": "Solr实战指南",
    "_version_": 1234567890
  }
}

# 使用版本更新
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "book-001",
    "title": "Solr实战指南(第二版)",
    "_version_": 1234567890
  }'

7.2 版本规则 #

_version_值 行为
> 0 必须匹配现有版本
= 0 必须不存在
< 0 忽略版本检查

7.3 冲突处理 #

bash
# 版本冲突响应
{
  "responseHeader": {
    "status": 409
  },
  "error": {
    "msg": "Document not found for update. id=book-001",
    "code": 409
  }
}

八、嵌套文档更新 #

8.1 嵌套文档结构 #

json
{
  "id": "product-001",
  "name": "iPhone 15",
  "price": 8999,
  "_childDocuments_": [
    {
      "id": "review-001",
      "content": "非常好用",
      "rating": 5
    },
    {
      "id": "review-002",
      "content": "性价比高",
      "rating": 4
    }
  ]
}

8.2 更新嵌套文档 #

bash
# 更新子文档
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "review-001",
    "content": {"set": "非常好用,推荐购买"},
    "rating": {"set": 5}
  }'

九、更新性能优化 #

9.1 批量更新 #

bash
# 批量更新
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '[
    {"id": "book-001", "views": {"inc": 1}},
    {"id": "book-002", "views": {"inc": 1}},
    {"id": "book-003", "views": {"inc": 1}}
  ]'

9.2 延迟提交 #

bash
# 批量更新后统一提交
curl -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
  -H "Content-Type: application/json" \
  -d @updates.json

curl -X POST "http://localhost:8983/solr/mycore/update?commit=true"

9.3 使用软提交 #

bash
curl -X POST "http://localhost:8983/solr/mycore/update?softCommit=true" \
  -H "Content-Type: application/json" \
  -d '{"id": "book-001", "views": {"inc": 1}}'

十、更新监控 #

10.1 更新统计 #

bash
curl "http://localhost:8983/solr/mycore/admin/stats?key=updateHandler"

10.2 事务日志监控 #

bash
# 查看事务日志大小
ls -lh server/solr/mycore/data/tlog/

# 查看事务日志数量
ls server/solr/mycore/data/tlog/ | wc -l

十一、实战示例 #

11.1 商品库存更新 #

bash
# 库存扣减
curl -X POST "http://localhost:8983/solr/products/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "product-001",
    "stock": {"inc": -1},
    "sales": {"inc": 1},
    "updated_at": {"set": "2026-03-27T10:00:00Z"}
  }'

11.2 文章浏览量更新 #

bash
# 浏览量+1
curl -X POST "http://localhost:8983/solr/articles/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "article-001",
    "views": {"inc": 1}
  }'

11.3 用户标签更新 #

bash
# 添加用户标签
curl -X POST "http://localhost:8983/solr/users/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "user-001",
    "tags": {"add": ["VIP", "活跃用户"]},
    "last_active": {"set": "2026-03-27T10:00:00Z"}
  }'

11.4 价格更新 #

bash
# 价格调整
curl -X POST "http://localhost:8983/solr/products/update/json/docs" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "product-001",
    "price": {"set": 7999.00},
    "original_price": {"set": 8999.00},
    "discount": {"set": true},
    "updated_at": {"set": "2026-03-27T10:00:00Z"}
  }'

十二、常见问题 #

12.1 原子更新失败 #

问题:字段未存储

xml
<!-- 错误配置 -->
<field name="title" type="text_general" indexed="true" stored="false"/>

<!-- 正确配置 -->
<field name="title" type="text_general" indexed="true" stored="true"/>

12.2 版本冲突 #

bash
# 处理版本冲突
max_retries=3
for i in $(seq 1 $max_retries); do
  version=$(curl -s "http://localhost:8983/solr/mycore/get?id=book-001" | jq '.doc._version_')
  result=$(curl -s -X POST "http://localhost:8983/solr/mycore/update/json/docs" \
    -H "Content-Type: application/json" \
    -d "{\"id\": \"book-001\", \"title\": {\"set\": \"新标题\"}, \"_version_\": $version}")
  
  if echo "$result" | jq -e '.responseHeader.status == 0' > /dev/null; then
    echo "更新成功"
    break
  fi
  
  echo "重试 $i/$max_retries"
  sleep 1
done

12.3 性能问题 #

bash
# 减少更新频率,批量处理
# 使用队列缓冲更新请求
# 配置合理的自动提交间隔

十三、总结 #

更新方式对比:

方式 适用场景 性能
全量更新 简单场景
原子更新 部分字段更新
脚本更新 复杂逻辑

最佳实践:

  • 优先使用原子更新
  • 批量处理更新请求
  • 使用乐观并发控制
  • 合理配置提交策略
  • 监控更新性能

下一步,让我们学习文档删除!

最后更新:2026-03-27