Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,38 @@ public void upsert(
startHnswBuildIfNecessary(collectionId, vectorSize);
}

public void deletePoints(
String collectionName,
List<Long> pointIds
) throws Exception {
EzyVectorCollectionVectorSizeResult collection =
getVectorSizeResultEntityByNameOrThrow(
collectionName
);
long collectionId = collection.getId();
synchronized (writeLock) {
List<EzyVectorCollectionPoint> points =
new ArrayList<>(pointIds.size());
List<Long> slotIds = new ArrayList<>(pointIds.size());
for (Long pointId : pointIds) {
EzyVectorCollectionPoint point = collectionPointRepository
.findByCollectionIdAndPointId(
collectionId,
pointId
);
if (point != null) {
points.add(point);
slotIds.add(point.getId());
}
}
newVectorFileStorage().deleteAll(collectionId, slotIds);
deleteFromHnswIndex(collectionId, points);
for (EzyVectorCollectionPoint point : points) {
collectionPointRepository.delete(point.getId());
}
}
}

public List<EzyVectorSearchResultModel> search(
String collectionName,
float[] vector,
Expand Down Expand Up @@ -466,6 +498,24 @@ private void updateHnswIndex(
}
}

private void deleteFromHnswIndex(
long collectionId,
List<EzyVectorCollectionPoint> points
) throws Exception {
HnswIndex index = hnswIndexByCollectionId.get(collectionId);
if (index == null) {
return;
}
for (EzyVectorCollectionPoint point : points) {
index.remove(point.getPointId());
}
if (readyHnswCollectionIds.contains(collectionId)) {
index.save(
newVectorFileStorage().getHnswPath(collectionId)
);
}
}

private void buildHnswIndex(long collectionId) {
try {
HnswIndex index = hnswIndexByCollectionId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,37 @@ public void upsertAll(
}
}

public void deleteAll(
long collectionId,
List<Long> slotIds
) throws IOException {
if (slotIds.isEmpty()) {
return;
}
Path pointIdsFile = getSegmentDir(collectionId)
.resolve(POINT_IDS_FILE);
if (!Files.isRegularFile(pointIdsFile)) {
return;
}
try (
FileChannel pointIdChannel = FileChannel.open(
pointIdsFile,
StandardOpenOption.WRITE
)
) {
for (Long slotId : slotIds) {
validateSlotId(slotId);
long pointIdOffset = (slotId - 1L) * Long.BYTES;
writeFully(
pointIdChannel,
toLongBuffer(0L),
pointIdOffset
);
}
pointIdChannel.force(true);
}
}

public List<SearchResult> search(
long collectionId,
long vectorSize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.youngmonkeys.ezyvector.web.controller.service.WebEzyVectorSearchControllerService;
import org.youngmonkeys.ezyvector.web.converter.WebEzyVectorRequestToModelConverter;
import org.youngmonkeys.ezyvector.web.request.WebCreateVectorCollectionRequest;
import org.youngmonkeys.ezyvector.web.request.WebDeleteVectorPointsRequest;
import org.youngmonkeys.ezyvector.web.request.WebEzyVectorSearchRequest;
import org.youngmonkeys.ezyvector.web.request.WebUpsertVectorPointsRequest;
import org.youngmonkeys.ezyvector.web.response.WebCreateVectorCollectionResponse;
Expand Down Expand Up @@ -105,6 +106,20 @@ public WebUpsertVectorPointsResponse collectionNamePointsPut(
);
}

@DoPost("/{collectionName}/points/delete")
public WebUpsertVectorPointsResponse collectionNamePointsDeletePost(
RequestArguments arguments,
@PathVariable String collectionName,
@RequestBody WebDeleteVectorPointsRequest request
) throws Exception {
vectorCollectionValidator.validateAuthentication(arguments);
vectorPointsValidator.validate(request);
return vectorPointsControllerService.deletePoints(
collectionName,
request
);
}

@DoPost("/{collectionName}/points/search")
public WebEzyVectorSearchResponse collectionNamePointsSearchPost(
RequestArguments arguments,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import lombok.AllArgsConstructor;
import org.youngmonkeys.ezyvector.web.controller.decorator.WebEzyVectorPointsModelDecorator;
import org.youngmonkeys.ezyvector.web.converter.WebEzyVectorRequestToModelConverter;
import org.youngmonkeys.ezyvector.web.request.WebDeleteVectorPointsRequest;
import org.youngmonkeys.ezyvector.web.request.WebUpsertVectorPointsRequest;
import org.youngmonkeys.ezyvector.web.response.WebUpsertVectorPointsResponse;
import org.youngmonkeys.ezyvector.web.service.WebEzyVectorService;
Expand All @@ -43,4 +44,16 @@ public WebUpsertVectorPointsResponse upsertPoints(
return vectorPointsModelDecorator
.decorateToUpsertVectorPointsResponse();
}

public WebUpsertVectorPointsResponse deletePoints(
String collectionName,
WebDeleteVectorPointsRequest request
) throws Exception {
vectorService.deletePoints(
collectionName,
request.getPoints()
);
return vectorPointsModelDecorator
.decorateToUpsertVectorPointsResponse();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2026 youngmonkeys.org
*
* Licensed under the ezyplatform, Version 1.0.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://youngmonkeys.org/licenses/ezyplatform-1.0.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.youngmonkeys.ezyvector.web.request;

import lombok.Getter;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
public class WebDeleteVectorPointsRequest {
private List<Long> points;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.tvd12.ezyfox.bean.annotation.EzySingleton;
import com.tvd12.ezyhttp.core.exception.HttpBadRequestException;
import org.youngmonkeys.ezyvector.web.request.WebDeleteVectorPointsRequest;
import org.youngmonkeys.ezyvector.web.request.WebUpsertVectorPointsRequest;

import java.util.HashMap;
Expand All @@ -27,6 +28,26 @@
@EzySingleton
public class WebEzyVectorPointsValidator {

public void validate(
WebDeleteVectorPointsRequest request
) {
Map<String, String> errors = new HashMap<>();
List<Long> points = request.getPoints();
if (points == null || points.isEmpty()) {
errors.put("points", "required");
} else {
for (int i = 0; i < points.size(); ++i) {
Long pointId = points.get(i);
if (pointId == null || pointId <= 0L) {
errors.put("points[" + i + "]", "invalid");
}
}
}
if (!errors.isEmpty()) {
throw new HttpBadRequestException(errors);
}
}

public void validate(
WebUpsertVectorPointsRequest request
) {
Expand Down
Loading