Elasticsearch 실전(5): Springboot는 Elasticsearch 전자상거래 플랫폼에서 로그 매장 지점 및 인기 단어 검색을 구현합니다.

시리즈 기사 색인

Elasticsearch 실전(1) : Springboot는 Elasticsearch 통합 검색 기능 구현
Elasticsearch 실전(2) : Springboot는 Elasticsearch 자동 한자 및 병음완성 구현, Springboot는 자동 맞춤법 ​​오류 수정 구현
Elasticsearch 실전(3) : Springboot는 Elasticsearch 검색 추천 구현
Elasticsearch 실전 전투 (4) : Springboot는 Elasticsearch 인덱스 집계 및 드릴다운 분석을 구현합니다.
Elasticsearch 실제 전투 (5): Springboot는 Elasticsearch 전자상거래 플랫폼 로그 임베딩 포인트 및 인기 단어 검색을 구현합니다.

1. 인기 검색어 추출

1. 핫 검색어 분석 흐름도

여기에 이미지 설명을 삽입하세요

2. 매장지점 로그

Log4j2 통합

log4j2는 다른 로그 시스템에 비해 데이터 손실 사례가 적고, Disruptor 기술은 멀티 스레드 환경에서 로그백보다 ​​10배 이상 높은 성능을 가지며, jdk1.5의 동시성 기능을 사용하면 데이터 손실이 줄어듭니다. 교착상태;

(1) 로그백의 기본 통합을 제외합니다.

Spring Cloud는 기본적으로 logback을 통합하기 때문에 pom.xml 파일에서 logback 통합을 먼저 제외해야 한다.

<!--排除logback的默认集成 Spring Cloud 默认集成了logback-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<exclusions>
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-logging</artifactId>
		</exclusion>
	</exclusions>
</dependency>

(2) log4j2 시작 종속성 도입

<!-- 引入log4j2起步依赖-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!-- log4j2依赖环形队列-->
<dependency>
	<groupId>com.lmax</groupId>
	<artifactId>disruptor</artifactId>
	<version>3.4.2</version>
</dependency>

(3) 구성 파일 설정

파일 이름을 사용자 정의하는 경우 application.yml에서 구성해야 합니다.
구성을 수정하려면 Nacos를 입력하세요.

logging:
	config: classpath:log4j2-dev.xml

(4) 구성 파일 템플릿

<Configuration>
	<Appenders>
		<Socket name="Socket" host="172.17.0.225" port="4567">
			<JsonLayout compact="true" eventEol="true" />
		</Socket>
	</Appenders>
	<Loggers>
		<Root level="info">
			<AppenderRef ref="Socket"/>
		</Root>
	</Loggers>
</Configuration>

구성 파일에서 볼 수 있듯이 여기서는 Socket Appender를 사용하여 Logstash에 로그 인쇄 정보를 보냅니다.
Logstash에 로그를 출력하려면 Socket Appender를 다음 Logger로 구성해야 합니다.
또한, 여기서 호스트는 Logstash 서버가 배포된 주소이며, 포트 번호는 Logstash에서 구성한 것과 일치해야 합니다.

(5) 로그 매설지점

private void getClientConditions(CommonEntity commonEntity, SearchSourceBuilder searchSourceBuilder) {
    
    
	//循环前端的查询条件
	for (Map.Entry<String, Object> m : commonEntity.getMap().entrySet()) {
    
    
		if (StringUtils.isNotEmpty(m.getKey()) && m.getValue() != null) {
    
    
			String key = m.getKey();
			String value = String.valueOf(m.getValue());
			//构造请求体中“query”:{}部分的内容 ,QueryBuilders静态工厂类,方便构造
			queryBuilder
			searchSourceBuilder.query(QueryBuilders.matchQuery(key, value));
			logger.info("search for the keyword:" + value);
		}
	}
}

(6) 인덱스 생성

다음 인덱스는 사용자가 입력한 키워드를 저장하고, 최종적으로 인덱스 데이터를 Aggregation을 통해 처리하여 최종적으로 코퍼스에 넣는다.

PUT es-log/
{
    
    
    "mappings": {
    
    
        "properties": {
    
    
            "@timestamp": {
    
    
                "type": "date"
            },
            "host": {
    
    
                "type": "text"
            },
            "searchkey": {
    
    
                "type": "keyword"
            },
            "port": {
    
    
                "type": "long"
            },
            "loggerName": {
    
    
                "type": "text"
            }
        }
    }
}

3. 데이터 저장(logstash)

(1) Logstash.conf 구성

Logstash를 연결하는 방법에는 두 가지가 있습니다.
(1) 하나는 소켓 연결이고
(2) 다른 하나는 gelf 연결입니다.

input {
    
    
    tcp {
    
    
        port => 4567
        codec => json
    }
}

filter {
    
    
#如果不包含search for the keyword则删除
    if [message] =~  "^(?!.*?search for the keyword).*$" {
    
    
        drop {
    
    }
  }
     mutate{
    
    
#移除不需要的列
        remove_field => ["threadPriority","endOfBatch","level","@version","threadId","tags","loggerFqcn","thread","instant"]
#对原始数据按照:分组,取分组后的搜索关键字
  split=>["message",":"]
                add_field => {
    
    
                        "searchkey" => "%{[message][1]}"
                }
#上面新增了searchkey新列,移除老的message列
 remove_field => ["message"]
           }
 }

# 输出部分
output {
    
    
    elasticsearch {
    
    
        # elasticsearch索引名
        index => "es-log"
        # elasticsearch的ip和端口号
        hosts => ["172.188.0.88:9200","172.188.0.89:9201","172.188.0.90:9202"]
    }
    stdout {
    
    
        codec => json_lines
    }
}

