github.com/weaviate/weaviate@v1.24.6/entities/moduletools/vectorizable_props_comparator.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package moduletools
    13  
    14  import (
    15  	"sort"
    16  
    17  	"github.com/weaviate/weaviate/entities/models"
    18  	"github.com/weaviate/weaviate/entities/schema"
    19  )
    20  
    21  type PropsComparatorFactory func() (VectorizablePropsComparator, error)
    22  
    23  type VectorizablePropsComparator interface {
    24  	PropsIterator() VectorizablePropsIterator
    25  	IsChanged(propName string) bool
    26  	PrevVector() []float32
    27  	PrevVectorForName(targetVector string) []float32
    28  }
    29  
    30  func NewVectorizablePropsComparator(propsSchema []*models.Property,
    31  	nextProps, prevProps models.PropertySchema, prevVector []float32,
    32  	prevVectors models.Vectors,
    33  ) VectorizablePropsComparator {
    34  	props, propsMap := extractVectorizablePropNames(propsSchema)
    35  	return &vectorizablePropsComparator{
    36  		prevProps:            notNilPropsMap(prevProps),
    37  		nextProps:            notNilPropsMap(nextProps),
    38  		vectorizableProps:    props,
    39  		vectorizablePropsMap: propsMap,
    40  		prevVector:           prevVector,
    41  		prevVectors:          prevVectors,
    42  	}
    43  }
    44  
    45  type vectorizablePropsComparator struct {
    46  	prevProps            map[string]interface{}
    47  	nextProps            map[string]interface{}
    48  	vectorizableProps    []string
    49  	vectorizablePropsMap map[string]struct{}
    50  	prevVector           []float32
    51  	prevVectors          models.Vectors
    52  }
    53  
    54  func (c *vectorizablePropsComparator) PropsIterator() VectorizablePropsIterator {
    55  	return &vectorizablePropsIterator{pos: 0, vectorizable: c.vectorizableProps, props: c.nextProps}
    56  }
    57  
    58  func (c *vectorizablePropsComparator) IsChanged(propName string) bool {
    59  	// not vectorizable prop -> not changed
    60  	if _, ok := c.vectorizablePropsMap[propName]; !ok {
    61  		return false
    62  	}
    63  
    64  	prevVal := c.prevProps[propName]
    65  	nextVal := c.nextProps[propName]
    66  
    67  	// both nil / missing / empty array -> not changed
    68  	switch typedPrevVal := prevVal.(type) {
    69  	case nil:
    70  		if nextVal == nil {
    71  			return false
    72  		}
    73  		if arr, ok := nextVal.([]string); ok && len(arr) == 0 {
    74  			return false
    75  		}
    76  		return true
    77  
    78  	case string:
    79  		if typedNextVal, ok := nextVal.(string); ok {
    80  			return typedNextVal != typedPrevVal
    81  		}
    82  		return true
    83  
    84  	case []string:
    85  		switch typedNextVal := nextVal.(type) {
    86  		case nil:
    87  			return len(typedPrevVal) != 0
    88  		case []string:
    89  			if len(typedNextVal) != len(typedPrevVal) {
    90  				return true
    91  			}
    92  			for i := range typedNextVal {
    93  				if typedNextVal[i] != typedPrevVal[i] {
    94  					return true
    95  				}
    96  			}
    97  			return false
    98  		default:
    99  			return true
   100  		}
   101  
   102  	// unmarshalled empty array might be []interface{} instead of []string
   103  	case []interface{}:
   104  		switch typedNextVal := nextVal.(type) {
   105  		case nil:
   106  			return len(typedPrevVal) != 0
   107  		case []string:
   108  			return len(typedPrevVal) != 0 || len(typedNextVal) != 0
   109  		default:
   110  			return true
   111  		}
   112  
   113  	default:
   114  		// fallback (vectorizable types should be string/[]string)
   115  		return false
   116  	}
   117  }
   118  
   119  func (c *vectorizablePropsComparator) PrevVector() []float32 {
   120  	return c.prevVector
   121  }
   122  
   123  func (c *vectorizablePropsComparator) PrevVectorForName(targetVector string) []float32 {
   124  	if c.prevVectors != nil {
   125  		return c.prevVectors[targetVector]
   126  	}
   127  	return nil
   128  }
   129  
   130  func NewVectorizablePropsComparatorDummy(propsSchema []*models.Property, nextProps models.PropertySchema,
   131  ) VectorizablePropsComparator {
   132  	props, propsMap := extractVectorizablePropNames(propsSchema)
   133  	return &vectorizablePropsComparatorDummy{
   134  		nextProps:            notNilPropsMap(nextProps),
   135  		vectorizableProps:    props,
   136  		vectorizablePropsMap: propsMap,
   137  	}
   138  }
   139  
   140  type vectorizablePropsComparatorDummy struct {
   141  	nextProps            map[string]interface{}
   142  	vectorizableProps    []string
   143  	vectorizablePropsMap map[string]struct{}
   144  }
   145  
   146  func (c *vectorizablePropsComparatorDummy) PropsIterator() VectorizablePropsIterator {
   147  	return &vectorizablePropsIterator{pos: 0, vectorizable: c.vectorizableProps, props: c.nextProps}
   148  }
   149  
   150  func (c *vectorizablePropsComparatorDummy) IsChanged(propName string) bool {
   151  	// not vectorizable prop -> not changed
   152  	if _, ok := c.vectorizablePropsMap[propName]; !ok {
   153  		return false
   154  	}
   155  
   156  	switch typedNextVal := c.nextProps[propName].(type) {
   157  	case nil:
   158  		return false
   159  
   160  	case string:
   161  		return true
   162  
   163  	case []string:
   164  		return len(typedNextVal) != 0
   165  
   166  	default:
   167  		// fallback (vectorizable types should be string/[]string)
   168  		return false
   169  	}
   170  }
   171  
   172  func (c *vectorizablePropsComparatorDummy) PrevVector() []float32 {
   173  	return nil
   174  }
   175  
   176  func (c *vectorizablePropsComparatorDummy) PrevVectorForName(targetVector string) []float32 {
   177  	return nil
   178  }
   179  
   180  type VectorizablePropsIterator interface {
   181  	Next() (propName string, propValue interface{}, ok bool)
   182  }
   183  
   184  type vectorizablePropsIterator struct {
   185  	pos          int
   186  	vectorizable []string
   187  	props        map[string]interface{}
   188  }
   189  
   190  func (it *vectorizablePropsIterator) Next() (propName string, propValue interface{}, ok bool) {
   191  	if it.pos >= len(it.vectorizable) {
   192  		return "", nil, false
   193  	}
   194  
   195  	propName = it.vectorizable[it.pos]
   196  	it.pos++
   197  	return propName, it.props[propName], true
   198  }
   199  
   200  func notNilPropsMap(props models.PropertySchema) map[string]interface{} {
   201  	if props != nil {
   202  		if propsMap, ok := props.(map[string]interface{}); ok {
   203  			return propsMap
   204  		}
   205  	}
   206  	return map[string]interface{}{}
   207  }
   208  
   209  func extractVectorizablePropNames(propsSchema []*models.Property) ([]string, map[string]struct{}) {
   210  	props := make([]string, 0, len(propsSchema))
   211  	propsMap := make(map[string]struct{})
   212  
   213  	for _, propSchema := range propsSchema {
   214  		if isVectorizableType(propSchema) {
   215  			props = append(props, propSchema.Name)
   216  			propsMap[propSchema.Name] = struct{}{}
   217  		}
   218  	}
   219  	sort.Strings(props)
   220  
   221  	return props, propsMap
   222  }
   223  
   224  func isVectorizableType(propSchema *models.Property) bool {
   225  	switch pdt, _ := schema.AsPrimitive(propSchema.DataType); pdt {
   226  	case schema.DataTypeText, schema.DataTypeTextArray, schema.DataTypeBlob:
   227  		return true
   228  	default:
   229  		return false
   230  	}
   231  }