//package com.ruoyi.project.service.impl;
//
//import com.github.pagehelper.Page;
//import com.github.pagehelper.PageHelper;
//import com.hankcs.hanlp.HanLP;
//import com.hankcs.hanlp.seg.common.Term;
//import com.ruoyi.common.core.text.Convert;
//import com.ruoyi.common.utils.RestHighLevelClientUtils;
//import com.ruoyi.project.domain.*;
//import com.ruoyi.project.mapper.*;
//import com.ruoyi.project.service.ITrsSiteconfigService;
//import org.ahocorasick.trie.Emit;
//import org.ahocorasick.trie.Trie;
//import org.elasticsearch.action.bulk.BulkRequest;
//import org.elasticsearch.action.bulk.BulkResponse;
//import org.elasticsearch.action.index.IndexRequest;
//import org.elasticsearch.action.search.ClearScrollRequest;
//import org.elasticsearch.action.search.SearchRequest;
//import org.elasticsearch.action.search.SearchResponse;
//import org.elasticsearch.action.search.SearchScrollRequest;
//import org.elasticsearch.client.RequestOptions;
//import org.elasticsearch.client.RestHighLevelClient;
//import org.elasticsearch.common.unit.TimeValue;
//import org.elasticsearch.index.query.BoolQueryBuilder;
//import org.elasticsearch.index.query.QueryBuilders;
//import org.elasticsearch.search.SearchHit;
//import org.elasticsearch.search.builder.SearchSourceBuilder;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Service;
//
//import javax.annotation.PreDestroy;
//import java.io.IOException;
//import java.io.InputStream;
//import java.net.HttpURLConnection;
//import java.net.URL;
//import java.util.*;
//import java.util.concurrent.*;
//import java.util.regex.Matcher;
//import java.util.regex.Pattern;
//
///**
// * 配置管理Service业务层处理
// *
// * @author ruoyi
// * @date 2025-03-19
// */
//@Service
//public class TrsSiteconfigServiceImplv3 implements ITrsSiteconfigService
//{
//    @Autowired
//    private TrsSiteconfigMapper trsSiteconfigMapper;
//
//    @Autowired
//    private TrsArticleInfoMapper trsArticleInfoMapper;
//
//    @Autowired
//    private TrsSensitiveWordsMapper trsSensitiveWordsMapper;
//
//    @Autowired
//    private TrsSensitiveResultsMapper trsSensitiveResultsMapper;
//
//
//    @Autowired
//    private RestHighLevelClientUtils restHighLevelClientUtils;
//
//    @Autowired
//    private RestHighLevelClient client;
//
//    @Autowired
//    private TrsTechnicalResultsMapper trsTechnicalResultsMapper;
//    @Autowired
//    private TrsPolicyResultsMapper trsPolicyResultsMapper;
//    @Autowired
//    private TrsNameResultsMapper trsNameResultsMapper;
//
//    @Autowired
//    private TrsDomainResultsMapper trsDomainResultsMapper;
//
//
//
//
//    @Autowired
//    private TrsTechnicalWordsMapper trsTechnicalWordsMapper;
//    @Autowired
//    private TrsPolicyWordsMapper trsPolicyWordsMapper;
//    @Autowired
//    private TrsNameWordsMapper trsNameWordsMapper;
//
//    @Autowired
//    private TrsDomainWordsMapper trsDomainWordsMapper;
//    /**
//     * 查询配置管理
//     *
//     * @param id 配置管理主键
//     * @return 配置管理
//     */
//    @Override
//    public TrsSiteconfig selectTrsSiteconfigById(Long id)
//    {
//        return trsSiteconfigMapper.selectTrsSiteconfigById(id);
//    }
//
//    /**
//     * 查询配置管理列表
//     *
//     * @param trsSiteconfig 配置管理
//     * @return 配置管理
//     */
//    @Override
//    public List<TrsSiteconfig> selectTrsSiteconfigList(TrsSiteconfig trsSiteconfig)
//    {
//        return trsSiteconfigMapper.selectTrsSiteconfigList(trsSiteconfig);
//    }
//
//    /**
//     * 新增配置管理
//     *
//     * @param trsSiteconfig 配置管理
//     * @return 结果
//     */
//    @Override
//    public int insertTrsSiteconfig(TrsSiteconfig trsSiteconfig)
//    {
//        return trsSiteconfigMapper.insertTrsSiteconfig(trsSiteconfig);
//    }
//
//    /**
//     * 修改配置管理
//     *
//     * @param trsSiteconfig 配置管理
//     * @return 结果
//     */
//    @Override
//    public int updateTrsSiteconfig(TrsSiteconfig trsSiteconfig)
//    {
//        return trsSiteconfigMapper.updateTrsSiteconfig(trsSiteconfig);
//    }
//
//    /**
//     * 批量删除配置管理
//     *
//     * @param ids 需要删除的配置管理主键
//     * @return 结果
//     */
//    @Override
//    public int deleteTrsSiteconfigByIds(String ids)
//    {
//        return trsSiteconfigMapper.deleteTrsSiteconfigByIds(Convert.toStrArray(ids));
//    }
//
//    /**
//     * 删除配置管理信息
//     *
//     * @param id 配置管理主键
//     * @return 结果
//     */
//    @Override
//    public int deleteTrsSiteconfigById(Long id)
//    {
//        return trsSiteconfigMapper.deleteTrsSiteconfigById(id);
//    }
//
//    @Override
//    public Integer dosysn(Long id) {
//        int currentPage = 1;
//        int BATCH_SIZE = 1000;
//        while (true) {
//            // 使用 PageHelper 分页
//            Page<TrsArticleInfo> page = PageHelper.startPage(currentPage, BATCH_SIZE);
//
//            // 执行查询
//            TrsArticleInfo trsArticleInfo = new TrsArticleInfo();
//            trsArticleInfo.setRecord(id);
//            List<TrsArticleInfo> articles = trsArticleInfoMapper.selectTrsArticleInfoList(trsArticleInfo);
//
//            if (articles.isEmpty()) {
//                break; // 数据已全部处理完毕
//            }
//
//            // 处理数据（例如插入 Elasticsearch）
//            processArticles(articles);
//
//            // 更新页码
//            currentPage++;
//            System.out.println("已处理 " + (currentPage - 1) * BATCH_SIZE + " 条数据");
//        }
//        return 1;
//    }
//
//    private void processArticles(List<TrsArticleInfo> articles) {
//        BulkRequest bulkRequest = new BulkRequest();
//
//        for (TrsArticleInfo article : articles) {
//            IndexRequest indexRequest = new IndexRequest("articles")
//                    .id(String.valueOf(article.getId()))
//                    .source(
//                            "content", article.getContent(),
//                            "page", article.getUrl(),
//                            "record", article.getRecord()
//                    );
//                    //.source("content", article.getContent(), XContentType.JSON);
//            bulkRequest.add(indexRequest);
//        }
//
//        try {
//            BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
//            if (bulkResponse.hasFailures()) {
//                System.err.println("批量插入失败：" + bulkResponse.buildFailureMessage());
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }
//
//    @Override
//    public void doscan(Long id) {
//        TrsSiteconfig trsSiteconfig = trsSiteconfigMapper.selectTrsSiteconfigById(id);
//        // 缓存敏感词的正确词和错误类型
//        Map<String, String> correctWordMap = new HashMap<>();
//        Map<String, String> errorTypeMap = new HashMap<>();
//
//        //
//        Map<String, String> technicalErrorTypeMap = new HashMap<>();
//        Map<String, String> policyErrorRuleMap = new HashMap<>();
//        Map<String, String> policyErrorTypeMap = new HashMap<>();
//        Map<String, String> nameCountryMap = new HashMap<>();
//        Map<String, String> nameWholeMap = new HashMap<>();
//        Map<String, String> nameShortMap = new HashMap<>();
//        Map<String, String> nameSortMap = new HashMap<>();
//        Map<String, String> domainMap = new HashMap<>();
//
//        loadWhitelist();
//        // 加载敏感词库
//        Trie trie = loadSensitiveWords(correctWordMap, errorTypeMap);
//
//        Trie technicalTrie = loadTechnicalWords(technicalErrorTypeMap);
//        Trie policyTrie = loadPolicyWords(policyErrorRuleMap, policyErrorTypeMap);
//        Trie nameTrie = loadNameWords(nameCountryMap, nameWholeMap,nameShortMap,nameSortMap);
//        Trie domainTrie = loadDomainWords(domainMap);
//
//        // 初始化 Scroll
//        String scrollId = initScroll(id);
//
//        // 分批处理文章
//        while (true) {
//            List<TrsArticleInfo> articles = loadArticlesBatch(scrollId,id);
//            if (articles.isEmpty()) break;
//
//            // 检测敏感词并生成结果
//            /*List<TrsSensitiveResults> results = detect(trie, articles, correctWordMap, errorTypeMap, trsSiteconfig.getSitename());
//            // 保存结果到 MySQL
//            results.forEach(result -> {
//                trsSensitiveResultsMapper.insertTrsSensitiveResults(result);
//            });*/
//
//
//            // 依次检测不同类型的敏感信息
//            detectAndSaveResults(trsSensitiveResultsMapper, TrsSensitiveResults.class, trie, articles, correctWordMap, errorTypeMap, null, null, trsSiteconfig);
//            detectAndSaveResults(trsTechnicalResultsMapper, TrsTechnicalResults.class, technicalTrie, articles, null, technicalErrorTypeMap, null, null, trsSiteconfig);
//            detectAndSaveResults(trsPolicyResultsMapper, TrsPolicyResults.class, policyTrie, articles, null, policyErrorTypeMap, policyErrorRuleMap, null, trsSiteconfig);
//            detectAndSaveResults(trsNameResultsMapper, TrsNameResults.class, nameTrie, articles, nameCountryMap, nameWholeMap, nameShortMap, nameSortMap, trsSiteconfig);
//            detectAndSaveResults(trsDomainResultsMapper, TrsDomainResults.class, domainTrie, articles, null, domainMap, null, null, trsSiteconfig);
//
//
//            if (articles.size()<100) break;
//        }
//
//        // 清理 Scroll
//        ClearScrollRequest clearRequest = new ClearScrollRequest();
//        clearRequest.addScrollId(scrollId);
//        try {
//            client.clearScroll(clearRequest, RequestOptions.DEFAULT);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }
//
//    private <T> void detectAndSaveResults(Object mapper, Class<T> clazz, Trie trie, List<TrsArticleInfo> articles,
//                                          Map<String, String> correctWordMap, Map<String, String> errorTypeMap,
//                                          Map<String, String> extraMap1, Map<String, String> extraMap2,
//                                          TrsSiteconfig trsSiteconfig) {
//        if (mapper == null) {
//            throw new RuntimeException("Mapper 为空，无法插入数据：" + clazz.getName());
//        }
//
//        Map<String, String> selectedErrorMap = errorTypeMap;
//        Map<String, String> selectedExtraMap1 = extraMap1;
//        Map<String, String> selectedExtraMap2 = extraMap2;
//        List<T> results = detect(clazz, trie, articles, correctWordMap, selectedErrorMap, selectedExtraMap1, selectedExtraMap2, trsSiteconfig);
//
//        // 通过反射调用 insert 方法
//        for (Object result : results) {
//            if (mapper instanceof TrsSensitiveResultsMapper) {
//                 ((TrsSensitiveResultsMapper) mapper).insertTrsSensitiveResults((TrsSensitiveResults) result);
//            } else if (mapper instanceof TrsTechnicalResultsMapper) {
//                ((TrsTechnicalResultsMapper) mapper).insertTrsTechnicalResults((TrsTechnicalResults) result);
//            } else if (mapper instanceof TrsPolicyResultsMapper) {
//                ((TrsPolicyResultsMapper) mapper).insertTrsPolicyResults((TrsPolicyResults) result);
//            } else if (mapper instanceof TrsNameResultsMapper) {
//                ((TrsNameResultsMapper) mapper).insertTrsNameResults((TrsNameResults) result);
//            } else if (mapper instanceof TrsDomainResultsMapper) {
//                ((TrsDomainResultsMapper) mapper).insertTrsDomainResults((TrsDomainResults) result);
//            } else {
//                throw new RuntimeException("未找到适配的 Mapper：" + mapper.getClass().getSimpleName());
//            }
//        }
//    }
//
//    private <T> List<T> detect(Class<T> clazz, Trie trie, List<TrsArticleInfo> articles,
//                               Map<String, String> correctWordMap, Map<String, String> errorTypeMap,
//                               Map<String, String> extraMap1, Map<String, String> extraMap2,
//                               TrsSiteconfig trsSiteconfig) {
//        Set<T> resultSet = new HashSet<>();
//
//        for (TrsArticleInfo article : articles) {
//            String content = article.getContent();
////            resultSet.addAll(detectContent(clazz, trie, content, correctWordMap, errorTypeMap, sitename, article.getUrl()));
////            resultSet.addAll(detectSegmentedContent(clazz, trie, content, correctWordMap, errorTypeMap, sitename, article.getUrl()));
//
//            resultSet.addAll(detectContent(clazz, trie, content, correctWordMap, errorTypeMap, extraMap1, extraMap2, trsSiteconfig, article.getUrl()));
//            resultSet.addAll(detectSegmentedContent(clazz, trie, content, correctWordMap, errorTypeMap, extraMap1, extraMap2, trsSiteconfig, article.getUrl()));
//
//        }
//
//        return new ArrayList<>(resultSet);
//    }
//    private <T> List<T> detectContent(Class<T> clazz, Trie trie, String content,
//                                      Map<String, String> correctWordMap, Map<String, String> errorTypeMap,
//                                      Map<String, String> extraMap1, Map<String, String> extraMap2,
//                                      TrsSiteconfig trsSiteconfig, String url) {
//        List<T> results = new ArrayList<>();
//
//        for (Emit emit : trie.parseText(content)) {
//            String wrongWord = emit.getKeyword();
//
//            // 如果匹配到的词在白名单中，则跳过
//            if (isInWhitelist(content, emit.getStart(), emit.getEnd() + 1)) {
//                continue;
//            }
//
//            // 只匹配独立的词，确保不是误匹配
//            Matcher matcher = Pattern.compile("\\b" + Pattern.quote(wrongWord) + "\\b").matcher(content);
//            if (matcher.find()) {
//                T result = createResultInstance(clazz, url, wrongWord, correctWordMap, errorTypeMap, extraMap1, extraMap2, trsSiteconfig, content, emit.getStart(), emit.getEnd());
//                results.add(result);
//            }
//        }
//
//        return results;
//    }
//
//
//    private <T> List<T> detectSegmentedContent(Class<T> clazz, Trie trie, String content,
//                                               Map<String, String> correctWordMap, Map<String, String> errorTypeMap,
//                                               Map<String, String> extraMap1, Map<String, String> extraMap2,
//                                               TrsSiteconfig trsSiteconfig, String url) {
//        List<T> results = new ArrayList<>();
//
//        // 先对文章进行分词
//        List<String> words = segmentText(content);
//
//        // 逐个分词进行敏感词匹配
//        for (String word : words) {
//            for (Emit emit : trie.parseText(word)) {
//                String wrongWord = emit.getKeyword();
//
//                // 如果匹配到的词在白名单中，则跳过
//                if (isInWhitelist(content, emit.getStart(), emit.getEnd() + 1)) {
//                    continue;
//                }
//
//                // 只匹配独立的词，确保不是误匹配
//                Matcher matcher = Pattern.compile("\\b" + Pattern.quote(wrongWord) + "\\b").matcher(word);
//                if (matcher.find()) {
//                    // 确定分词的起始和结束位置
//                    int start = content.indexOf(word);
//                    int end = start + word.length();
//
//                    T result = createResultInstance(clazz, url, wrongWord, correctWordMap, errorTypeMap, extraMap1, extraMap2, trsSiteconfig, content, start, end);
//                    results.add(result);
//                }
//            }
//        }
//
//        return results;
//    }
//
//    private <T> T createResultInstance(Class<T> clazz, String url, String wrongWord,
//                                       Map<String, String> correctWordMap, Map<String, String> errorTypeMap,
//                                       Map<String, String> extraMap1, Map<String, String> extraMap2,
//                                       TrsSiteconfig trsSiteconfig, String content, int start, int end) {
//        try {
//            T result = clazz.getDeclaredConstructor().newInstance();
//
//            if (result instanceof TrsSensitiveResults) {
//                TrsSensitiveResults r = (TrsSensitiveResults) result;
//                r.setPage(url);
//                r.setWrongWord(wrongWord);
//                r.setCorrectWord(correctWordMap.getOrDefault(wrongWord, "未知"));
//                r.setErrorType(errorTypeMap.getOrDefault(wrongWord, "未知"));
//                r.setContext(extractContext(content, start, end));
//                r.setSitename(trsSiteconfig.getSitename());
//                r.setStatus("待处理");
//
//            } else if (result instanceof TrsTechnicalResults) {
//                TrsTechnicalResults r = (TrsTechnicalResults) result;
//                r.setPage(url);
//                r.setWrongWord(wrongWord);
//                r.setErrorType(errorTypeMap.getOrDefault(wrongWord, "未知"));
//                r.setContext(extractContext(content, start, end));
//                r.setSitename(trsSiteconfig.getSitename());
//                r.setStatus("待处理");
//
//            } else if (result instanceof TrsPolicyResults) {
//                TrsPolicyResults r = (TrsPolicyResults) result;
//                r.setPage(url);
//                r.setWrongWord(wrongWord);
//                r.setErrorType(errorTypeMap.getOrDefault(wrongWord, "未知"));
//                r.setContext(extractContext(content, start, end));
//                r.setSitename(trsSiteconfig.getSitename());
//                r.setStatus("待处理");
//                r.setWrongRule(extraMap1 != null ? extraMap1.getOrDefault(wrongWord, "未知") : "未知");
//
//            } else if (result instanceof TrsNameResults) {
//                TrsNameResults r = (TrsNameResults) result;
//                r.setPage(url);
//                r.setWrongWord(wrongWord);
//                r.setSort(extraMap2 != null ? extraMap2.getOrDefault(wrongWord, "未知") : "未知");
//                r.setDutyShort(extraMap1 != null ? extraMap1.getOrDefault(wrongWord, "未知") : "未知");
//                r.setDutyAll(errorTypeMap != null ? errorTypeMap.getOrDefault(wrongWord, "未知") : "未知");
//                r.setCountry(correctWordMap != null ? correctWordMap.getOrDefault(wrongWord, "未知") : "未知");
//                r.setContext(extractContext(content, start, end));
//                r.setSitename(trsSiteconfig.getSitename());
//                r.setStatus("待处理");
//
//            } else if (result instanceof TrsDomainResults) {
//                TrsDomainResults r = (TrsDomainResults) result;
//                r.setPage(url);
//                r.setWrongWord(wrongWord);
//                r.setDomainType(errorTypeMap != null ? errorTypeMap.getOrDefault(wrongWord, "未知") : "未知");
//                r.setContext(extractContext(content, start, end));
//                r.setSitename(trsSiteconfig.getSitename());
//                r.setStatus("待处理");
//
//            } else {
//                throw new RuntimeException("未支持的结果类型：" + clazz.getName());
//            }
//
//            return result;
//        } catch (Exception e) {
//            throw new RuntimeException("无法创建实例：" + clazz.getName(), e);
//        }
//    }
//
//
//
//
//
//
//    public List<String> segmentText(String text) {
//        List<Term> termList = HanLP.segment(text);
//        List<String> words = new ArrayList<>();
//        for (Term term : termList) {
//            words.add(term.word);
//        }
//        return words;
//    }
//
//    // 检测敏感词并生成结果
///*    public List<TrsSensitiveResults> detect(Trie trie, List<TrsArticleInfo> articles,
//                                            Map<String, String> correctWordMap,
//                                            Map<String, String> errorTypeMap, String sitename) {
//        Set<TrsSensitiveResults> resultSet = new HashSet<>(); // 使用 Set 去重
//
//        for (TrsArticleInfo article : articles) {
//            String content = article.getContent();
//
//            // 1. 先进行整体匹配
//            resultSet.addAll(detectWholeContent(trie, content, correctWordMap, errorTypeMap, sitename, article.getUrl()));
//
//            // 2. 再进行分词后匹配
//            resultSet.addAll(detectSegmentedContent(trie, content, correctWordMap, errorTypeMap, sitename, article.getUrl()));
//        }
//
//        return new ArrayList<>(resultSet); // 转换为 List 返回
//    }
//
//    *//**
//     * 整体匹配：直接对文章内容进行敏感词匹配
//     *//*
//    private List<TrsSensitiveResults> detectWholeContent(Trie trie, String content,
//                                                         Map<String, String> correctWordMap,
//                                                         Map<String, String> errorTypeMap, String sitename, String url) {
//        List<TrsSensitiveResults> results = new ArrayList<>();
//
//        for (Emit emit : trie.parseText(content)) {
//            String wrongWord = emit.getKeyword();
//
//            // 判断错词是否在白名单短语里
//            if (isInWhitelist(content, emit.getStart(), emit.getEnd() + 1)) {
//                continue; // 跳过匹配
//            }
//
//            // 使用正则表达式匹配独立的词
//            String regex = "\\b" + Pattern.quote(wrongWord) + "\\b";
//            Pattern pattern = Pattern.compile(regex);
//            Matcher matcher = pattern.matcher(content);
//
//            // 如果匹配到独立的词
//            if (matcher.find()) {
//                TrsSensitiveResults trsSensitiveResults = new TrsSensitiveResults();
//                trsSensitiveResults.setPage(url);
//                trsSensitiveResults.setWrongWord(wrongWord);
//                trsSensitiveResults.setCorrectWord(correctWordMap.get(wrongWord));
//                trsSensitiveResults.setErrorType(errorTypeMap.get(wrongWord));
//                trsSensitiveResults.setContext(extractContext(content, emit.getStart(), emit.getEnd()));
//                trsSensitiveResults.setSitename(sitename);
//                trsSensitiveResults.setStatus("待处理");
//                results.add(trsSensitiveResults);
//            }
//        }
//
//        return results;
//    }
//
//    *//**
//     * 分词后匹配：对文章内容进行分词，然后对每个分词结果进行敏感词匹配
//     *//*
//    private List<TrsSensitiveResults> detectSegmentedContent(Trie trie, String content,
//                                                             Map<String, String> correctWordMap,
//                                                             Map<String, String> errorTypeMap, String sitename, String url) {
//        List<TrsSensitiveResults> results = new ArrayList<>();
//
//        // 对内容进行分词
//        List<String> words = segmentText(content);
//
//        // 对每个分词结果进行敏感词匹配
//        for (String word : words) {
//            for (Emit emit : trie.parseText(word)) {
//                String wrongWord = emit.getKeyword();
//
//                // 判断错词是否在白名单短语里
//                if (isInWhitelist(content, emit.getStart(), emit.getEnd() + 1)) {
//                    continue; // 跳过匹配
//                }
//
//                // 使用正则表达式匹配独立的词
//                String regex = "\\b" + Pattern.quote(wrongWord) + "\\b";
//                Pattern pattern = Pattern.compile(regex);
//                Matcher matcher = pattern.matcher(word);
//
//                // 如果匹配到独立的词
//                if (matcher.find()) {
//                    // 找到分词结果在原始内容中的位置
//                    int start = content.indexOf(word); // 分词结果在原始内容中的起始位置
//                    int end = start + word.length();   // 分词结果在原始内容中的结束位置
//                    TrsSensitiveResults trsSensitiveResults = new TrsSensitiveResults();
//                    trsSensitiveResults.setPage(url);
//                    trsSensitiveResults.setWrongWord(wrongWord);
//                    trsSensitiveResults.setCorrectWord(correctWordMap.get(wrongWord));
//                    trsSensitiveResults.setErrorType(errorTypeMap.get(wrongWord));
////                    trsSensitiveResults.setContext(extractContext(word, emit.getStart(), emit.getEnd()));
//                    trsSensitiveResults.setContext(extractContext(content, start, end)); // 从原始内容中截取上下文
//                    trsSensitiveResults.setSitename(sitename);
//                    trsSensitiveResults.setStatus("待处理");
//                    results.add(trsSensitiveResults);
//                }
//            }
//        }
//
//        return results;
//    }*/
//
//    // 提取上下文（示例：前后 20 字符）
//    private  String extractContext(String text, int start, int end) {
//        int contextSize = 20;
//        int contextStart = Math.max(0, start - contextSize);
//        int contextEnd = Math.min(text.length(), end + contextSize);
//        return text.substring(contextStart, contextEnd);
//    }
//
//    public void doArticleInfo(Long id) {
//
//    }
//
//    // 初始化 Scroll 查询
//    public String initScroll(Long id) {
//        SearchRequest searchRequest = new SearchRequest("articles");
//        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//        boolQueryBuilder.filter(QueryBuilders.termQuery("record", id));
//        sourceBuilder.query(boolQueryBuilder);
////        sourceBuilder.query(QueryBuilders.matchAllQuery());
//        sourceBuilder.size(100); // 每批加载 1000 篇文章
////        sourceBuilder.timeout(TimeValue.timeValueSeconds(30)); // 增加超时时间
//        searchRequest.source(sourceBuilder);
//        searchRequest.scroll(TimeValue.timeValueMinutes(1L));
//        SearchResponse response = null;
//        try {
//            response = client.search(searchRequest, RequestOptions.DEFAULT);
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
//        return response.getScrollId();
//    }
//
//    // 从 MySQL 加载敏感词库
//    public Trie loadSensitiveWords(Map<String, String> correctWordMap, Map<String, String> errorTypeMap) {
//        /*
//            java Aho-Corasick算法
//            Aho-Corasick算法是一种用于多模式字符串匹配的算法，它可以同时在一个文本字符串中查找多个模式字符串。该算法由Alfred V. Aho和Margaret J. Corasick在1975年共同发明。相比于传统的多模式匹配方法（如KMP算法），Aho-Corasick算法在处理多个模式时具有更高的效率。
//            Aho-Corasick算法的工作原理
//            构建Trie树：首先，将所有模式字符串构建成一个Trie树（前缀树）。
//            构建失败链接：在Trie树上添加失败链接（也称为失效链接或故障链接），使得在匹配过程中遇到非匹配字符时可以跳转到Trie树上的其他节点，从而减少不必要的回溯。
//            输出链接：对于每个节点，标记其所有子节点对应的模式字符串的结束位置。这样，在遍历文本字符串时，一旦到达某个节点的输出链接，就意味着在该位置找到了一个模式字符串。
//            匹配过程：在文本字符串上从左到右进行扫描，利用Trie树和失败链接进行匹配。如果在某个节点上找到了一个模式字符串的结束，就记录下这个位置。
//         */
//        Trie.TrieBuilder builder = Trie.builder();
//
//        TrsSensitiveWords trsSensitiveWords = new TrsSensitiveWords();
//        List<TrsSensitiveWords> sensitiveWords = trsSensitiveWordsMapper.selectTrsSensitiveWordsList(trsSensitiveWords);
//        for (TrsSensitiveWords sensitiveWord : sensitiveWords) {
//            String wrongWord = sensitiveWord.getWrongWord();
//            builder.addKeyword(wrongWord);
//            correctWordMap.put(wrongWord, sensitiveWord.getCorrectWord());
//            errorTypeMap.put(wrongWord, sensitiveWord.getErrorType());
//        }
//        return builder.build();
//    }
//
//    public Trie loadTechnicalWords(Map<String, String> errorTypeMap) {
//        Trie.TrieBuilder builder = Trie.builder();
//        TrsTechnicalWords results = new TrsTechnicalWords();
//        List<TrsTechnicalWords> results1 = trsTechnicalWordsMapper.selectTrsTechnicalWordsList(results);
//        for (TrsTechnicalWords sensitiveWord : results1) {
//            String wrongWord = sensitiveWord.getWrongWord();
//            builder.addKeyword(wrongWord);
//            errorTypeMap.put(wrongWord, sensitiveWord.getErrorType());
//        }
//        return builder.build();
//    }
//
//    public Trie loadPolicyWords(Map<String, String> policyErrorRuleMap, Map<String, String> policyErrorTypeMap) {
//        Trie.TrieBuilder builder = Trie.builder();
//        TrsPolicyWords results = new TrsPolicyWords();
//        List<TrsPolicyWords> results1 = trsPolicyWordsMapper.selectTrsPolicyWordsList(results);
//        for (TrsPolicyWords sensitiveWord : results1) {
//            String wrongWord = sensitiveWord.getWrongWord();
//            builder.addKeyword(wrongWord);
//            policyErrorRuleMap.put(wrongWord, sensitiveWord.getErrorRule());
//            policyErrorTypeMap.put(wrongWord, sensitiveWord.getErrorType());
//        }
//        return builder.build();
//    }
//
//    public Trie loadNameWords(Map<String, String> nameCountryMap, Map<String, String> nameWholeMap, Map<String, String> nameShortMap, Map<String, String> nameSortMap) {
//        Trie.TrieBuilder builder = Trie.builder();
//        TrsNameWords results = new TrsNameWords();
//        List<TrsNameWords> results1 = trsNameWordsMapper.selectTrsNameWordsList(results);
//        for (TrsNameWords sensitiveWord : results1) {
//            String wrongWord = sensitiveWord.getWrongWord();
//            builder.addKeyword(wrongWord);
//            nameCountryMap.put(wrongWord, sensitiveWord.getCountry());
//            nameWholeMap.put(wrongWord, sensitiveWord.getDutyAll());
//            nameShortMap.put(wrongWord, sensitiveWord.getDutyShort());
//            nameSortMap.put(wrongWord, sensitiveWord.getSort());
//        }
//        return builder.build();
//    }
//
//    public Trie loadDomainWords(Map<String, String> domainMap) {
//        Trie.TrieBuilder builder = Trie.builder();
//        TrsDomainWords results = new TrsDomainWords();
//        List<TrsDomainWords> results1 = trsDomainWordsMapper.selectTrsDomainWordsList(results);
//        for (TrsDomainWords sensitiveWord : results1) {
//            String wrongWord = sensitiveWord.getWrongWord();
//            builder.addKeyword(wrongWord);
//            domainMap.put(wrongWord, sensitiveWord.getDomainType());
//        }
//        return builder.build();
//    }
//
//    // 加载一批文章
//    public List<TrsArticleInfo> loadArticlesBatch(String scrollId, Long id) {
//        List<TrsArticleInfo> articles = new ArrayList<>();
//        SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
//        scrollRequest.scroll(TimeValue.timeValueMinutes(1L));
//        SearchResponse response = null;
//        try {
//            response = client.scroll(scrollRequest, RequestOptions.DEFAULT);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        //通过response获取命中的数量
//        System.out.println("response获取命中的数量：" + response.getHits().getTotalHits().value);
//        long totalHits = response.getHits().getTotalHits().value;
//        if (totalHits < 100 && totalHits>0) {
//            SearchRequest searchRequest = new SearchRequest("articles");
//            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//            boolQueryBuilder.filter(QueryBuilders.termQuery("record", id));
//            searchRequest.source(sourceBuilder);
//            sourceBuilder.query(boolQueryBuilder);
//            try {
//                response = client.search(searchRequest, RequestOptions.DEFAULT);
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
//
//
//        for (SearchHit hit : response.getHits().getHits()) {
//            Map<String, Object> source = hit.getSourceAsMap();
//            TrsArticleInfo article =new TrsArticleInfo();
//            article.setContent((String) source.get("content"));
//            article.setUrl((String) source.get("page"));
//            articles.add(article);
//        }
//        return articles;
//    }
//
//
//    private Set<String> whitelistPhrases = new HashSet<>();
//    public void loadWhitelist() {
//        // 这里可以从数据库或配置文件加载白名单
//        /*whitelistPhrases.add("内蒙古自治区");
//        whitelistPhrases.add("中国银行");
//        whitelistPhrases.add("中华人民共和国");*/
//        TrsSensitiveWords trsSensitiveWords = new TrsSensitiveWords();
//        trsSensitiveWords.setFlag(0);
//        trsSensitiveWordsMapper.selectTrsSensitiveWordsListBy(new TrsSensitiveWords()).forEach(sensitiveWord -> {
//            whitelistPhrases.add(sensitiveWord.getWrongWord());
//        });
//    }
//    private boolean isInWhitelist(String text, int start, int end) {
//        for (String phrase : whitelistPhrases) {
//            int phraseStart = start - (phrase.length() - (end - start)); // 计算完整短语的起点
//            if (phraseStart >= 0 && phraseStart + phrase.length() <= text.length()) {
//                String subText = text.substring(phraseStart, phraseStart + phrase.length());
//                if (whitelistPhrases.contains(subText)) {
//                    return true; // 如果匹配到白名单短语，则跳过
//                }
//            }
//        }
//        return false;
//    }
//
//
//    @Override
//    public void docon(Long id) {
//        TrsSiteconfig trsSiteconfig = trsSiteconfigMapper.selectTrsSiteconfigById(id);
//        loadAllowedDomains(trsSiteconfig.getDomain());
////        List<String> urls = trsArticleInfoMapper.selectTrsArticleInfoUrlList(id);
//        TrsArticleInfo trsArticleInfo = new TrsArticleInfo();
//        trsArticleInfo.setRecord(id);
//        List<TrsArticleInfo> trsArticleInfos = trsArticleInfoMapper.selectTrsArticleInfoList(trsArticleInfo);
//        processUrls(trsArticleInfos);
//    }
//
//
//    private Set<String> ALLOWED_DOMAINS = new HashSet<>();
//    public void loadAllowedDomains(String domain) {
//        ALLOWED_DOMAINS.add(domain);
//    }
//    /**
//     * 判断 URL 是否是外链
//     *
//     * @param url URL 地址
//     * @return true 是外链，false 不是外链
//     */
//    private boolean isExternalLink(String url) {
//        try {
//            URL parsedUrl = new URL(url);
//            String host = parsedUrl.getHost();
//            return !ALLOWED_DOMAINS.contains(host);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return true; // 如果解析失败，默认认为是外链
//        }
//    }
//
//    /**
//     * 判断 URL 是否是错断链
//     *
//     * @param url URL 地址
//     * @return true 是错断链，false 不是错断链
//     */
//    private boolean isBrokenLink(String url) {
//        HttpURLConnection connection = null;
//        try {
//            URL parsedUrl = new URL(url);
//            connection = (HttpURLConnection) parsedUrl.openConnection();
//            connection.setRequestMethod("HEAD"); // 使用 HEAD 方法，只获取响应头，不下载内容
//            connection.setConnectTimeout(5000); // 设置连接超时
//            connection.setReadTimeout(5000); // 设置读取超时
//            int responseCode = connection.getResponseCode();
//            return responseCode == HttpURLConnection.HTTP_NOT_FOUND || responseCode >= 400;
//        } catch (IOException e) {
//            e.printStackTrace();
//            return true; // 如果请求失败，默认认为是错断链
//        } finally {
//            if (connection != null) {
//                connection.disconnect(); // 关闭连接
//            }
//        }
//    }
//
//    /**
//     * 获取 URL 的内容
//     *
//     * @param url URL 地址
//     * @return URL 的内容，如果获取失败则返回 null
//     */
//    private String getUrlContent(String url) {
//        HttpURLConnection connection = null;
//        try {
//            URL parsedUrl = new URL(url);
//            connection = (HttpURLConnection) parsedUrl.openConnection();
//            connection.setRequestMethod("GET"); // 使用 GET 方法获取内容
//            connection.setConnectTimeout(5000); // 设置连接超时
//            connection.setReadTimeout(5000); // 设置读取超时
//
//            int responseCode = connection.getResponseCode();
//            if (responseCode == HttpURLConnection.HTTP_OK) {
//                InputStream inputStream = connection.getInputStream();
//                Scanner scanner = new Scanner(inputStream).useDelimiter("\\A");
//                return scanner.hasNext() ? scanner.next() : null;
//            } else {
//                return null; // 如果状态码不是 200，返回 null
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//            return null; // 如果请求失败，返回 null
//        } finally {
//            if (connection != null) {
//                connection.disconnect(); // 关闭连接
//            }
//        }
//    }
//
//    /**
//     * 处理单个 URL
//     *
//     * @param
//     * @return 处理结果
//     */
//    private String processSingleUrl(TrsArticleInfo trsArticleInfo) {
//        if (isExternalLink(trsArticleInfo.getUrl())) {
//            return "外链: " + trsArticleInfo.getUrl();
//        } else if (isBrokenLink(trsArticleInfo.getUrl())) {
//            return "错断链: " + trsArticleInfo.getUrl();
//        } else {
//            String content = getUrlContent(trsArticleInfo.getUrl());
//            if (content != null) {
//                //更新到数据库中
//                trsArticleInfo.setContent(content);
//                trsArticleInfoMapper.updateTrsArticleInfo(trsArticleInfo);
//                return "URL 内容: " + content.substring(0, Math.min(content.length(), 100)) + "..."; // 只打印前 100 个字符
//            } else {
//                return "无法获取 URL 内容: " + trsArticleInfo.getUrl();
//            }
//        }
//    }
//    /**
//     * 多线程处理 URL 列表
//     *
//     * @param urls URL 列表
//     * @return 处理结果列表
//     */
//    // 线程池
//    private final ExecutorService executorService = Executors.newFixedThreadPool(10);
//    public ConcurrentHashMap<String, String> processUrls(List<TrsArticleInfo> trsArticleInfos) {
//        ConcurrentHashMap<String, String> resultMap = new ConcurrentHashMap<>();
//        CountDownLatch latch = new CountDownLatch(trsArticleInfos.size()); // 用于等待所有任务完成
//        // 提交任务到线程池
//        for (TrsArticleInfo articleInfo : trsArticleInfos) {
//            executorService.submit(() -> {
//                try {
//                    String result = processSingleUrl(articleInfo);
//                    resultMap.put(articleInfo.getUrl(), result);
//                } finally {
//                    latch.countDown(); // 任务完成，计数器减一
//                }
//            });
//        }
//
//        try {
//            latch.await(); // 等待所有任务完成
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//
//        return resultMap;
//    }
//    /**
//     * 关闭线程池
//     */
//    @PreDestroy
//    public void shutdown() {
//        executorService.shutdown();
//        try {
//            if (!executorService.awaitTermination(1, TimeUnit.MINUTES)) {
//                executorService.shutdownNow();
//            }
//        } catch (InterruptedException e) {
//            executorService.shutdownNow();
//        }
//    }
//
//}
