Привет, у меня есть Java-бэкэнд с пружинной загрузкой и угловой интерфейс.У меня есть сценарий, в котором пользователь может нажать на кнопку загрузить CSV в моем угловом интерфейсе, и он сделает вызов API Rest.Остальные вызовы API обрабатываются ресурсным методом, он запрашивает эластичный поиск, конвертирует документы в список объектов, а затем мы возвращаем файл пользователю.Он работает нормально, однако, если я скачаю огромный набор результатов, он выдаст кучу, превышающую исключение, и к тому же он очень медленный.Я попробовал пару стратегий, чтобы оптимизировать это, но я не преуспел в этом.поэтому, пожалуйста, помогите, если вы найдете, какие изменения / оптимизацию я могу внести в мой код, чтобы улучшить производительность и проблемы с памятью при загрузке файла.Я отправляю код, как показано ниже.
MessageHistoryReportingResource.java
@RestController
@RequestMapping("/api")
public class MessageHistoryReportingResource {
@GetMapping("/message-history/csv")
@Timed
@Secured({ AuthoritiesConstants.CAMPAIGN_MANAGER, AuthoritiesConstants.TEAM_MEMBER,AuthoritiesConstants.ACCOUNT_ADMIN,
AuthoritiesConstants.GLOBAL_ADMIN })
public ResponseEntity<MessageHistoryCSVWrapper> getMessageHistoriesCSV(MessageHistoryFilterRequest messageHistoryFilterRequest)
throws IOException {
log.debug("REST request to download message histories: {}", messageHistoryFilterRequest);
byte[] bytes =
CsvUtil.createByteArray(this.messageHistoryReportingService.findCSV(messageHistoryFilterRequest));
return ResponseEntity.ok().body(new MessageHistoryCSVWrapper(new String(bytes)));
}
}
MessageHistoryReportingServiceImpl
@Service
public class MessageHistoryReportingServiceImpl implements MessageHistoryReportingService {
@Override
public List<String> findCSV(MessageHistoryFilterRequest messageHistoryFilterRequest) {
List<MessageHistory> messageHistories = messageHistoryReportingRepository
.findAllCSV(messageHistoryFilterRequest);
List<String> csvLines = new ArrayList<>();
String header = String.join(",", csvHeader);
csvLines.add(header);
List<String> msgHistoriesAsLines = messageHistories.stream().map(this::convertMessageHistoryAsCSV)
.collect(Collectors.toList());
csvLines.addAll(msgHistoriesAsLines);
return csvLines;
}
private String convertMessageHistoryAsCSV(MessageHistory msgHistory) {
return String.join(",", msgHistory.getTimeStamp().toString(), msgHistory.getRecipient(), msgHistory.getSender(),
msgHistory.getCampaignName(), msgHistory.getFlightName(), msgHistory.getStatus(), msgHistory.getError(),
msgHistory.getMessageText());
}
}
MessageHistoryReportingRepository
@Repository
public class MessageHistoryReportingRepository {
private RestHighLevelClient elasticSearchClient;
public List<MessageHistory> findAllCSV(MessageHistoryFilterRequest messageHistoryFilterRequest) {
SearchRequestBuilder searchRequestBuilder = new SearchRequestBuilder(ELASTIC_SEARCH_INDEX);
SearchRequest searchRequest = searchRequestBuilder
.timeout(300, TimeUnit.SECONDS)
.range(messageHistoryFilterRequest.getStartDate(), messageHistoryFilterRequest.getEndDate())
.msisdn(messageHistoryFilterRequest.getMsisdn()).accountId(messageHistoryFilterRequest.getAccountId())
.campaignId(messageHistoryFilterRequest.getCampaignId())
.flightId(messageHistoryFilterRequest.getFlightId())
.cdrStatus(messageHistoryFilterRequest.getCdrStatus())
.inventoryCode(messageHistoryFilterRequest.getInventoryCode()).sort()
.fetchSourceContext(true, INCLUDES, EXCLUDES).scroll(TimeValue.timeValueMinutes(1L)).build();
SearchResponse searchResponse = null;
List<MessageHistory> messageHistories = null;
try {
searchResponse = elasticSearchClient.search(searchRequest, RequestOptions.DEFAULT);
String scrollId = searchResponse.getScrollId();
SearchHit[] searchHits = searchResponse.getHits().getHits();
Collection<SearchHit> searchHitCollection = new LinkedList<SearchHit>();
while (searchHits != null && searchHits.length > 0) {
searchHitCollection.addAll(Arrays.asList(searchHits));
SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
scrollRequest.scroll(new Scroll(TimeValue.timeValueMinutes(1l)));
searchResponse = elasticSearchClient.scroll(scrollRequest, RequestOptions.DEFAULT);
scrollId = searchResponse.getScrollId();
searchHits = searchResponse.getHits().getHits();
}
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
clearScrollRequest.addScrollId(scrollId);
ClearScrollResponse clearScrollResponse = elasticSearchClient.clearScroll(clearScrollRequest,
RequestOptions.DEFAULT);
boolean succeeded = clearScrollResponse.isSucceeded();
messageHistories = searchHitCollection.stream().map(this::translate).collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return messageHistories;
}
private MessageHistory translate(SearchHit searchHit) {
try {
return objectMapper.readValue(searchHit.getSourceAsString(), MessageHistory.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
так что просто, чтобы объяснить немного подробнее.в моем MessageHistoryReportingRepository метод findAllCSV запрашивает эластичный поиск, использует прокрутку, продолжает извлекать записи и помещает его в список Collection searchHitCollection.затем я перевожу коллекцию, используя translate (SearchHit searchHit), который используется в потоке api searchHitCollection.stream (). map (this :: translate) .collect (Collectors.toList ());.
, затемСписок, возвращаемый из findAllCSV, возвращается в MessageHistoryReportingServiceImpl # findCSV, где он перебирает список объектов и преобразует каждый объект в строку.затем в моем MessageHistoryResource я буду вызывать CSVUtil.createByArray, чтобы преобразовать его в byte [] для возврата в пользовательский интерфейс.
CsvUtil
открытый класс CsvUtil {
private static final Logger log = LoggerFactory.getLogger(CsvUtil.class);
/**
* The List of recipients is converted to a byte array formatted for a csv.
* A recipient per line
*
* @param csvRows list of contact list recipients
* @return The byte array of the recipients
*/
public static byte[] createByteArray(List<String> csvRows) {
byte[] listToBytes = new byte[0];
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream))) {
csvRows.forEach(row -> {
try {
bw.write(row);
bw.write("\n");
} catch (IOException e) {
log.error("Error writing recipients to outputstream ", e);
}
});
bw.close();
listToBytes = outputStream.toByteArray();
} catch (IOException e) {
log.error("Error writing recipients to outputstream ", e);
}
return listToBytes;
}
}
MessageHistory.java
public class MessageHistory {
@JsonProperty("inventory")
private String inventory;
@JsonProperty("msg_text")
private String messageText;
@JsonProperty("status")
private String status;
@JsonProperty("@timestamp")
private Instant timeStamp;
@JsonProperty("o_error")
private String error;
@JsonProperty("flight_id")
private UUID flightId;
@JsonProperty("recipient")
private String recipient;
@JsonProperty("account_id")
private UUID accountId;
@JsonProperty("sender")
private String sender;
@JsonProperty("campaign_id")
private UUID campaignId;
@JsonProperty("nof_segments")
private Integer segmentCount;
@JsonProperty("@version")
private Integer version;
@JsonProperty("submission_ts")
@JsonFormat(shape = JsonFormat.Shape.NUMBER_INT)
private Instant submissionTimeStamp;
@JsonProperty("delivery_ts")
@JsonFormat(shape = JsonFormat.Shape.NUMBER_INT)
private Instant deliveryTimeStamp;
@JsonProperty("campaign_name")
private String campaignName;
@JsonProperty("flight_name")
private String flightName;
public String getInventory() {
return inventory;
}
public void setInventory(String inventory) {
this.inventory = inventory;
}
public String getMessageText() {
return messageText;
}
public void setMessageText(String messageText) {
this.messageText = messageText;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Instant getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(Instant timeStamp) {
this.timeStamp = timeStamp;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public UUID getFlightId() {
return flightId;
}
public void setFlightId(UUID flightId) {
this.flightId = flightId;
}
public String getRecipient() {
return recipient;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public UUID getAccountId() {
return accountId;
}
public void setAccountId(UUID accountId) {
this.accountId = accountId;
}
public UUID getCampaignId() {
return campaignId;
}
public void setCampaignId(UUID campaignId) {
this.campaignId = campaignId;
}
public Integer getSegmentCount() {
return segmentCount;
}
public void setSegmentCount(Integer segmentCount) {
this.segmentCount = segmentCount;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
public Instant getSubmissionTimeStamp() {
return submissionTimeStamp;
}
public void setSubmissionTimeStamp(Instant submissionTimeStamp) {
this.submissionTimeStamp = submissionTimeStamp;
}
public Instant getDeliveryTimeStamp() {
return deliveryTimeStamp;
}
public void setDeliveryTimeStamp(Instant deliveryTimeStamp) {
this.deliveryTimeStamp = deliveryTimeStamp;
}
public String getCampaignName() {
return campaignName;
}
public void setCampaignName(String campaignName) {
this.campaignName = campaignName;
}
public String getFlightName() {
return flightName;
}
public void setFlightName(String flightName) {
this.flightName = flightName;
}
}
очень ценю вашу помощь, если у вас есть некоторые предложения в коде для повышения производительности, улучшения оптимизации и проблемы с памятью.
спасибо