Logstash를 다시 시작하여 포트 4567을 외부에 노출합니다.

docker run --name logstash   -p 4567:4567 -v /usr/local/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml   -v /usr/local/logstash/config/conf.d/:/usr/share/logstash/pipeline/   -v /usr/local/logstash/config/jars/mysql-connector-java-5.1.48.jar:/usr/share/logstash/logstash-core/lib/jars/mysql-connector-java-5.1.48.jar       --net czbkNetwork --ip 172.188.0.77 --privileged=true  -d  c2c1ac6b995b

(2) 데이터가 있는지 쿼리

GET es-log/_search
{
    
    
	"from": 0,
	"size": 200,
	"query": {
    
    
		"match_all": {
    
    }
	}
}

返回:
{
    
    
	"_index" : "es-log",
	"_type" : "_doc",
	"_id" : "s4sdPHEBfG2xXcKw2Qsg",
	"_score" : 1.0,
	"_source" : {
    
    
		"searchkey" : "华为全面屏",
		"port" : 51140,
		"@timestamp" : "2023-04-02T18:18:41.085Z",
		"host" : "192.168.23.1",
		"loggerName" :
		"com.service.impl.ElasticsearchDocumentServiceImpl"
	}
}

(3) API 전문 검색 실행

매개변수:

{
    
    
	"pageNumber": 1,
	"pageSize": 3,
	"indexName": "product_list_info",
	"highlight": "productname",
	"map": {
    
    
		"productname": "小米"
	}
}

2. 핫서치 OpenAPI

1. 중합

es-log 인덱스에서 문서 데이터를 획득 및 그룹화하고, 인기 검색어의 빈도를 계산하고, 빈도에 따라 유효한 데이터를 획득합니다.

2. DSL 구현

field: 쿼리 열, 키워드 유형
min_doc_count:
1보다 큰 인기 순서 time: 인기 순서
size: 처음 몇 개 제거
per_count: "사용자 정의 집계 이름

POST es-log/_search?size=0
{
    
    
    "aggs": {
    
    
        "result": {
    
    
            "terms": {
    
    
                "field": "searchkey",
                "min_doc_count": 5,
                "size": 2,
                "order": {
    
    
                    "_count": "desc"
                }
            }
        }
    }
}

结果:
{
    
    
    "took": 13,
    "timed_out": false,
    "_shards": {
    
    
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
    
    
        "total": {
    
    
            "value": 40,
            "relation": "eq"
        },
        "max_score": null,
        "hits": []
    },
    "aggregations": {
    
    
        "per_count": {
    
    
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 12,
            "buckets": [
                {
    
    
                    "key": "阿迪达斯外套",
                    "doc_count": 14
                },
                {
    
    
                    "key": "华为",
                    "doc_count": 8
                }
            ]
        }
    }
}

3. OpenAPI 쿼리 매개변수 설계

/*
 * @Description: 获取搜索热词
 * @Method: hotwords
 * @Param: [commonEntity]
 * @Update:
 * @since: 1.0.0
 * @Return: java.util.List<java.lang.String>
 *
 */
public Map<String, Long> hotwords(CommonEntity commonEntity) throws Exception {
    
    
    //定义返回数据
    Map<String, Long> map = new LinkedHashMap<String, Long>();
    //执行查询
    SearchResponse result = getSearchResponse(commonEntity);
    //这里的自定义的分组别名(get里面)key当一个的时候为动态获取
    Terms packageAgg = result.getAggregations().get(result.getAggregations().getAsMap().entrySet().iterator().next().getKey());
    for (Terms.Bucket entry : packageAgg.getBuckets()) {
    
    
        if (entry.getKey() != null) {
    
    
            // key为分组的字段
            String key = entry.getKey().toString();
            // count为每组的条数
            Long count = entry.getDocCount();
            map.put(key, count);
        }
    }

    return map;
}
/*
 * @Description: 查询公共调用,参数模板化
 * @Method: getSearchResponse
 * @Param: [commonEntity]
 * @Update:
 * @since: 1.0.0
 * @Return: org.elasticsearch.action.search.SearchResponse
 *
 */
private SearchResponse getSearchResponse(CommonEntity commonEntity) throws Exception {
    
    
    //定义查询请求
    SearchRequest searchRequest = new SearchRequest();
    //指定去哪个索引查询
    searchRequest.indices(commonEntity.getIndexName());
    //构建资源查询构建器,主要用于拼接查询条件
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    //将前端的dsl查询转化为XContentParser
    XContentParser parser = SearchTools.getXContentParser(commonEntity);
    //将parser解析成功查询API
    sourceBuilder.parseXContent(parser);
    //将sourceBuilder赋给searchRequest
    searchRequest.source(sourceBuilder);
    //执行查询
    SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
    return response;
}

핫워드 메소드 매개변수 호출:

{
    
    
    "indexName": "es-log",
    "map": {
    
    
        "aggs": {
    
    
            "per_count": {
    
    
                "terms": {
    
    
                    "field": "searchkey",
                    "min_doc_count": 5,
                    "size": 2,
                    "order": {
    
    
                        "_count": "desc"
                    }
                }
            }
        }
    }
}

필드는 검색할 열을 나타냅니다
. min_doc_count: 문서에 핫 검색어가 나타나는 횟수입니다.
크기는 데이터를 얼마나 꺼내는지 나타냅니다. 순서
는 정렬(오름차순 또는 내림차순)을 나타냅니다.

Guess you like

Origin blog.csdn.net/A_art_xiang/article/details/132708387