搜索引擎质量指标(nDCG) 参考博客https://blog.csdn.net/LintaoD/article/details/82661206
特征feature:相关性 时效性 质量 点击率 权威度 冷启动
搜索/推荐业务哪一些场景要放到缓存
搜索:特征
大页cache和小页cache 实现区别
小页缓存是为了提高进入搜索结果页的加载速度,是渐进加载或者叫预加载,将原来的1页内容分两页返回,第一页请求回30个,分为两页返回,第一页返回10个,第二页返回20个。
大页缓存是对一次完整的请求结果,只不过不是像原来的请求一页30个,现在第一次请求会70多个结果,最开始是一下请求回5页共150个结果
推荐:分user和item,是单独存的。然后user又分为很多个feature
需求1:给一批query,保证每个query下都返回卡片A的a字段(数据脱敏)
需求2:给上万个keyword校验每个keyword算法接口下召回A且B或A或B或AB都没有的比率
需求3:意图理解测试(要求手动测试,标注,但可以用脚本实现)。给一批新的词表,纠错类的一共70。其他的一共700,头部一共有400,腰部200,尾部100。乱序排的,哪层都有。
意图接口测试:类目预测、纠错、改写、qt(query tagging分词)。qp的当前线上结果也会出现badcase,所以需要人工审核下数据
对于超时无结果的可以查接口补充数据,如下:
改写的结果 :
设计:query准备,PM提供的Excel格式,转换为txt格式,但是没有,
shell脚本处理
把文件1.txt的内容在每行结尾添加,写到2.txt
➜ ~ sed 's/$/&,/g' 1.txt > 2.txt
[文本处理] 多列合并一行的SHELL,以,隔开
➜ ~ awk '{a=a?a","$1:$1;b=b?b","$2:$2}END{print a,b}' 1.txt
脚本部分-线上环境:
业务需求1:logOnlineReadFiles70-纠错
接口取值--多层nodes下取需求字段
QP算法接口返回的数据:qc(纠错词) qaGrade(纠错词级别) keyword(原始query)
业务接口:取第二个卡片的类型-标题 docSource-object_title,因为第1个(index=0)的nodes为纠错词,第二个(index=1)为业务卡片
业务需求2:logOnlineReadFiles700-改写
logOnlineReadFilesQP-类目预测category,打分level,分词数组query tagging
业务接口:取第一个卡片的类型-标题 docSource-object_title,因为无纠错词,第一个(index=0)为业务卡片
算法接口:取打分、分词、改写、纠错、类型标注
特殊字段查找,CR代码:
/**
* 纠错词级别:1提示,2替换查询
*/
private int qcGrade;
框架设计:取算法接口和业务接口同时判断
基于httpclient框架,以及对文件解析处理,按照需求设计需要的列,如ABC列分别abc三个文件。CD两列写入c文件
整体设计:shell解析Excel文件内容,读取txt文件,query分类(3类),3类接口结果按需求要求写入文本,每次运行程序前删除txt文件,新数据可每次写入
代码如下:
1. 70个纠错词query-业务代码实现
package com.alibaba.searchQP.utils;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import static com.alibaba.searchQP.utils.ReadFiles.readTxt;
/**
* Excel文本处理:query粘贴放到1.txt文件,执行awk '{a=a?a","$1:$1;b=b?b","$2:$2}END{print a,b}' 1.txt
* 处理70个纠错词query,Excel原始query取纠错词以及取第一个卡片类型-标题
*/
public class logOnlineReadFiles70 {
private static Logger logger = LoggerFactory.getLogger(logOnlineReadFiles700.class);
public static void main(String[] args) {
// 运行程序(读取新的log文件)之前,清空旧文件(上次的log日志信息)
FileWrite.deleteAllLogFile();
FileWrite.deleteAllLogCopyFile();
startSearch();
}
// 定义集合,把搜索场景放到list集合
public static List<String> list = new ArrayList<>();
public static void startSearch() {
long startTime = System.currentTimeMillis();
System.out.println("===程序开始执行===");
// 拼接的传参参数为中文,需要把中文放到map
// 方法1:把待测试的query top排行前1000在odps查询出,存到本地,再通过接口拼接
String filePath = "/Users/lishan/Desktop/code/xx/qp.txt";
System.out.println(filePath);
String[] keywords = readTxt(filePath);
// System.out.println("strings:" + Arrays.toString(keywords));
// String keywords=record.getString("f1");
// 方法2:代码读取odps工具类,查询top1000的query,再通过接口拼接
// 见logOnlineReadODPS
// String[] keywords={"吴亦凡","杨幂","唐嫣"};
// String[] keywords = {"吴亦凡"};
int only1 = 0;
String query1 = "";
int totalCount = 0;
try {
for (int i = 0; i < keywords.length; i++) {
Map<String, String> query = new HashMap<>();
query.put("keyword", keywords[i]);
// 如果URL没有公共参数,则把 ?去掉;
// 业务接口传参增加cmd=4拿到引擎字段返回
String url_pre = "http://xx";
// 开始请求,域名、接口名==url+请求参数param(hashMap)
// String response = HTTPCommonMethod.doGet(url_pre, url_online, map, count);
System.out.println("第" + (i + 1) + "条数据==" + query);
String response = HTTPCommonMethod.doGet(url_pre, query, i);
JSONObject responseJson = JSONObject.parseObject(response);
int type = responseToParse(i, keywords[i], responseJson);
// 仅节目卡
if (type == 1) {
only1++;
query1 = query1 + keywords[i] + ",";
// 仅系列卡
}
// 打印接口返回的数据
// System.out.println("第【" + i + "】条日志,预发环境pre接口返回response为=======" + response);
totalCount = i + 1;
// System.out.println("每次循环的totalCount=="+totalCount);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("totalCount==" + totalCount);
float rate3 = (float) only1 / (float) totalCount;
System.out.println("------------------------------------------------------------------------------------------------");
System.out.println("------------------------------------------------------------------------------------------------");
System.out.println("only1---召回纠错词卡==【" + only1 + "】个,总数" + totalCount + "个,---比率为==【" + rate3 + "】---query1==【" + query1 + "】");
long endTime = System.currentTimeMillis();
System.out.println("===程序结束执行===");
long durationTime = endTime - startTime;
System.out.println("===程序耗时===【" + durationTime + "】毫秒");
// System.out.println("===程序耗时===【" + durationTime / 1000 / 60 + "】分钟");
}
/**
* @param count
* @param query
* @param response
* @return 1:返回纠错词卡片 2: 未返回
*/
public static int responseToParse(int count, String query, JSONObject response) {
try {
// HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
boolean qpResult = false;
if (!response.isEmpty()) {
// 获取JSONObject
// 意图理解算法接口:是否纠错qcGrade。纠错词级别:1提示,2替换查询
// 业务接口:取第一个纠错词结果的卡片标题和卡片类型
// QP接口
JSONObject data0 = response.getJSONArray("nodes").getJSONObject(0).
getJSONArray("nodes").getJSONObject(0).
getJSONArray("nodes").getJSONObject(0).
getJSONObject("data");
// 纠错词类型
Integer qcGrade = data0.getInteger("qcGrade");
// qc为纠错词,如keyword=新白胖子传奇,qc=新白娘子传奇
String qc = data0.getString("qc");
// keyword为原始query(用户输入),如keyword=新白胖子传奇
String keyword = data0.getString("keyword");
// 业务接口
JSONObject data1 = response.getJSONArray("nodes").getJSONObject(1).
getJSONArray("nodes").getJSONObject(0).
getJSONArray("nodes").getJSONObject(0).
getJSONObject("data");
String object_title = data1.getJSONObject("action").getJSONObject("report").
getJSONObject("trackInfo").getString("object_title");
Integer docSource = data1.getInteger("docSource");
// QP算法接口和业务接口同时满足时
if (qcGrade == 2 && (!qc.equals(keyword))) {
if (!object_title.isEmpty() && docSource != 0) {
System.out.println("第【" + (count + 1) + "】条日志,搜索query为==【" + query + "】,纠错词qc为==【" + qc + "】," +
"docSource==【" + docSource + "】,第一个卡片标题==【" + object_title + "】");
// 用于写入正常日志文件originLog,再做字段拆分,从而写入数据库,记录读取的log日志
// 全部数据
// FileWrite.originLog(FileWrite.rex + query + FileWrite.rex + qc + FileWrite.rex + docSource + "-" + object_title);
// 单个字段写入-原始query 纠错词qc 类型-第一个卡片的主标题
FileWrite.keywordLog(query);
FileWrite.qcLog(qc);
FileWrite.videoTitleLog(docSource + "-" + object_title);
qpResult = true;
} else {
System.err.println("BUG!BUG!BUG!QP接口识别错误,未纠错!!!第【" + (count + 1) + "】条日志," +
"搜索query为==【" + query + "】,纠错词qc为==【" + qc + "】," +
"docSource==【" + docSource + "】,第一个卡片标题==【" + object_title + "】");
}
}
if (qpResult) {
// 是纠错词卡片
return 1;
//
} else {
return 0;
}
} else {
System.err.println("第【" + count + "】条日志,搜索query为==【" + query + "】,接口返回为空");
}
} catch (Exception e) {
e.printStackTrace();
}
return 2;
}
public static JSONObject jsonObject = new JSONObject();
}
700个query类目预测-业务代码实现
算法接口-分词,对应query_tagging.tag.word
package com.alibaba.searchQP.utils;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import static com.alibaba.searchQP.utils.ReadFiles.readTxt;
/**
* Excel文本处理:query粘贴放到1.txt文件,执行awk '{a=a?a","$1:$1;b=b?b","$2:$2}END{print a,b}' 1.txt
* 处理700个query,纠错、类目预测 、改写、qt(query tagging分词),Excel原始query取第一个卡片类型-标题
* 人物卡-12 scg播单-98 banner(大图推广)-24 节目大词-10 等返回的json格式略微不同,时间原因,暂未开发对此类query的支持。所以这部分数据抓取结果为空,可以手动移动下
* 跑700个query 直接用此脚本运行
*/
public class logOnlineReadFiles700 {
private static Logger logger = LoggerFactory.getLogger(logOnlineReadFiles700.class);
public static void main(String[] args) {
// 运行程序(读取新的log文件)之前,清空旧文件(上次的log日志信息)
FileWrite.deleteAllLogFile();
FileWrite.deleteAllLogCopyFile();
startSearch();
}
// 定义集合,把搜索场景放到list集合
public static List<String> list = new ArrayList<>();
public static void startSearch() {
long startTime = System.currentTimeMillis();
System.out.println("===程序开始执行===");
// 拼接的传参参数为中文,需要把中文放到map
// 方法1:把待测试的query top排行前1000在odps查询出,存到本地,再通过接口拼接
String filePath = "/Users/lishan/Desktop/code/xx/qp.txt";
System.out.println(filePath);
String[] keywords = readTxt(filePath);
// System.out.println("strings:" + Arrays.toString(keywords));
// String keywords=record.getString("f1");
// 方法2:代码读取odps工具类,查询top1000的query,再通过接口拼接
// 见logOnlineReadODPS
// String[] keywords={"吴亦凡","杨幂","唐嫣"};
// String[] keywords = {"吴亦凡"};
int only1 = 0;
String query1 = "";
int totalCount = 0;
try {
for (int i = 0; i < keywords.length; i++) {
Map<String, String> query = new HashMap<>();
query.put("keyword", keywords[i]);
// 如果URL没有公共参数,则把 ?去掉;
// 业务接口传参增加cmd=4拿到引擎字段返回
String url_pre = "http://xx";
// 开始请求,域名、接口名==url+请求参数param(hashMap)
// String response = HTTPCommonMethod.doGet(url_pre, url_online, map, count);
System.out.println("第" + (i + 1) + "条数据==" + query);
String response = HTTPCommonMethod.doGet(url_pre, query, i);
JSONObject responseJson = JSONObject.parseObject(response);
int type = responseToParse(i, keywords[i], responseJson);
// 仅节目卡
if (type == 1) {
only1++;
query1 = query1 + keywords[i] + ",";
// 仅系列卡
}
// 打印接口返回的数据
// System.out.println("第【" + i + "】条日志,预发环境pre接口返回response为=======" + response);
totalCount = i + 1;
// System.out.println("每次循环的totalCount=="+totalCount);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("totalCount==" + totalCount);
float rate3 = (float) only1 / (float) totalCount;
System.out.println("------------------------------------------------------------------------------------------------");
System.out.println("------------------------------------------------------------------------------------------------");
System.out.println("only1---召回纠错词卡==【" + only1 + "】个,总数" + totalCount + "个,---比率为==【" + rate3 + "】---query1==【" + query1 + "】");
long endTime = System.currentTimeMillis();
System.out.println("===程序结束执行===");
long durationTime = endTime - startTime;
System.out.println("===程序耗时===【" + durationTime + "】毫秒");
// System.out.println("===程序耗时===【" + durationTime / 1000 / 60 + "】分钟");
}
/**
* @param count
* @param query
* @param response
* @return 1:获取第一个卡片的类型-标题 2: 未返回
*/
public static int responseToParse(int count, String query, JSONObject response) {
try {
// HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
boolean qpResult = false;
if (!response.isEmpty()) {
// 获取JSONObject
// 意图理解算法接口:是否纠错qcGrade。纠错词级别:1提示,2替换查询
// 业务接口:取第一个纠错词结果的卡片标题和卡片类型
// QP接口
JSONObject data0 = response.getJSONArray("nodes").getJSONObject(0).
getJSONArray("nodes").getJSONObject(0).
getJSONArray("nodes").getJSONObject(0).
getJSONObject("data");
// 业务接口
String object_title = data0.getJSONObject("action").getJSONObject("report").
getJSONObject("trackInfo").getString("object_title");
Integer docSource = data0.getInteger("docSource");
if (!object_title.isEmpty()) {
if (docSource == null) {
System.err.println("第【" + (count + 1) + "】条日志,原始keyword为==【" + query + "】," +
"docSource==【null】,第一个卡片标题object_title==【" + object_title + "】");
FileWrite.keywordLog(query);
FileWrite.videoTitleLog("null-" + object_title);
qpResult = true;
return 3;
}
if (docSource > 0) {
System.out.println("第【" + (count + 1) + "】条日志,原始keyword为==【" + query + "】," +
"docSource==【" + docSource + "】,第一个卡片标题object_title==【" + object_title + "】");
// 用于写入正常日志文件originLog,再做字段拆分,从而写入数据库,记录读取的log日志
// 全部数据
// FileWrite.originLog(FileWrite.rex + query + FileWrite.rex + qc + FileWrite.rex + docSource + "-" + object_title);
// 单个字段写入-原始query 纠错词qc 类型-第一个卡片的主标题
FileWrite.keywordLog(query);
FileWrite.videoTitleLog(docSource + "-" + object_title);
qpResult = true;
} else if (docSource <= 0) {
System.err.println("BUG!BUG!BUG!业务接口docSource枚举值错误!!!第【" + (count + 1) + "】条日志," +
"原始keyword为==【" + query + "】," +
"docSource==【" + docSource + "】,第一个卡片标题object_title==【" + object_title + "】");
}
// }
} else if (object_title == null) {
System.err.println("第【" + (count + 1) + "】条日志,原始keyword为==【" + query + "】," +
"docSource==【" + docSource + "】,第一个卡片标题object_title==【null】");
// 单个字段写入-原始query 纠错词qc 类型-第一个卡片的主标题
FileWrite.keywordLog(query);
FileWrite.videoTitleLog(docSource + "-null");
// System.err.println("第【" + count + "】条日志,原始keyword为==【" + query + "】,object_title为空");
qpResult = true;
return 3;
}
if (object_title == null && docSource == null) {
System.err.println("第【" + (count + 1) + "】条日志,原始keyword为==【" + query + "】," +
"docSource==【null】,第一个卡片标题object_title==【null】");
// 单个字段写入-原始query 纠错词qc 类型-第一个卡片的主标题
FileWrite.keywordLog(query);
FileWrite.videoTitleLog("null-null");
qpResult = true;
return 3;
}
if (qpResult) {
// 是纠错词卡片
return 1;
//
} else {
return 0;
}
} else {
System.err.println("第【" + count + "】条日志,原始keyword为==【" + query + "】,接口返回为空");
}
} catch (Exception e) {
e.printStackTrace();
}
return 2;
}
public static JSONObject jsonObject = new JSONObject();
}
2. 基于httpclient框架,解析请求
package com.alibaba.searchQP.utils;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.util.EncodingUtil;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class HTTPCommonMethod {
/**
* get 请求,只需将变动的参数传入params中即可
*
* @param url_pre
* @param params
* @return
*/
public static String requestURL;
public static String doGet(String url_pre, Map<String, String> params, int count) {
try {
Header header = new Header("Content-type", "application/json");
String response = "";
// HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。
// HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient。
// 使用HttpClient发送请求、接收响应
HttpClient httpClient = new HttpClient();
if (url_pre != null) {
// NameValuePair是简单名称值对节点类型。多用于Java像url_pre发送Post请求。在发送post请求时用该list来存放参数
// getParamsList(url_online, params, count);
// 预发环境value替换线上环境value
List<NameValuePair> qparams_pre = getParamsList_pre(params);
if (qparams_pre != null && qparams_pre.size() > 0) {
String formatParams = EncodingUtil.formUrlEncode(qparams_pre.toArray(new NameValuePair[qparams_pre.size()]),
"utf-8");
url_pre = url_pre.indexOf("?") < 0 ? url_pre + "?" + formatParams : url_pre + "&" + formatParams;
}
requestURL = url_pre;
System.out.println("第【" + (count+1) + "】条日志,预发环境pre imerge请求的url_pre==" + url_pre);
GetMethod getMethod = new GetMethod(url_pre);
getMethod.addRequestHeader(header);
/*if (null != headers) {
Iterator var8 = headers.entrySet().iterator();
while (var8.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry)var8.next();
getMethod.addRequestHeader((String)entry.getKey(), (String)entry.getValue());
}
}*/
//System.out.println(getMethod.getRequestHeader("User-Agent"));
int statusCode = httpClient.executeMethod(getMethod);
// 如果请求失败则打印出失败的返回码
if (statusCode != 200) {
System.out.println("第" + statusCode + "【" + count + "】条日志,预发环境请求出错,错误码为=======" + statusCode);
return response;
}
response = new String(getMethod.getResponseBody(), "utf-8");
}
return response;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 参数格式化
private static List<NameValuePair> getParamsList_pre(Map<String, String> paramsMap) {
if (paramsMap != null && paramsMap.size() != 0) {
List<NameValuePair> params = new ArrayList();
Iterator var2 = paramsMap.entrySet().iterator();
while (var2.hasNext()) {
Map.Entry<String, String> map = (Map.Entry) var2.next();
// 预发环境最新版本日志回放,请求参数打开以下if else,注释掉最后一行
// 参数格式化,commons-httpclient自带的方法NameValuePair会自动将==转为=,还有特殊符号格式化
// NameValuePair是简单名称值对节点类型。多用于Java像url_pre发送Post请求。在发送post请求时用该list来存放参数
params.add(new NameValuePair(map.getKey() + "", map.getValue() + ""));
// params.add(new NameValuePair(map.getKey() + "", map.getValue() + ""));
}
return params;
} else {
return null;
}
}
}
3. 文件读取解析
package com.alibaba.searchQP.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
public class ReadFiles {
public static String[] readTxt(String filePath) {
StringBuilder builder = new StringBuilder();
try {
File file = new File(filePath);
if (file.isFile() && file.exists()) {
InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "utf-8");
BufferedReader br = new BufferedReader(isr);
String lineTxt = null;
int num = 0;
long time1 = System.currentTimeMillis();
while ((lineTxt = br.readLine()) != null) {
System.out.println(lineTxt);
builder.append(lineTxt);
builder.append(",");
num++;
// System.out.println("总共" + num + "条数据!");
}
//System.out.println("总共"+num+"条数据!");
long time2 = System.currentTimeMillis();
long time = time1 - time2;
// System.out.println("共花费" + time + "秒");
br.close();
} else {
System.out.println("文件不存在!");
}
} catch (Exception e) {
System.out.println("文件读取错误!");
}
String[] strings = builder.toString().split(",");
return strings;
}
public static void main(String[] args) {
String filePath = "/Users/lishan/Desktop/xx.txt";
System.out.println(filePath);
String[] strings = readTxt(filePath);
System.out.println("strings:"+Arrays.toString(strings));
}
}
4. 测试结果:按Excel写入(时间原因,不支持直接插入Excel,需要手动拷贝)
召回纠错词卡==【10】个,总数10个,---比率为==【1.0】---query1==【七小英雄,因为爱情有多美吻,少主慢行,大罐蓝,三叉记,乡材爱情8,那一场呼唤而过的青春,国产电视剧赵丽颕主演的楚乔传,神战权利之眼,干物埋小妹,】
===程序结束执行===
===程序耗时===【4194】毫秒
5. 优化脚本,将控制台输出的日志写入文件。每次运行程序之前删除历史日志文件
package com.alibaba.searchQP.utils;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class FileWrite {
// 定义path全局路径 原始日志存放路径pathOrigin 错误日志存放路径pathError
public static String pathAll = "/Users/lishan/Desktop/xx/HistoryLog";
public static String rex = " ";
public static void main(String[] args) {
String content = "a log will be write in file";
System.out.println(content + "" + "");
originLog(content + "" + "");
errorLog(content + "" + "");
}
public static void originLog(String content) {
try {
// File.separator代表系统目录中的间隔符,说白了就是斜线 '\',不过有时候需要双线,有时候是单线,用这个静态变量就解决兼容问题了。
File file = new File(pathAll + File.separator + "origin_log.txt");
if (!file.exists()) {
file.createNewFile();
}
FileWriter fileWriter = new FileWriter(file.getAbsoluteFile(), true);
BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write(content + "\r\n");
bw.close();
System.out.println("finish");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void keywordLog(String content) {
try {
// File.separator代表系统目录中的间隔符,说白了就是斜线 '\',不过有时候需要双线,有时候是单线,用这个静态变量就解决兼容问题了。
File file = new File(pathAll + File.separator + "keyword_log.txt");
if (!file.exists()) {
file.createNewFile();
}
FileWriter fileWriter = new FileWriter(file.getAbsoluteFile(), true);
BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write(content + "\r\n");
bw.close();
System.out.println("finish");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void qcLog(String content) {
try {
// File.separator代表系统目录中的间隔符,说白了就是斜线 '\',不过有时候需要双线,有时候是单线,用这个静态变量就解决兼容问题了。
File file = new File(pathAll + File.separator + "qc_log.txt");
if (!file.exists()) {
file.createNewFile();
}
FileWriter fileWriter = new FileWriter(file.getAbsoluteFile(), true);
BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write(content + "\r\n");
bw.close();
System.out.println("finish");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void videoTitleLog(String content) {
try {
// File.separator代表系统目录中的间隔符,说白了就是斜线 '\',不过有时候需要双线,有时候是单线,用这个静态变量就解决兼容问题了。
File file = new File(pathAll + File.separator + "videoTitle_log.txt");
if (!file.exists()) {
file.createNewFile();
}
FileWriter fileWriter = new FileWriter(file.getAbsoluteFile(), true);
BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write(content + "\r\n");
bw.close();
System.out.println("finish");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void errorLog(String content) {
try {
// File.separator代表系统目录中的间隔符,说白了就是斜线 '\',不过有时候需要双线,有时候是单线,用这个静态变量就解决兼容问题了。
File file = new File(pathAll + File.separator + "error_log.txt");
if (!file.exists()) {
file.createNewFile();
}
FileWriter fileWriter = new FileWriter(file.getAbsoluteFile(), true);
BufferedWriter bw = new BufferedWriter(fileWriter);
bw.write("\r\n" + content);
bw.close();
System.out.println("finish");
} catch (IOException e) {
e.printStackTrace();
}
}
public static String getErrorLog(String currentTimeMillis, String clientTimeStamp, int count, String printMsg) {
String errorLog = "";
errorLog = currentTimeMillis + FileWrite.rex + clientTimeStamp + FileWrite.rex + count + FileWrite.rex + printMsg;
return errorLog;
}
// 错误日志写入cpw_log_error数据表,暂无clientTimeStamp的日志
public static String getErrorLogNoclientTimeStamp(String currentTimeMillis, int count, String printMsg, int errorLevel) {
String errorLogNoclientTimeStamp = "";
// errorLogNoclientTimeStamp = currentTimeMillis + FileWrite.rex + clientTimeStamp + FileWrite.rex + count + FileWrite.rex +printMsg;
errorLogNoclientTimeStamp = currentTimeMillis + FileWrite.rex + "暂无clientTimeStamp" + FileWrite.rex + count + FileWrite.rex + printMsg + FileWrite.rex + errorLevel;
return errorLogNoclientTimeStamp;
}
// 错误日志写入cpw_log_error数据表,有clientTimeStamp的日志
public static String getErrorLogHasclientTimeStamp(String currentTimeMillis, String clientTimeStamp, int count, String printMsg, int errorLevel) {
String getErrorLogHasclientTimeStamp = "";
// errorLogNoclientTimeStamp = currentTimeMillis + FileWrite.rex + clientTimeStamp + FileWrite.rex + count + FileWrite.rex +printMsg;
getErrorLogHasclientTimeStamp = currentTimeMillis + FileWrite.rex + clientTimeStamp + FileWrite.rex + count + FileWrite.rex + printMsg + FileWrite.rex + errorLevel;
return getErrorLogHasclientTimeStamp;
}
// 删除原始origin_log.txt和error_log.txt,防止日志重复写入
public static void deleteAllLogFile() {
try {
// File.separator代表系统目录中的间隔符,说白了就是斜线 '\',不过有时候需要双线,有时候是单线,用这个静态变量就解决兼容问题了。
// 删除原始keyword日志
File fileKeyword = new File(pathAll + File.separator + "keyword_log.txt");
if (fileKeyword.exists()) {
fileKeyword.delete();
}
System.out.println("原始keyword日志已删除。delete keyword_log.txt file success");
// 删除纠错词qc错误日志
File fileQc = new File(pathAll + File.separator + "qc_log.txt");
if (fileQc.exists()) {
fileQc.delete();
}
System.out.println("纠错词日志已删除。delete qc_log.txt file success");
// 删除原始keyword日志
File fileVideoTitle = new File(pathAll + File.separator + "videoTitle_log.txt");
if (fileVideoTitle.exists()) {
fileVideoTitle.delete();
}
System.out.println("第一个卡片主标题日志已删除。delete videoTitle_log.txt file success");
} catch (Exception e) {
e.printStackTrace();
}
}
// 删除原始origin_log.txt,防止接口重复请求导致日志重复写入
public static void deleteOriginLogFirstRunFile() {
try {
// File.separator代表系统目录中的间隔符,说白了就是斜线 '\',不过有时候需要双线,有时候是单线,用这个静态变量就解决兼容问题了。
// 删除原始日志
File fileOrigin = new File(pathAll + File.separator + "origin_log.txt");
if (fileOrigin.exists()) {
fileOrigin.delete();
}
System.out.println("原始日志已删除。delete origin_log.txt file success");
} catch (Exception e) {
e.printStackTrace();
}
}
// 删除原始error_log.txt,防止接口重复请求导致日志重复写入
public static void deleteErrorLogFirstRunFile() {
try {
// File.separator代表系统目录中的间隔符,说白了就是斜线 '\',不过有时候需要双线,有时候是单线,用这个静态变量就解决兼容问题了。
// 删除错误日志
File fileError = new File(pathAll + File.separator + "error_log.txt");
if (fileError.exists()) {
fileError.delete();
}
System.out.println("错误参数断言日志已删除。delete error_log.txt file success");
} catch (Exception e) {
e.printStackTrace();
}
}
// 删除副本origin_log_copy.txt和error_log_copy.txt
public static void deleteAllLogCopyFile() {
try {
// 删除原始日志副本
// File.separator代表系统目录中的间隔符,说白了就是斜线 '\',不过有时候需要双线,有时候是单线,用这个静态变量就解决兼容问题了。
File fileOrigin = new File(pathAll + File.separator + "origin_log_copy.txt");
if (fileOrigin.exists()) {
fileOrigin.delete();
}
System.out.println("原始日志副本已删除。delete origin_log_copy.txt file ");
// 删除错误日志副本
File fileError = new File(pathAll + File.separator + "error_log_copy.txt");
if (fileError.exists()) {
fileError.delete();
}
System.out.println("错误参数断言日志副本已删除。delete error_log_copy file ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
再将txt文件的日志(需求所要的列复制粘贴到Excel)
待续